feat: add official application icon across GUI, binary, and documentation
This commit is contained in:
parent
46dc6dc849
commit
96ad93b180
10 changed files with 86 additions and 5 deletions
|
|
@ -5,8 +5,8 @@ a = Analysis(
|
|||
['patcher\\patcher_gui.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[('bettercf', 'bettercf'), ('patcher\\vendor', 'vendor'), ('patcher\\patch_core.py', '.')],
|
||||
hiddenimports=[],
|
||||
datas=[('bettercf', 'bettercf'), ('patcher\\vendor', 'vendor'), ('patcher\\patch_core.py', '.'), ('assets', 'assets')],
|
||||
hiddenimports=['PIL', 'PIL.Image', 'PIL.ImageTk'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
|
|
@ -35,4 +35,5 @@ exe = EXE(
|
|||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon='assets\\icon.ico',
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<div align="center">
|
||||
|
||||
<img src="docs/public/logo.svg" alt="BetterCurseForge Logo" width="128" height="128" />
|
||||
<img src="assets/icon_512.png" alt="BetterCurseForge Logo" width="128" height="128" />
|
||||
|
||||
### The modern, lightweight client modification for CurseForge Launcher.
|
||||
|
||||
|
|
|
|||
BIN
assets/icon.ico
Normal file
BIN
assets/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
BIN
assets/icon.png
Normal file
BIN
assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 667 KiB |
BIN
assets/icon_512.png
Normal file
BIN
assets/icon_512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
|
|
@ -9,7 +9,7 @@ export default defineConfig({
|
|||
cleanUrls: true,
|
||||
|
||||
head: [
|
||||
['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }],
|
||||
['link', { rel: 'icon', type: 'image/png', href: (process.env.BASE_URL || '/BetterCurseForge/') + 'logo.png' }],
|
||||
['meta', { name: 'theme-color', content: '#9333ea' }],
|
||||
['meta', { name: 'og:type', content: 'website' }],
|
||||
['meta', { name: 'og:title', content: 'BetterCurseForge' }],
|
||||
|
|
@ -18,6 +18,7 @@ export default defineConfig({
|
|||
|
||||
themeConfig: {
|
||||
siteTitle: 'BetterCurseForge',
|
||||
logo: '/logo.png',
|
||||
|
||||
nav: [
|
||||
{ text: 'Guide', link: '/guide/installation' },
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ hero:
|
|||
name: "BetterCurseForge"
|
||||
text: "Client mod for CurseForge Launcher"
|
||||
tagline: "Ad-free experience, custom themes, unlocked premium skins, and plugins."
|
||||
image:
|
||||
src: /logo.png
|
||||
alt: BetterCurseForge
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Get Started
|
||||
|
|
|
|||
BIN
docs/public/logo.png
Normal file
BIN
docs/public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
|
|
@ -26,6 +26,7 @@ PERMANENT_DIR = Path(os.environ.get("LOCALAPPDATA", "")) / "BetterCurseForge"
|
|||
PERMANENT_EXE = PERMANENT_DIR / "BetterCurseForge.exe"
|
||||
PERMANENT_BCF = PERMANENT_DIR / "bettercf"
|
||||
PERMANENT_VENDOR = PERMANENT_DIR / "vendor"
|
||||
PERMANENT_ASSETS = PERMANENT_DIR / "assets"
|
||||
|
||||
class GlobalNamedMutex:
|
||||
def __init__(self, name: str, timeout_ms: int = 5000):
|
||||
|
|
@ -247,6 +248,20 @@ def find_vendor_dir() -> Path | None:
|
|||
return c
|
||||
return None
|
||||
|
||||
def find_assets_dir() -> Path | None:
|
||||
candidates = [
|
||||
Path(getattr(sys, "_MEIPASS", "")) / "assets" if hasattr(sys, "_MEIPASS") else None,
|
||||
Path(sys.executable).parent / "assets" if getattr(sys, "frozen", False) else None,
|
||||
PERMANENT_ASSETS,
|
||||
Path(__file__).parent / "assets",
|
||||
Path(__file__).parent.parent / "assets",
|
||||
Path.cwd() / "assets",
|
||||
]
|
||||
for c in candidates:
|
||||
if c and c.exists() and c.is_dir():
|
||||
return c
|
||||
return None
|
||||
|
||||
def run_asar_tool(args: list[str], cf_dir: Path | None = None) -> tuple[bool, str]:
|
||||
"""
|
||||
Executes asar pack/extract offline using bundled @electron/asar with either
|
||||
|
|
@ -775,6 +790,13 @@ def ensure_permanent_installation() -> Path:
|
|||
shutil.rmtree(PERMANENT_VENDOR, ignore_errors=True)
|
||||
shutil.copytree(src_vendor, PERMANENT_VENDOR)
|
||||
|
||||
src_assets = find_assets_dir()
|
||||
if src_assets and src_assets.exists():
|
||||
if PERMANENT_ASSETS.resolve() != src_assets.resolve():
|
||||
if PERMANENT_ASSETS.exists():
|
||||
shutil.rmtree(PERMANENT_ASSETS, ignore_errors=True)
|
||||
shutil.copytree(src_assets, PERMANENT_ASSETS)
|
||||
|
||||
if getattr(sys, "frozen", False):
|
||||
curr_exe = Path(sys.executable).resolve()
|
||||
if curr_exe != PERMANENT_EXE.resolve():
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ from tkinter import ttk, messagebox, scrolledtext
|
|||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
from PIL import Image, ImageTk
|
||||
HAS_PIL = True
|
||||
except ImportError:
|
||||
HAS_PIL = False
|
||||
|
||||
# Import patch core logic
|
||||
try:
|
||||
from . import patch_core
|
||||
|
|
@ -33,6 +39,20 @@ except ImportError:
|
|||
|
||||
VERSION = "1.0.0"
|
||||
|
||||
def find_asset(filename: str) -> Path | None:
|
||||
candidates = [
|
||||
Path(getattr(sys, "_MEIPASS", "")) / "assets" / filename if hasattr(sys, "_MEIPASS") else None,
|
||||
Path(getattr(sys, "_MEIPASS", "")) / filename if hasattr(sys, "_MEIPASS") else None,
|
||||
Path(sys.executable).parent / "assets" / filename if getattr(sys, "frozen", False) else None,
|
||||
getattr(patch_core, "PERMANENT_ASSETS", Path()) / filename,
|
||||
Path(__file__).parent.parent / "assets" / filename,
|
||||
Path.cwd() / "assets" / filename,
|
||||
]
|
||||
for c in candidates:
|
||||
if c and c.exists():
|
||||
return c
|
||||
return None
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# COLOR PALETTE (Modern Discord / Vencord Dark Theme)
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
|
@ -71,11 +91,34 @@ class BetterCFApp:
|
|||
|
||||
self.install_dir = None
|
||||
self.is_working = False
|
||||
self._icon_photo = None
|
||||
self._header_icon_photo = None
|
||||
|
||||
self._configure_styles()
|
||||
self._setup_window_icon()
|
||||
self._build_ui()
|
||||
self._refresh_status()
|
||||
|
||||
def _setup_window_icon(self):
|
||||
ico_path = find_asset("icon.ico")
|
||||
if ico_path and os.name == "nt":
|
||||
try:
|
||||
self.root.iconbitmap(default=str(ico_path.resolve()))
|
||||
except Exception:
|
||||
pass
|
||||
png_path = find_asset("icon_512.png") or find_asset("icon.png")
|
||||
if png_path:
|
||||
try:
|
||||
if HAS_PIL:
|
||||
im = Image.open(png_path)
|
||||
self._icon_photo = ImageTk.PhotoImage(im.resize((64, 64), Image.Resampling.LANCZOS))
|
||||
self.root.iconphoto(True, self._icon_photo)
|
||||
else:
|
||||
self._icon_photo = tk.PhotoImage(file=str(png_path))
|
||||
self.root.iconphoto(True, self._icon_photo)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _configure_styles(self):
|
||||
style = ttk.Style()
|
||||
style.theme_use("clam")
|
||||
|
|
@ -97,8 +140,19 @@ class BetterCFApp:
|
|||
title_frame = tk.Frame(header, bg=COLORS["bg_card"])
|
||||
title_frame.pack(side="left")
|
||||
|
||||
# Header icon thumbnail
|
||||
png_path = find_asset("icon_512.png") or find_asset("icon.png")
|
||||
if png_path and HAS_PIL:
|
||||
try:
|
||||
header_img = Image.open(png_path).resize((32, 32), Image.Resampling.LANCZOS)
|
||||
self._header_icon_photo = ImageTk.PhotoImage(header_img)
|
||||
icon_lbl = tk.Label(title_frame, image=self._header_icon_photo, bg=COLORS["bg_card"])
|
||||
icon_lbl.pack(side="left", padx=(0, 10))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
title_lbl = tk.Label(
|
||||
title_frame, text="⬡ BetterCurseForge", font=("Segoe UI", 16, "bold"),
|
||||
title_frame, text="BetterCurseForge", font=("Segoe UI", 16, "bold"),
|
||||
bg=COLORS["bg_card"], fg=COLORS["purple_glow"]
|
||||
)
|
||||
title_lbl.pack(side="left")
|
||||
|
|
|
|||
Loading…
Reference in a new issue