diff --git a/src/components/launcher/MainLaunchButton.tsx b/src/components/launcher/MainLaunchButton.tsx index 122f593e..97b1cb05 100644 --- a/src/components/launcher/MainLaunchButton.tsx +++ b/src/components/launcher/MainLaunchButton.tsx @@ -387,8 +387,10 @@ export function MainLaunchButton({ const displaySubText = statusSubText || selectedVersionLabel; return ( -
- {actionText}{" "} +
+ + {actionText} + {" "} {displaySubText && ( onProjectTypeChange(type)} variant={projectType === type ? "flat" : "ghost"} size={buttonSize} - className={`flex-1 min-w-0 text-[1.7em]`} + className={`flex-1 min-w-0 text-2xl`} > {type}s diff --git a/src/components/tabs/SettingsTab.tsx b/src/components/tabs/SettingsTab.tsx index 972433e4..a5d33111 100644 --- a/src/components/tabs/SettingsTab.tsx +++ b/src/components/tabs/SettingsTab.tsx @@ -61,6 +61,12 @@ export function SettingsTab() { } = useThemeStore(); const { currentEffect, setCurrentEffect } = useBackgroundEffectStore(); const { qualityLevel, setQualityLevel } = useQualitySettingsStore(); + const { + headerFontPreset, + textFontPreset, + setHeaderFontPreset, + setTextFontPreset, + } = useThemeStore(); const { confirm, confirmDialog } = useConfirmDialog(); @@ -478,16 +484,143 @@ export function SettingsTab() { size="md" > Download -
+ +
+ + + + +
+
+ +

+ Typography +

+
+

+ Choose fonts and base size used throughout the launcher +

+ + {(() => { + const options = [ + { + value: "minecraft" as const, + label: "Minecraft (default)", + headerSample: 'Minecraft, monospace', + textSample: + 'MinecraftTen, ui-sans-serif, system-ui, "Segoe UI", Inter, sans-serif', + }, + { + value: "system" as const, + label: "System Sans", + headerSample: + 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, "Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif', + textSample: + 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, "Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif', + }, + { + value: "monospace" as const, + label: "Monospace", + headerSample: + 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "DejaVu Sans Mono", "Cascadia Mono", "Fira Code", "Courier New", monospace', + textSample: + 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "DejaVu Sans Mono", "Cascadia Mono", "Fira Code", "Courier New", monospace', + }, + ]; + + return ( +
+
+

Header font

+
+ {options.map((opt) => ( + setHeaderFontPreset(opt.value)} + > +
+

{opt.label}

+
+
+ Heading Sample +
+
+
+ {headerFontPreset === opt.value && ( +
+ +
+ )} +
+ ))} +
+
+ +
+

Text font

+
+ {options.map((opt) => ( + setTextFontPreset(opt.value)} + > +
+

{opt.label}

+
+
+ Lorem ipsum dolor sit amet +
+
+
+ {textFontPreset === opt.value && ( +
+ +
+ )} +
+ ))} +
+
+
+ ); + })()}
-

+

Custom Colors -

+

Create your own custom accent color @@ -536,8 +669,11 @@ export function SettingsTab() { /> ))} - )} - + + )} + + +

