|
1 | 1 | <script lang="ts"> |
2 | 2 | import { goto } from '$app/navigation'; |
3 | | - import { getCatalogItem } from '$lib/macos-prefs-catalog'; |
| 3 | + import { getCatalogItem, CATALOG_CATEGORIES } from '$lib/macos-prefs-catalog'; |
4 | 4 |
|
5 | 5 | let { |
6 | 6 | configUser, |
|
144 | 144 | const snapshot = $derived(config.snapshot || {}); |
145 | 145 | const snapshotPkgs = $derived(snapshot.packages || {}); |
146 | 146 | const macosPrefs = $derived(snapshot.macos_prefs || []); |
147 | | - interface PrefGroup { |
148 | | - category: string; |
149 | | - items: { pref: any; catalogItem: ReturnType<typeof getCatalogItem> }[]; |
150 | | - } |
151 | | - const groupedMacosPrefs = $derived.by((): PrefGroup[] => { |
152 | | - const result: PrefGroup[] = []; |
| 147 | +
|
| 148 | + const prefsByCategory = $derived.by(() => { |
| 149 | + const map: Record<string, { pref: any; catalogItem: ReturnType<typeof getCatalogItem> }[]> = {}; |
153 | 150 | for (const pref of macosPrefs) { |
154 | 151 | const catalogItem = getCatalogItem(pref.domain, pref.key); |
155 | 152 | const category = catalogItem?.category ?? 'Custom'; |
156 | | - const existing = result.find((g: PrefGroup) => g.category === category); |
157 | | - if (existing) { |
158 | | - existing.items = [...existing.items, { pref, catalogItem }]; |
159 | | - } else { |
160 | | - result.push({ category, items: [{ pref, catalogItem }] }); |
161 | | - } |
| 153 | + if (!map[category]) map[category] = []; |
| 154 | + map[category] = [...map[category], { pref, catalogItem }]; |
162 | 155 | } |
163 | | - return result; |
| 156 | + return map; |
164 | 157 | }); |
| 158 | +
|
| 159 | + const prefCategoryNames = $derived(Object.keys(prefsByCategory)); |
165 | 160 | const shell = $derived(snapshot.shell || {}); |
166 | 161 | const git = $derived(snapshot.git || {}); |
167 | 162 | const devToolsRaw = $derived(snapshot.dev_tools || []); |
|
436 | 431 | {#if macosPrefs.length > 0} |
437 | 432 | <section class="section"> |
438 | 433 | <h2 class="section-title">🍎 macOS Preferences</h2> |
439 | | - <div class="prefs-groups"> |
440 | | - {#each groupedMacosPrefs as group} |
441 | | - <div class="prefs-category-block"> |
442 | | - <div class="prefs-category-name">{group.category}</div> |
443 | | - <div class="prefs-category-items"> |
444 | | - {#each group.items as { pref, catalogItem }} |
445 | | - <div class="pref-card"> |
446 | | - <div class="pref-card-body"> |
447 | | - <div class="pref-card-label">{catalogItem?.label ?? pref.key}</div> |
448 | | - {#if catalogItem?.description} |
449 | | - <div class="pref-card-desc">{catalogItem.description}</div> |
450 | | - {:else if pref.desc} |
451 | | - <div class="pref-card-desc">{pref.desc}</div> |
452 | | - {:else} |
453 | | - <div class="pref-card-desc pref-card-raw">{pref.domain} · {pref.key}</div> |
454 | | - {/if} |
455 | | - </div> |
456 | | - <div class="pref-card-value"> |
| 434 | + <div class="prefs-accordion"> |
| 435 | + {#each prefCategoryNames as cat} |
| 436 | + {@const items = prefsByCategory[cat]} |
| 437 | + <div class="prefs-acc-group"> |
| 438 | + <div class="prefs-acc-header"> |
| 439 | + <span class="prefs-acc-name">{cat}</span> |
| 440 | + <span class="prefs-acc-count">{items.length}</span> |
| 441 | + </div> |
| 442 | + <div class="prefs-acc-body"> |
| 443 | + {#each items as { pref, catalogItem }} |
| 444 | + <div class="prefs-kv-row"> |
| 445 | + <span class="prefs-kv-label">{catalogItem?.label ?? pref.key}</span> |
| 446 | + <span class="prefs-kv-value"> |
457 | 447 | {#if (catalogItem?.type ?? pref.type) === 'bool'} |
458 | | - <span class="pref-bool {pref.value === 'true' ? 'pref-bool-on' : 'pref-bool-off'}"> |
459 | | - {pref.value === 'true' ? 'ON' : 'OFF'} |
| 448 | + {@const boolOn = pref.value === 'true' || pref.value === '1'} |
| 449 | + <span class="pref-bool {boolOn ? 'pref-bool-on' : 'pref-bool-off'}"> |
| 450 | + {boolOn ? 'ON' : 'OFF'} |
460 | 451 | </span> |
461 | 452 | {:else if catalogItem?.options} |
462 | 453 | {@const opt = catalogItem.options.find((o: { value: string; label: string }) => o.value === pref.value)} |
463 | 454 | <span class="pref-option-val">{opt?.label ?? pref.value}</span> |
464 | 455 | {:else} |
465 | 456 | <span class="pref-raw-val">{pref.value}</span> |
466 | 457 | {/if} |
467 | | - </div> |
| 458 | + </span> |
468 | 459 | </div> |
469 | 460 | {/each} |
470 | 461 | </div> |
|
1126 | 1117 | color: var(--text-primary); |
1127 | 1118 | } |
1128 | 1119 |
|
1129 | | - .prefs-groups { |
1130 | | - display: flex; |
1131 | | - flex-direction: column; |
1132 | | - gap: 28px; |
1133 | | - } |
1134 | | -
|
1135 | | - .prefs-category-block { |
1136 | | - display: flex; |
1137 | | - flex-direction: column; |
1138 | | - gap: 10px; |
| 1120 | + .prefs-accordion { |
| 1121 | + border: 1px solid var(--border); |
| 1122 | + border-radius: 12px; |
| 1123 | + overflow: hidden; |
1139 | 1124 | } |
1140 | 1125 |
|
1141 | | - .prefs-category-name { |
1142 | | - font-size: 0.75rem; |
1143 | | - font-weight: 700; |
1144 | | - text-transform: uppercase; |
1145 | | - letter-spacing: 0.1em; |
1146 | | - color: var(--text-muted); |
1147 | | - padding-bottom: 8px; |
| 1126 | + .prefs-acc-group { |
1148 | 1127 | border-bottom: 1px solid var(--border); |
1149 | 1128 | } |
1150 | 1129 |
|
1151 | | - .prefs-category-items { |
1152 | | - display: flex; |
1153 | | - flex-direction: column; |
1154 | | - gap: 8px; |
| 1130 | + .prefs-acc-group:last-child { |
| 1131 | + border-bottom: none; |
1155 | 1132 | } |
1156 | 1133 |
|
1157 | | - .pref-card { |
| 1134 | + .prefs-acc-header { |
1158 | 1135 | display: flex; |
1159 | 1136 | align-items: center; |
1160 | | - justify-content: space-between; |
1161 | | - gap: 16px; |
1162 | | - padding: 14px 18px; |
| 1137 | + gap: 8px; |
| 1138 | + padding: 10px 16px; |
1163 | 1139 | background: var(--bg-tertiary); |
1164 | | - border: 1px solid var(--border); |
1165 | | - border-radius: 10px; |
1166 | 1140 | } |
1167 | 1141 |
|
1168 | | - .pref-card-body { |
| 1142 | + .prefs-acc-name { |
| 1143 | + font-size: 0.75rem; |
| 1144 | + font-weight: 700; |
| 1145 | + text-transform: uppercase; |
| 1146 | + letter-spacing: 0.08em; |
| 1147 | + color: var(--text-muted); |
1169 | 1148 | flex: 1; |
1170 | | - min-width: 0; |
1171 | 1149 | } |
1172 | 1150 |
|
1173 | | - .pref-card-label { |
1174 | | - font-size: 0.95rem; |
1175 | | - font-weight: 600; |
1176 | | - color: var(--text-primary); |
1177 | | - margin-bottom: 3px; |
| 1151 | + .prefs-acc-count { |
| 1152 | + font-size: 0.7rem; |
| 1153 | + color: var(--text-muted); |
1178 | 1154 | } |
1179 | 1155 |
|
1180 | | - .pref-card-desc { |
1181 | | - font-size: 0.82rem; |
1182 | | - color: var(--text-muted); |
1183 | | - line-height: 1.4; |
| 1156 | + .prefs-acc-body { |
| 1157 | + display: grid; |
| 1158 | + grid-template-columns: 1fr; |
1184 | 1159 | } |
1185 | 1160 |
|
1186 | | - .pref-card-raw { |
1187 | | - font-family: 'JetBrains Mono', monospace; |
1188 | | - font-size: 0.78rem; |
| 1161 | + @media (min-width: 640px) { |
| 1162 | + .prefs-acc-body { |
| 1163 | + grid-template-columns: 1fr 1fr; |
| 1164 | + } |
1189 | 1165 | } |
1190 | 1166 |
|
1191 | | - .pref-card-value { |
| 1167 | + .prefs-kv-row { |
| 1168 | + display: flex; |
| 1169 | + align-items: center; |
| 1170 | + justify-content: space-between; |
| 1171 | + gap: 12px; |
| 1172 | + padding: 8px 16px; |
| 1173 | + border-top: 1px solid color-mix(in srgb, var(--border) 50%, transparent); |
| 1174 | + } |
| 1175 | +
|
| 1176 | + .prefs-kv-label { |
| 1177 | + font-size: 0.88rem; |
| 1178 | + color: var(--text-primary); |
| 1179 | + font-weight: 500; |
| 1180 | + } |
| 1181 | +
|
| 1182 | + .prefs-kv-value { |
1192 | 1183 | flex-shrink: 0; |
1193 | 1184 | } |
1194 | 1185 |
|
1195 | 1186 | .pref-bool { |
1196 | 1187 | display: inline-block; |
1197 | | - padding: 4px 10px; |
1198 | | - border-radius: 6px; |
1199 | | - font-size: 0.78rem; |
| 1188 | + padding: 3px 8px; |
| 1189 | + border-radius: 5px; |
| 1190 | + font-size: 0.72rem; |
1200 | 1191 | font-weight: 700; |
1201 | 1192 | letter-spacing: 0.05em; |
1202 | 1193 | } |
|
1216 | 1207 | .pref-option-val, |
1217 | 1208 | .pref-raw-val { |
1218 | 1209 | font-family: 'JetBrains Mono', monospace; |
1219 | | - font-size: 0.85rem; |
| 1210 | + font-size: 0.8rem; |
1220 | 1211 | color: var(--accent); |
1221 | 1212 | background: var(--bg-secondary); |
1222 | | - padding: 4px 10px; |
1223 | | - border-radius: 6px; |
| 1213 | + padding: 3px 8px; |
| 1214 | + border-radius: 5px; |
1224 | 1215 | border: 1px solid var(--border); |
1225 | 1216 | } |
1226 | 1217 |
|
|
0 commit comments