diff --git a/src/App.tsx b/src/App.tsx index c05fe194..79e890fc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1088,7 +1088,7 @@ export default function App() { useGlobalShortcutsStore.getState().registerAll(); }, []); - // ── Lol: Ctrl+Shift+Alt+N → export new albums image ── + // ── Easter egg: Ctrl+Shift+Alt+N → export new albums image ── useEffect(() => { const onKey = (e: KeyboardEvent) => { if (!e.ctrlKey || !e.shiftKey || !e.altKey || e.code !== 'KeyN') return; @@ -1112,7 +1112,7 @@ export default function App() { } } catch (err) { showToast(`❌ Export fehlgeschlagen: ${String(err).slice(0, 80)}`); - console.error('[lol] export failed:', err); + console.error('[easter egg] export failed:', err); } }; diff --git a/src/components/AboutPsysonicLol.tsx b/src/components/AboutPsysonicLol.tsx deleted file mode 100644 index c7ddbb67..00000000 --- a/src/components/AboutPsysonicLol.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import { createPortal } from 'react-dom'; -import { X } from 'lucide-react'; -import { open as openUrl } from '@tauri-apps/plugin-shell'; -import PsysonicLogo from './PsysonicLogo'; - -const TAPS_TO_REVEAL_HINT = 10; -const TARGET_CLICKS_IN_WINDOW = 100; -const WINDOW_MS = 60_000; - -/** Hardcoded About lol copy — intentionally not in locale files. */ -const MSG_HINT = - 'To become a developer, you need to click the Psysonic logo 100 times within one minute.'; - -const MSG_CONGRATS_TITLE = 'Congratulations.'; -const MSG_CONGRATS_SIGN_OFF = 'Sincerely, your maintainers.'; -const MSG_CONGRATS_PS = "PS: Don't forget to star the repo! ★"; - -/** - * About page brand row + Settings → System → About lol (logo taps + modal). - * Modal copy is English and hardcoded by design. - */ -export function AboutPsysonicBrandHeader({ - appVersion, - aboutVersionLabel, -}: { - appVersion: string; - aboutVersionLabel: string; -}) { - const [phase, setPhase] = useState<'idle' | 'hint' | 'done'>('idle'); - const [idleTaps, setIdleTaps] = useState(0); - const [hintTimestamps, setHintTimestamps] = useState([]); - const [overlayOpen, setOverlayOpen] = useState(false); - - const onLogoClick = useCallback(() => { - if (phase === 'done') return; - - if (phase === 'idle') { - setIdleTaps(prev => { - const next = prev + 1; - if (next >= TAPS_TO_REVEAL_HINT) queueMicrotask(() => setPhase('hint')); - return next; - }); - return; - } - - if (phase === 'hint') { - const now = Date.now(); - setHintTimestamps(prev => { - const inWindow = prev.filter(t => t > now - WINDOW_MS); - const nextTimes = [...inWindow, now]; - if (nextTimes.length >= TARGET_CLICKS_IN_WINDOW) { - queueMicrotask(() => { - setPhase('done'); - setOverlayOpen(true); - }); - } - return nextTimes; - }); - } - }, [phase]); - - const closeOverlay = useCallback(() => setOverlayOpen(false), []); - - useEffect(() => { - if (!overlayOpen) return; - const prevOverflow = document.body.style.overflow; - document.body.style.overflow = 'hidden'; - return () => { - document.body.style.overflow = prevOverflow; - }; - }, [overlayOpen]); - - return ( - <> -
- -
-
- Psysonic -
-
- {aboutVersionLabel} {appVersion} -
-
-
- - {phase === 'hint' && !overlayOpen && ( -

- {MSG_HINT} -

- )} - - {overlayOpen && - createPortal( -
- -
-
- -
-
-

- {MSG_CONGRATS_TITLE} -

-

- {"We're very much looking forward to you as a developer — join us on "} - - {' and build great features!'} -

-

{MSG_CONGRATS_SIGN_OFF}

-

{MSG_CONGRATS_PS}

-
-
-
, - document.body, - )} - - ); -} diff --git a/src/components/PsysonicLogo.tsx b/src/components/PsysonicLogo.tsx index 1bf15672..7a35f2e0 100644 --- a/src/components/PsysonicLogo.tsx +++ b/src/components/PsysonicLogo.tsx @@ -1,4 +1,4 @@ -import React, { useId } from 'react'; +import React from 'react'; interface Props { className?: string; @@ -6,17 +6,16 @@ interface Props { } export default function PsysonicLogo({ className, style }: Props) { - const gradId = `psysonicGrad-${useId().replace(/:/g, '')}`; return ( - + ); diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index f7a7713a..6e84416d 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -21,7 +21,6 @@ import { lastfmGetToken, lastfmAuthUrl, lastfmGetSession, lastfmGetUserInfo, Las import LastfmIcon from '../components/LastfmIcon'; import CustomSelect from '../components/CustomSelect'; import SettingsSubSection from '../components/SettingsSubSection'; -import { AboutPsysonicBrandHeader } from '../components/AboutPsysonicLol'; import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable'; import ThemePicker, { THEME_GROUPS } from '../components/ThemePicker'; import { useShallow } from 'zustand/react/shallow'; @@ -3985,7 +3984,17 @@ export default function Settings() { icon={} >
- +
+ Psysonic +
+
+ Psysonic +
+
+ {t('settings.aboutVersion')} {appVersion} +
+
+

{t('settings.aboutDesc')} diff --git a/src/styles/components.css b/src/styles/components.css index 9b41458c..b9f43273 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -3756,168 +3756,6 @@ gap: var(--space-4); } -.about-psysonic-logo-lol-hit { - flex-shrink: 0; - margin: 0; - padding: 0; - border: none; - background: none; - cursor: pointer; - border-radius: 14px; - line-height: 0; -} - -.about-psysonic-logo-lol-hit:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 3px; -} - -.about-psysonic-lol-close { - position: fixed; - top: max(12px, env(safe-area-inset-top, 0px)); - right: max(12px, env(safe-area-inset-right, 0px)); - z-index: 100001; - display: flex; - align-items: center; - justify-content: center; - width: 48px; - height: 48px; - margin: 0; - padding: 0; - border: 2px solid #e2e8f0; - border-radius: var(--radius-full); - background: #1e293b; - color: #f8fafc; - cursor: pointer; - box-shadow: - 0 0 0 1px #0f172a, - 0 6px 24px rgba(0, 0, 0, 0.5); - transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease; -} - -.about-psysonic-lol-close:hover { - background: #334155; - border-color: #f8fafc; - color: #fff; -} - -.about-psysonic-lol-close:focus-visible { - outline: 3px solid #38bdf8; - outline-offset: 2px; -} - -.about-psysonic-lol-overlay { - position: fixed; - inset: 0; - z-index: 100000; - display: flex; - align-items: center; - justify-content: center; - padding: 2rem; - box-sizing: border-box; - isolation: isolate; - background: rgba(0, 0, 0, 0.82); -} - -/* Opaque panel + fixed palette so contrast holds on every app theme. */ -.about-psysonic-lol-panel { - width: min(26rem, calc(100vw - 2.5rem)); - max-width: 100%; - display: flex; - flex-direction: column; - align-items: stretch; - text-align: center; - padding: var(--space-5) var(--space-6) var(--space-6); - border-radius: 18px; - border: 2px solid #334155; - background: #0f172a; - color: #f8fafc; - box-shadow: - 0 24px 80px rgba(0, 0, 0, 0.55), - inset 0 1px 0 rgba(255, 255, 255, 0.06); - --logo-color-start: #a78bfa; - --logo-color-end: #38bdf8; -} - -.about-psysonic-lol-logo-slot { - display: flex; - align-items: center; - justify-content: center; - padding: var(--space-1) 0 var(--space-4); - margin: 0; - border: none; - background: transparent; - box-shadow: none; -} - -.about-psysonic-lol-logo-mark { - flex-shrink: 0; - filter: drop-shadow(0 2px 16px rgba(0, 0, 0, 0.55)); -} - -.about-psysonic-lol-copy { - display: flex; - flex-direction: column; - gap: var(--space-3); - color: #f8fafc; -} - -.about-psysonic-lol-title { - margin: 0; - font-family: var(--font-display); - font-size: clamp(1.5rem, 4.5vw, 1.9rem); - font-weight: 700; - line-height: 1.15; - letter-spacing: -0.02em; - color: #ffffff; -} - -.about-psysonic-lol-lede { - margin: 0; - font-size: clamp(0.9rem, 2.4vw, 1rem); - line-height: 1.55; - color: #e2e8f0; - max-width: 24em; - margin-inline: auto; - text-wrap: balance; -} - -.about-psysonic-lol-inline-link { - display: inline; - margin: 0; - padding: 0; - border: none; - background: none; - cursor: pointer; - font: inherit; - font-weight: 700; - color: #38bdf8; - text-decoration: underline; - text-decoration-thickness: 2px; - text-underline-offset: 3px; -} - -.about-psysonic-lol-inline-link:hover { - color: #7dd3fc; -} - -.about-psysonic-lol-signoff { - margin: 0; - font-size: 0.875rem; - line-height: 1.45; - color: #cbd5e1; - font-style: italic; -} - -.about-psysonic-lol-ps { - margin: 0; - font-size: 0.8125rem; - line-height: 1.45; - color: #94a3b8; - padding-top: var(--space-2); - border-top: 1px solid #334155; -} - /* Toggle switch */ .toggle-switch { position: relative;