diff --git a/src/store/useThemeStore.ts b/src/store/useThemeStore.ts index a3790839..a23b5aa2 100644 --- a/src/store/useThemeStore.ts +++ b/src/store/useThemeStore.ts @@ -207,6 +207,11 @@ interface ThemeState { setAccentColor: (color: AccentColor) => void; setCustomAccentColor: (hexColor: string) => void; applyAccentColorToDOM: () => void; + headerFontPreset: FontPreset; + textFontPreset: FontPreset; + setHeaderFontPreset: (preset: FontPreset) => void; + setTextFontPreset: (preset: FontPreset) => void; + applyFontPresetsToDOM: () => void; customColorHistory: string[]; addToCustomColorHistory: (hexColor: string) => void; clearCustomColorHistory: () => void; @@ -232,6 +237,8 @@ export const useThemeStore = create()( persist( (set, get) => ({ accentColor: ACCENT_COLORS.blue, + headerFontPreset: 'minecraft', + textFontPreset: 'minecraft', isBackgroundAnimationEnabled: false, isDetailViewSidebarOnLeft: true, profileGroupingCriterion: "group", @@ -252,6 +259,40 @@ export const useThemeStore = create()( get().applyBorderRadiusToDOM(); }, + setHeaderFontPreset: (preset: FontPreset) => { + set({ headerFontPreset: preset }); + get().applyFontPresetsToDOM(); + }, + + setTextFontPreset: (preset: FontPreset) => { + set({ textFontPreset: preset }); + get().applyFontPresetsToDOM(); + }, + + applyFontPresetsToDOM: () => { + const { headerFontPreset, textFontPreset } = get(); + const getFont = (preset: FontPreset, target: 'header' | 'text') => { + switch (preset) { + case 'minecraft': + return target === 'header' + ? '"Minecraft", monospace' + : '"MinecraftTen", sans-serif'; + case 'system': + return 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, "Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif'; + case 'monospace': + return 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "DejaVu Sans Mono", "Cascadia Mono", "Fira Code", "Courier New", monospace'; + default: + return '"Minecraft", monospace'; + } + }; + const headerFont = getFont(headerFontPreset, 'header'); + const textFont = getFont(textFontPreset, 'text'); + document.documentElement.style.setProperty('--font-minecraft', headerFont); + document.documentElement.style.setProperty('--font-minecraft-ten', textFont); + // Expose current header font preset + document.documentElement.setAttribute('data-header-font', headerFontPreset); + }, + setCustomAccentColor: (hexColor: string) => { const colorVariants = calculateColorVariants(hexColor); const customColor: AccentColor = { @@ -385,6 +426,7 @@ export const useThemeStore = create()( state.applyAccentColorToDOM(); state.applyBorderRadiusToDOM(); + state.applyFontPresetsToDOM?.(); // Ensure collapsedProfileGroups exists after rehydrate if (!Array.isArray(state.collapsedProfileGroups)) { state.collapsedProfileGroups = []; @@ -394,3 +436,6 @@ export const useThemeStore = create()( }, ), ); + +// Font presets for appearance settings +export type FontPreset = 'minecraft' | 'system' | 'monospace'; diff --git a/src/styles/globals.css b/src/styles/globals.css index d79b80e3..80ecb390 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -206,7 +206,7 @@ background-size: cover; background-position: center; background-attachment: fixed; - font-family: var(--font-minecraft), monospace; + font-family: var(--font-minecraft-ten), sans-serif; letter-spacing: 0.03em; } @@ -247,6 +247,37 @@ letter-spacing: 0.03em; } +/* Normalize heading visual size for non-Minecraft presets */ +:root[data-header-font='system'] .text-6xl.font-minecraft, +:root[data-header-font='monospace'] .text-6xl.font-minecraft { + font-size: 2.5rem; +} +:root[data-header-font='system'] .text-5xl.font-minecraft, +:root[data-header-font='monospace'] .text-5xl.font-minecraft { + font-size: 2rem; +} +:root[data-header-font='system'] .text-4xl.font-minecraft, +:root[data-header-font='monospace'] .text-4xl.font-minecraft { + font-size: 1.7rem; +} +:root[data-header-font='system'] .text-3xl.font-minecraft, +:root[data-header-font='monospace'] .text-3xl.font-minecraft { + font-size: 1.2rem; +} +:root[data-header-font='system'] .text-2xl.font-minecraft, +:root[data-header-font='monospace'] .text-2xl.font-minecraft { + font-size: 1.1rem; +} +:root[data-header-font='system'] .text-xl.font-minecraft, +:root[data-header-font='monospace'] .text-xl.font-minecraft { + font-size: 0.9rem; +} +:root[data-header-font='system'] .launch-btn, +:root[data-header-font='monospace'] .launch-btn { + /* Reset margin for launch buttons for non Minecraft presets */ + margin-top: 0; +} + .text-shadow { text-shadow: 0 2px 6px rgba(0, 0, 0, 0.9), 0 0 3px rgba(0, 0, 0, 1); }