PageSourceSearch

https://command-z.vercel.app/js/apps/settings.js

js command-z.vercel.app collected 2026-10-03 06:29:59 UTC 6,226 bytes, 116 lines download raw bytes

1/* ============================================================
2   settings.js — SETTINGS (System Preferences)
3   Appearance (light/dark), wallpaper, accent, reduced motion.
4   All persisted to localStorage and applied live.
5   ============================================================ */
6
7const WALLS = {
8  // the ones we made — Cmd + Z originals first (matches the mobile wallpaper order)
9  "Kato's Doodle": 'url("/assets/img/walls/kato-doodle.png") center/cover no-repeat',   // Kato's own Paint creation
10  'Poker Dogs':   'url("/assets/img/walls/poker-dogs.webp") center/cover no-repeat',
11  'Sticker Table':'url("/assets/img/walls/sticker-table.webp") center/cover no-repeat',
12  'Swama':        'url("/assets/img/walls/swama.webp") center/cover no-repeat',
13  'Cracked Paint':'url("/assets/img/walls/cracked-paint.webp") center/cover no-repeat',
14  'Distress':     'url("/assets/img/walls/distress.webp") center/cover no-repeat',
15  'Patchwork':    'url("/assets/img/walls/patchwork.webp") center/cover no-repeat',
16  'Boro':     'url("/assets/img/walls/boro.svg") center/cover no-repeat',        // indigo
17  'Mono':     'url("/assets/img/walls/mono-paper.svg") center/cover no-repeat',   // paper (light)
18  // Removed the 3 near-identical all-black ⌘Z stock walls (undo-dark / noho / underdog) —
19  // they read as duplicates in the picker. Every remaining tile is a distinct image.
20  // ("Default" theme-adaptive tile, "Icons" + "Happy Mac" removed earlier.)
21};
22const ACCENTS = { Blue: '#0a84ff', Red: '#ff453a', Green: '#28c840', Amber: '#febc2e', Purple: '#bf5af2', Mono: '#8a8a90' };
23const root = document.documentElement;
24const setWall = (g) => { const d = document.getElementById('wall-layer'); if (d) d.style.background = g || ''; };
25
26export function mountSettings(el, ctx) {
27  el.classList.add('settings');
28  const theme = root.dataset.theme || 'dark';
29  el.innerHTML = `
30    <div class="set-pad">
31      <span class="app-tag">SETTINGS.app</span>
32      <h1 style="font-family:var(--display)">System Preferences</h1>
33
34      <div class="set-group"><label>Appearance</label>
35        <div class="set-seg">
36          <button class="set-mode ${theme==='light'?'on':''}" data-mode="light">☀︎ Light</button>
37          <button class="set-mode ${theme==='dark'?'on':''}" data-mode="dark">☾ Dark</button>
38        </div>
39      </div>
40
41      <div class="set-group"><label>Wallpaper</label><div class="set-walls"></div></div>
42      <div class="set-group"><label>Accent</label><div class="set-accents"></div></div>
43      <div class="set-group"><label>Screen saver — idle time</label>
44        <div class="set-seg set-ss"></div>
45      </div>
46      <div class="set-group set-row"><label>Reduce motion</label><input type="checkbox" class="set-rm"/></div>
47      <div class="set-group set-row"><label>Replay boot sequence next visit</label><input type="checkbox" class="set-boot"/></div>
48    </div>`;
49
50  /* appearance — switch theme only; the chosen wallpaper is kept, not reset */
51  el.querySelectorAll('.set-mode').forEach((b) => b.onclick = () => {
52    const m = b.dataset.mode;
53    root.dataset.theme = m;
54    localStorage.setItem('cz-theme', m);
55    el.querySelectorAll('.set-mode').forEach((x) => x.classList.toggle('on', x === b));
56    ctx.toast(m === 'light' ? '☀︎' : '☾', 'Appearance', m[0].toUpperCase() + m.slice(1));
57  });
58
59  /* wallpaper — highlight whichever one is actually applied */
60  const walls = el.querySelector('.set-walls');
61  const curWall = localStorage.getItem('cz-wall');
62  // with no override stored, the applied wall IS the theme default (paper in light,
63  // ⌘Z monogram in dark) → highlight that tile so the picker matches what's on screen.
64  const themeDefaultG = theme === 'light' ? WALLS['Mono'] : null;   // dark default wall isn't a picker tile
65  Object.entries(WALLS).forEach(([name, g]) => {
66    const b = document.createElement('button');
67    const isCur = curWall ? curWall === g : g === themeDefaultG;
68    b.className = 'set-wall' + (isCur ? ' on' : '');
69    b.style.background = g || 'var(--wall)'; b.title = name;
70    b.onclick = () => {
71      setWall(g);
72      if (g) localStorage.setItem('cz-wall', g);
72 else localStorage.removeItem('cz-wall');
73      walls.querySelectorAll('.set-wall').forEach((x) => x.classList.remove('on')); b.classList.add('on');
74      ctx.toast('🖼️', 'Wallpaper', name);
75    };
76    walls.appendChild(b);
77  });
78
79  /* screen saver idle time */
80  const SS = [['Off', 0], ['1 min', 1], ['3 min', 3], ['5 min', 5], ['10 min', 10]];
81  const ssEl = el.querySelector('.set-ss');
82  const curIdle = (() => { const v = parseFloat(localStorage.getItem('cz-ss-idle')); return isNaN(v) ? 5 : v; })();
83  SS.forEach(([label, min]) => {
84    const b = document.createElement('button');
85    b.className = 'set-mode' + (min === curIdle ? ' on' : '');
86    b.textContent = label;
87    b.onclick = () => {
88      ssEl.querySelectorAll('.set-mode').forEach((x) => x.classList.toggle('on', x === b));
89      window.__screensaver && window.__screensaver.setIdle(min);
90      ctx.toast('🖥️', 'Screen saver', min ? `Starts after ${label} idle` : 'Off');
91    };
92    ssEl.appendChild(b);
93  });
94
95  /* accent */
96  const accents = el.querySelector('.set-accents');
97  const savedAccent = localStorage.getItem('cz-accent') || ACCENTS.Blue;
98  Object.entries(ACCENTS).forEach(([name, c]) => {
99    const b = document.createElement('button');
100    b.className = 'set-accent' + (c === savedAccent ? ' on' : '');
101    b.style.background = c; b.title = name;
102    b.onclick = () => {
103      root.style.setProperty('--accent', c); localStorage.setItem('cz-accent', c);
104      accents.querySelectorAll('.set-accent').forEach((x) => x.classList.remove('on')); b.classList.add('on');
105      ctx.toast('🎨', 'Accent', name);
106    };
107    accents.appendChild(b);
108  });
109
110  /* toggles */
111  const rm = el.querySelector('.set-rm'); rm.checked = root.classList.contains('rm');
112  rm.onchange = (e) => { root.classList.toggle('rm', e.target.checked); ctx.toast('⌁', 'Reduced motion', e.target.checked ? 'On' : 'Off'); };
113  el.querySelector('.set-boot').onchange = (e) => {
114    if (e.target.checked) sessionStorage.removeItem('cz-booted'); else sessionStorage.setItem('cz-booted', '1');
115  };
116}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.