Initial Lime window manager
This commit is contained in:
420
work/lime-lisp-palettes.html
Normal file
420
work/lime-lisp-palettes.html
Normal file
@@ -0,0 +1,420 @@
|
||||
<div id="lime-lisp-palettes" aria-label="Lime dark workstation palette comparison">
|
||||
<style>
|
||||
#lime-lisp-palettes { --lime-base:#0f0f0f; --lime-surface:#191919; --lime-selection:#262626; --lime-selection-ink:#ffb054; --lime-title-text:#dbc9a6; --lime-text:#dbc9a6; --lime-muted:#928f86; --lime-accent:#ffb054; --lime-mint:#768565; --lime-sky:#76929f; --lime-alert:#b76c64; --lime-app:#0f0f0f; --lime-app-text:#dbc9a6; --lime-app-muted:#928f86; --lime-edge:#4c4c4c; --lime-bar-text:#dbc9a6; --lime-bar-background:#191919; --lime-logo:#dbc9a6; --lime-attention:#b76c64; --lime-separator:#686868; --lime-key:#ffb054; --lime-menu-label:#dbc9a6; --lime-music:#dbc9a6; --lime-volume:#dbc9a6; --lime-clock:#dbc9a6; --lime-status-icon:#76929f; color:var(--lime-text); font:400 13px/1.65 "Dina", "Iosevka", "DejaVu Sans Mono", monospace; width:100%; }
|
||||
#lime-lisp-palettes * { box-sizing:border-box; }
|
||||
#lime-lisp-palettes button { font:inherit; color:inherit; cursor:pointer; }
|
||||
#lime-lisp-palettes .lime-palette-switcher { display:flex; flex-wrap:wrap; gap:8px; padding-bottom:12px; }
|
||||
#lime-lisp-palettes .lime-choice-swatch { display:inline-block; width:14px; height:14px; margin-right:8px; vertical-align:-2px; }
|
||||
#lime-lisp-palettes .lime-palette-switcher button { flex:1 1 180px; min-height:44px; padding:9px 14px; background:var(--lime-surface); color:var(--lime-text); border:1px solid var(--lime-edge); }
|
||||
#lime-lisp-palettes .lime-palette-switcher button:hover { background:var(--lime-selection); color:var(--lime-selection-ink); }
|
||||
#lime-lisp-palettes .lime-palette-switcher button[aria-pressed="true"] { background:var(--lime-selection); color:var(--lime-selection-ink); border-color:var(--lime-accent); box-shadow:inset 0 -2px 0 var(--lime-accent); }
|
||||
#lime-lisp-palettes .lime-desk { background:var(--lime-base); position:relative; isolation:isolate; }
|
||||
#lime-lisp-palettes .lime-bar { display:flex; align-items:center; gap:0; min-height:32px; background:var(--lime-bar-background); color:var(--lime-bar-text); white-space:nowrap; }
|
||||
#lime-lisp-palettes .lime-context-group { display:flex; align-items:center; max-width:100%; }
|
||||
#lime-lisp-palettes .lime-logo { background:none; border:0; padding:4px 16px; color:var(--lime-logo); }
|
||||
#lime-lisp-palettes .lime-pipe { color:var(--lime-separator); padding:0; }
|
||||
#lime-lisp-palettes .lime-context { padding:0 16px; }
|
||||
#lime-lisp-palettes .lime-layout { padding:0 16px; }
|
||||
#lime-lisp-palettes .lime-title { padding:4px 12px; flex:1; min-width:20px; overflow:hidden; text-overflow:ellipsis; border-inline:1px solid var(--lime-edge); background:var(--lime-selection); color:var(--lime-title-text); }
|
||||
#lime-lisp-palettes .lime-status { display:flex; flex-wrap:wrap; align-items:center; padding:0 16px; column-gap:12px; row-gap:4px; }
|
||||
#lime-lisp-palettes .lime-status .lime-pipe { padding:0; }
|
||||
#lime-lisp-palettes .lime-attention { color:var(--lime-attention); }
|
||||
#lime-lisp-palettes .lime-music { color:var(--lime-music); }
|
||||
#lime-lisp-palettes .lime-volume { color:var(--lime-volume); }
|
||||
#lime-lisp-palettes .lime-clock { color:var(--lime-clock); }
|
||||
#lime-lisp-palettes .lime-status-icon { color:var(--lime-status-icon); display:inline-flex; align-items:center; vertical-align:middle; }
|
||||
#lime-lisp-palettes .lime-volume .lime-status-icon, #lime-lisp-palettes .lime-clock .lime-status-icon { margin-right:1ch; }
|
||||
#lime-lisp-palettes .lime-workspace { position:relative; }
|
||||
#lime-lisp-palettes .lime-windows { padding:7px; display:grid; grid-template-columns:minmax(0,1.4fr) minmax(0,1fr); gap:7px; min-height:510px; }
|
||||
#lime-lisp-palettes .lime-window { min-width:0; background:var(--lime-app); color:var(--lime-app-text); border:3px solid var(--lime-edge); display:flex; flex-direction:column; }
|
||||
#lime-lisp-palettes .lime-window[data-selected="true"] { border-color:var(--lime-accent); }
|
||||
#lime-lisp-palettes .lime-stack { display:grid; grid-template-rows:1fr 1fr; min-width:0; gap:7px; }
|
||||
#lime-lisp-palettes .lime-buffer-tabs { padding:8px 13px; border-bottom:1px solid var(--lime-edge); color:var(--lime-app-muted); display:flex; gap:18px; }
|
||||
#lime-lisp-palettes .lime-buffer-tabs span:first-child { color:var(--lime-accent); }
|
||||
#lime-lisp-palettes .lime-code { margin:0; padding:26px 17px; font:inherit; white-space:pre-wrap; overflow-wrap:anywhere; flex:1; }
|
||||
#lime-lisp-palettes .lime-code .lime-comment, #lime-lisp-palettes .lime-faded { color:var(--lime-app-muted); }
|
||||
#lime-lisp-palettes .lime-keyword { color:var(--lime-accent); }
|
||||
#lime-lisp-palettes .lime-symbol { color:var(--lime-mint); }
|
||||
#lime-lisp-palettes .lime-constant { color:var(--lime-sky); }
|
||||
#lime-lisp-palettes .lime-string { color:var(--lime-alert); }
|
||||
#lime-lisp-palettes .lime-edit-space { min-height:75px; flex:1; }
|
||||
#lime-lisp-palettes .lime-mode-line { padding:3px 12px; display:flex; justify-content:space-between; gap:12px; background:var(--lime-surface); color:var(--lime-muted); border-top:1px solid var(--lime-edge); }
|
||||
#lime-lisp-palettes .lime-minibuffer { padding:5px 12px; color:var(--lime-app-muted); }
|
||||
#lime-lisp-palettes .lime-terminal { padding:20px 18px; overflow-wrap:anywhere; }
|
||||
#lime-lisp-palettes .lime-terminal p { margin:0 0 10px; }
|
||||
#lime-lisp-palettes .lime-caret { display:inline-block; height:15px; width:8px; vertical-align:middle; background:var(--lime-accent); }
|
||||
#lime-lisp-palettes .lime-notes { padding:22px 20px; }
|
||||
#lime-lisp-palettes .lime-notes h3 { font:500 16px/1.5 "Dina", "DejaVu Sans Mono", monospace; color:var(--lime-mint); margin:0 0 15px; }
|
||||
#lime-lisp-palettes .lime-notes p { margin:0 0 12px; }
|
||||
#lime-lisp-palettes .lime-note-rule { height:1px; background:var(--lime-edge); margin:18px 0; }
|
||||
#lime-lisp-palettes .lime-menu { position:absolute; z-index:2; top:8px; left:12px; right:12px; background:var(--lime-surface); border:1px solid var(--lime-edge); box-shadow:0 12px 22px #00000033; padding:13px 18px 10px; }
|
||||
#lime-lisp-palettes .lime-menu[hidden] { display:none; }
|
||||
#lime-lisp-palettes .lime-menu-top { display:flex; justify-content:space-between; align-items:center; color:var(--lime-muted); padding-bottom:10px; border-bottom:1px solid var(--lime-edge); }
|
||||
#lime-lisp-palettes .lime-menu-heading { color:var(--lime-accent); }
|
||||
#lime-lisp-palettes .lime-menu-back { border:0; padding:0; background:none; color:var(--lime-muted); }
|
||||
#lime-lisp-palettes .lime-map { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:4px 22px; padding:12px 0; }
|
||||
#lime-lisp-palettes .lime-map button { background:none; border:0; padding:4px 0; display:flex; align-items:baseline; gap:12px; text-align:left; min-width:0; }
|
||||
#lime-lisp-palettes .lime-map button:hover { background:var(--lime-selection); color:var(--lime-selection-ink); }
|
||||
#lime-lisp-palettes .lime-map kbd { font:inherit; color:var(--lime-key); min-width:16px; }
|
||||
#lime-lisp-palettes .lime-map-label { min-width:0; overflow-wrap:anywhere; }
|
||||
#lime-lisp-palettes .lime-map button[data-branch="true"] .lime-map-label { color:var(--lime-menu-label); }
|
||||
#lime-lisp-palettes .lime-map-plus { color:var(--lime-muted); margin-left:auto; }
|
||||
#lime-lisp-palettes .lime-map button:hover kbd, #lime-lisp-palettes .lime-map button:hover .lime-map-plus, #lime-lisp-palettes .lime-map button[data-branch="true"]:hover .lime-map-label { color:inherit; }
|
||||
#lime-lisp-palettes .lime-menu-footer { color:var(--lime-muted); display:flex; justify-content:space-between; border-top:1px solid var(--lime-edge); padding-top:7px; gap:12px; }
|
||||
#lime-lisp-palettes .lime-palette-key { padding:15px 16px; background:#191919; color:#dbc9a6; border-top:1px solid #4c4c4c; }
|
||||
#lime-lisp-palettes .lime-palette-name { display:block; margin-bottom:12px; font-weight:500; }
|
||||
#lime-lisp-palettes .lime-color-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr)); gap:12px 18px; }
|
||||
#lime-lisp-palettes .lime-color-field { min-width:0; }
|
||||
#lime-lisp-palettes .lime-color-field label { display:block; margin-bottom:4px; }
|
||||
#lime-lisp-palettes .lime-color-inputs { display:flex; gap:8px; align-items:center; }
|
||||
#lime-lisp-palettes .lime-color-inputs input { font:inherit; border:1px solid #686868; background:#0f0f0f; color:#dbc9a6; border-radius:0; min-height:36px; }
|
||||
#lime-lisp-palettes .lime-color-inputs input[type="color"] { flex:none; width:44px; padding:3px; cursor:pointer; }
|
||||
#lime-lisp-palettes .lime-color-inputs input[type="text"] { width:100%; min-width:0; padding:5px 9px; }
|
||||
#lime-lisp-palettes .lime-color-inputs input[aria-invalid="true"] { border-color:#d98e85; }
|
||||
#lime-lisp-palettes .lime-color-error { color:#d98e85; display:block; margin-top:4px; }
|
||||
#lime-lisp-palettes .lime-color-error[hidden] { display:none; }
|
||||
#lime-lisp-palettes .lime-more-colors { margin-top:14px; }
|
||||
#lime-lisp-palettes .lime-more-colors summary { cursor:pointer; padding:4px 0; }
|
||||
#lime-lisp-palettes .lime-more-colors[open] summary { margin-bottom:10px; }
|
||||
@media(max-width:1000px) { #lime-lisp-palettes .lime-bar { flex-wrap:wrap; } #lime-lisp-palettes .lime-status { flex-basis:100%; justify-content:flex-end; order:3; padding:5px 16px; } }
|
||||
@media(max-width:880px) { #lime-lisp-palettes .lime-windows { grid-template-columns:minmax(0,1.15fr) minmax(0,1fr); } }
|
||||
@media(max-width:650px) { #lime-lisp-palettes .lime-title { flex-basis:100%; order:2; border:0; border-top:1px solid var(--lime-edge); } #lime-lisp-palettes .lime-map { grid-template-columns:repeat(2,minmax(0,1fr)); gap:3px 18px; } #lime-lisp-palettes .lime-windows { grid-template-columns:minmax(0,1fr); } #lime-lisp-palettes .lime-window-editor { min-height:470px; } #lime-lisp-palettes .lime-stack { grid-template-rows:auto auto; } #lime-lisp-palettes .lime-palette-name { flex-basis:100%; } #lime-lisp-palettes .lime-code { padding:20px 12px; } }
|
||||
@media(pointer:coarse) { #lime-lisp-palettes .lime-map button, #lime-lisp-palettes .lime-logo, #lime-lisp-palettes .lime-menu-back { min-height:44px; } #lime-lisp-palettes .lime-window-editor { min-height:540px; } }
|
||||
@media(pointer:coarse) { #lime-lisp-palettes .lime-color-inputs input { min-height:44px; font-size:16px; } #lime-lisp-palettes .lime-more-colors summary { min-height:44px; } }
|
||||
</style>
|
||||
<div class="lime-palette-switcher" role="group" aria-label="Preview palette">
|
||||
<button type="button" data-palette="Your picks" aria-pressed="true"><span class="lime-choice-swatch" style="background:#ffb054" aria-hidden="true"></span>Your picks</button>
|
||||
<button type="button" data-palette="dwm cream · neutral backgrounds" aria-pressed="false"><span class="lime-choice-swatch" style="background:#ffdbb0" aria-hidden="true"></span>Previous version</button>
|
||||
</div>
|
||||
<section class="lime-desk" aria-label="Lime master-stack desktop, with an editor, Lisp REPL, and notes">
|
||||
<header class="lime-bar">
|
||||
<div class="lime-context-group">
|
||||
<button type="button" class="lime-logo" aria-expanded="true" aria-controls="lime-palette-menu">Lime</button>
|
||||
<span class="lime-pipe" aria-hidden="true">|</span>
|
||||
<span class="lime-context">lime:Code*</span>
|
||||
<span class="lime-pipe" aria-hidden="true">|</span>
|
||||
<span class="lime-layout">[]=</span>
|
||||
</div>
|
||||
<span class="lime-title">attention.lisp — Emacs</span>
|
||||
<div class="lime-status"><span class="lime-attention">! 1</span><span class="lime-pipe">|</span><span class="lime-music"><span class="lime-status-icon" aria-hidden="true">▶</span> quiet company</span><span class="lime-pipe lime-media-pipe">|</span><span class="lime-volume"><span class="lime-status-icon"><i data-lucide="volume-2" aria-hidden="true"></i></span> 32%</span><span class="lime-pipe">|</span><span class="lime-clock"><span class="lime-status-icon"><i data-lucide="calendar" aria-hidden="true"></i></span> Thu Oct 01, 01:42</span></div>
|
||||
</header>
|
||||
<div class="lime-workspace">
|
||||
<div class="lime-windows">
|
||||
<section class="lime-window lime-window-editor" data-window="editor" data-selected="true" aria-label="Emacs, focused window">
|
||||
<div class="lime-buffer-tabs"><span>attention.lisp</span><span>config.lisp</span></div>
|
||||
<pre class="lime-code"><span class="lime-comment">;;; Attention belongs to the live session.</span>
|
||||
|
||||
(<span class="lime-keyword">in-package</span> <span class="lime-constant">#:lime.x11</span>)
|
||||
|
||||
(<span class="lime-keyword">defun</span> <span class="lime-symbol">visit-next-request</span> (backend)
|
||||
(<span class="lime-keyword">let</span> ((requests
|
||||
(<span class="lime-symbol">backend-attention-client-ids</span> backend)))
|
||||
(<span class="lime-keyword">when</span> requests
|
||||
(<span class="lime-symbol">backend-attend-client</span> backend
|
||||
(first requests)))))
|
||||
|
||||
<span class="lime-comment">;; Quiet until something needs you.</span>
|
||||
|
||||
<span class="lime-caret" aria-hidden="true"></span></pre>
|
||||
<div class="lime-edit-space"></div>
|
||||
<div class="lime-mode-line"><span>** attention.lisp</span><span>Lisp · 15:0</span></div>
|
||||
<div class="lime-minibuffer">Connected to SBCL. Ready.</div>
|
||||
</section>
|
||||
<div class="lime-stack">
|
||||
<section class="lime-window" data-window="repl" data-selected="false" aria-label="Lisp REPL, unfocused window">
|
||||
<div class="lime-terminal">
|
||||
<p class="lime-faded">SBCL · lime development</p>
|
||||
<p><span class="lime-symbol">LIME></span> (backend-attention-client-ids<br> *backend*)<br><span class="lime-string">("x11-800005")</span></p>
|
||||
<p><span class="lime-symbol">LIME></span> (world-revision *world*)<br><span class="lime-constant">42</span></p>
|
||||
<p><span class="lime-symbol">LIME></span> <span class="lime-caret" aria-hidden="true"></span></p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="lime-window" data-window="notes" data-selected="false" aria-label="Project notes, unfocused window">
|
||||
<div class="lime-notes">
|
||||
<span class="lime-faded">~/notes/lime.org</span>
|
||||
<h3>* Making a desk feel like home</h3>
|
||||
<p><span class="lime-symbol">DONE</span> activities + views<br><span class="lime-symbol">DONE</span> persistence<br><span class="lime-symbol">DONE</span> attention indicators</p>
|
||||
<div class="lime-note-rule"></div>
|
||||
<p><span class="lime-string">NEXT</span> actually live here</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<section class="lime-menu" id="lime-palette-menu" aria-label="Lime which-key command menu">
|
||||
<div class="lime-menu-top"><span class="lime-menu-heading">Lime</span><button class="lime-menu-back" type="button">Esc close</button></div>
|
||||
<div class="lime-map">
|
||||
<button type="button" data-prefix="Activities"><kbd>a</kbd><span class="lime-map-label">Activities</span><span class="lime-map-plus">+</span></button>
|
||||
<button type="button" data-prefix="Views"><kbd>v</kbd><span class="lime-map-label">Views</span><span class="lime-map-plus">+</span></button>
|
||||
<button type="button" data-prefix="Windows"><kbd>w</kbd><span class="lime-map-label">Windows</span><span class="lime-map-plus">+</span></button>
|
||||
<button type="button" data-prefix="Layout"><kbd>l</kbd><span class="lime-map-label">Layout</span><span class="lime-map-plus">+</span></button>
|
||||
<button type="button" data-prefix="Heads"><kbd>h</kbd><span class="lime-map-label">Heads</span><span class="lime-map-plus">+</span></button>
|
||||
<button type="button" data-prefix="Launch"><kbd>r</kbd><span class="lime-map-label">Launch</span><span class="lime-map-plus">+</span></button>
|
||||
</div>
|
||||
<div class="lime-menu-footer"><span>Space · search commands</span><span>Esc · close</span></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="lime-palette-key" role="group" aria-label="Live palette editor">
|
||||
<span class="lime-palette-name" aria-live="polite">Your picks</span>
|
||||
<div class="lime-color-grid" data-color-fields="primary"></div>
|
||||
<details class="lime-more-colors">
|
||||
<summary>More colors</summary>
|
||||
<div class="lime-color-grid" data-color-fields="more"></div>
|
||||
</details>
|
||||
</div>
|
||||
</section>
|
||||
<script>
|
||||
(() => {
|
||||
const root = document.getElementById('lime-lisp-palettes');
|
||||
const palettes = {
|
||||
// Bar/window colors: ~/.config/dwm/config.h, active `comfy` scheme.
|
||||
// Status roles: ~/scripts/bar.sh, the script launched by ~/.xinitrc.
|
||||
// Lime's extra menu/app roles reuse this palette for the comparison.
|
||||
'Your dwm · comfy': { base:'#060a0c',surface:'#060a0c',selection:'#121f25','selection-ink':'#ffdbb0',text:'#ffdbb0',muted:'#416e79',accent:'#ffac54',mint:'#416e79',sky:'#416e79',alert:'#d44429',edge:'#121f25',separator:'#ffdbb0',music:'#416e79',volume:'#ffac54',clock:'#d44429','status-icon':'inherit' },
|
||||
'Warm signal': { base:'#191919',surface:'#222222',selection:'#30302f','selection-ink':'#ce956f',text:'#c9c3b8',muted:'#a29b90',accent:'#ce956f',mint:'#a6b59a',sky:'#89a3ab',alert:'#d77d70',edge:'#494743','bar-text':'#b9b4ab',separator:'#68655f','status-icon':'#89a3ab' },
|
||||
'Fuji · quieter': { base:'#0f0f0f',surface:'#191919',selection:'#262626','selection-ink':'#c6a679',text:'#cacaca',muted:'#989898',accent:'#c6a679',mint:'#8aac8b',sky:'#8a98ac',alert:'#ac8aac',edge:'#4c4c4c','bar-text':'#b5b5b5',separator:'#686868','status-icon':'#8a98ac' },
|
||||
'Fuji · full accents': { base:'#0f0f0f',surface:'#191919',selection:'#262626','selection-ink':'#c6a679',text:'#f0f0f0',muted:'#8a98ac',accent:'#c6a679',mint:'#8aac8b',sky:'#8a98ac',alert:'#ac8aac',edge:'#4c4c4c','bar-background':'#0f0f0f',separator:'#8f8aac','menu-label':'#8f8aac',music:'#8aac8b',volume:'#8aacab',clock:'#aca98a','status-icon':'inherit' },
|
||||
'Fuji · Mountain': { base:'#0f0f0f',surface:'#191919',selection:'#262626','selection-ink':'#f0f0f0',text:'#cacaca',muted:'#989898',accent:'#c6a679',mint:'#8aac8b',sky:'#7797b7',alert:'#ac8a8c',edge:'#4c4c4c' },
|
||||
'Workbench · softened': { base:'#232323',surface:'#2d2d2d',selection:'#494743','selection-ink':'#e3ddd2',text:'#ddd7cc',muted:'#aba69e',accent:'#d79a75',mint:'#c9be99',sky:'#b7bcc0',alert:'#e7c279',edge:'#53514e' },
|
||||
'Workbench': { base:'#202321',surface:'#2b2e2b',selection:'#d8d0bd','selection-ink':'#2a2d29',text:'#ddd8c8',muted:'#a7aa98',accent:'#d79a75',mint:'#b9c285',sky:'#adbeb0',alert:'#e7c279',edge:'#51554b' },
|
||||
'Late-night listener': { base:'#212322',surface:'#2a2d2a',selection:'#424739','selection-ink':'#e3dfc9',text:'#d9d8c3',muted:'#a5ab98',accent:'#c6c6a0',mint:'#b3bf7e',sky:'#d29e85',alert:'#df967c',edge:'#515849' },
|
||||
'Lambda Lab · steel': { base:'#181d23',surface:'#222a31',selection:'#2c3b46',text:'#e3e2da',muted:'#9eacb5',accent:'#9bb9c9',mint:'#96c6b1',sky:'#a8bfce',alert:'#e4b080',edge:'#43515c' },
|
||||
'Lambda Lab · graphite': { base:'#1b1e22',surface:'#24282d',selection:'#343a40',text:'#e3e2da',muted:'#a2abae',accent:'#c2ccc8',mint:'#96c6b1',sky:'#a8bfce',alert:'#e4b080',edge:'#474f55' },
|
||||
'Lambda Lab': { base:'#181c25',surface:'#202631',selection:'#30344a',text:'#e3e2da',muted:'#9ca8b6',accent:'#b7a7de',mint:'#96c6b1',sky:'#9abbd3',alert:'#e4b080',edge:'#414b5c' },
|
||||
'Phosphor Garden': { base:'#18211f',surface:'#202c27',selection:'#2a4037',text:'#e0e5d9',muted:'#9fb2a5',accent:'#a7cfaa',mint:'#b4bae0',sky:'#8dbfca',alert:'#e3b08b',edge:'#43584b' },
|
||||
'Amethyst Workstation': { base:'#221e29',surface:'#2b2535',selection:'#3c314a',text:'#e7dfe8',muted:'#b1a1ba',accent:'#d1a4cc',mint:'#9cc9c5',sky:'#a5b9df',alert:'#e4b78b',edge:'#55465f' }
|
||||
};
|
||||
// Personal Lime accents extend the dwm reference without recoloring
|
||||
// its widgets, separators, title, or application syntax samples.
|
||||
palettes['Comfy · Lime accents'] = {
|
||||
...palettes['Your dwm · comfy'], logo:'#9fb58b', attention:'#b2a1c7'
|
||||
};
|
||||
// Custom accent set, using quieter Fuji's unchanged neutral surfaces,
|
||||
// text contrast, separators, and menu labels as the foundation.
|
||||
palettes['Fuji · clear colors'] = {
|
||||
...palettes['Fuji · quieter'],
|
||||
accent:'#d99856', 'selection-ink':'#d99856',
|
||||
mint:'#83b56b', sky:'#6c9fd2', alert:'#d97065',
|
||||
logo:'#83b56b', attention:'#d97065',
|
||||
music:'#6c9fd2', volume:'#d1bb62', clock:'#66b6b2',
|
||||
'status-icon':'inherit'
|
||||
};
|
||||
// Creamier lettering at similar brightness; neutral surfaces retained.
|
||||
// Status labels and logo share the quiet foreground. Only the small
|
||||
// widget icons use denim blue, with brick red reserved for attention.
|
||||
palettes['Fuji · cream'] = {
|
||||
...palettes['Fuji · quieter'],
|
||||
text:'#cbc5b7', muted:'#928f86', 'bar-text':'#c4bfb2',
|
||||
accent:'#b6ab70', 'selection-ink':'#b6ab70',
|
||||
mint:'#91a58a', sky:'#76929f', alert:'#b76c64',
|
||||
'status-icon':'#76929f'
|
||||
};
|
||||
// Keep the accepted colors and arrangement fixed while comparing
|
||||
// warmer lettering, then a straw-yellow alternative to the olive focus.
|
||||
palettes['Fuji · warmer cream'] = {
|
||||
...palettes['Fuji · cream'], text:'#dbc9a6', 'bar-text':'#d3c2a1'
|
||||
};
|
||||
palettes['Fuji · cream & yellow'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#c7b45b', 'selection-ink':'#c7b45b'
|
||||
};
|
||||
palettes['Fuji · cream & golden yellow'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#d8b04c', 'selection-ink':'#d8b04c'
|
||||
};
|
||||
palettes['Fuji · cream & muted yellow'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#b8aa80', 'selection-ink':'#b8aa80'
|
||||
};
|
||||
palettes['Fuji · butter yellow'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#d6cc83', 'selection-ink':'#d6cc83'
|
||||
};
|
||||
palettes['Fuji · dim butter'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#c3ba77', 'selection-ink':'#c3ba77'
|
||||
};
|
||||
// Establish the hue with standard RGB yellow, then reduce saturation
|
||||
// and brightness while retaining equal red/green channels (60° hue).
|
||||
palettes['Yellow reference'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#ffff00', 'selection-ink':'#ffff00'
|
||||
};
|
||||
palettes['Softer yellow'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#e0e080', 'selection-ink':'#e0e080'
|
||||
};
|
||||
palettes['Cream · dwm focus'] = {
|
||||
...palettes['Fuji · warmer cream'],
|
||||
accent:'#ffac54', 'selection-ink':'#ffac54'
|
||||
};
|
||||
palettes['dwm cream · neutral backgrounds'] = {
|
||||
...palettes['Cream · dwm focus'],
|
||||
text:'#ffdbb0', 'bar-text':'#ffdbb0', 'title-text':'#ffdbb0'
|
||||
};
|
||||
palettes['Your picks'] = {
|
||||
...palettes['dwm cream · neutral backgrounds'],
|
||||
accent:'#ffb054', 'selection-ink':'#ffb054',
|
||||
text:'#dbc9a6', 'bar-text':'#dbc9a6', 'title-text':'#dbc9a6',
|
||||
mint:'#768565'
|
||||
};
|
||||
const state = { palette:'Your picks', menu:true, focused:'editor', matchedApps:true };
|
||||
// Keep edits per comparison palette, so switching does not lose them.
|
||||
const colorEdits = new Map();
|
||||
const colorFields = [
|
||||
{ id:'accent', label:'Focus / accent', roles:['accent','selection-ink'], primary:true },
|
||||
{ id:'text', label:'Cream text / title', roles:['text','bar-text','title-text','logo','menu-label','music','volume','clock'], primary:true },
|
||||
{ id:'sky', label:'Icons / blue', roles:['sky','status-icon'], primary:true },
|
||||
{ id:'base', label:'Window background', roles:['base'] },
|
||||
{ id:'surface', label:'Bar / menu background', roles:['surface','bar-background'] },
|
||||
{ id:'selection', label:'Title / hover background', roles:['selection'] },
|
||||
{ id:'muted', label:'Secondary text', roles:['muted'] },
|
||||
{ id:'edge', label:'Unfocused borders', roles:['edge'] },
|
||||
{ id:'separator', label:'Bar separators', roles:['separator'] },
|
||||
{ id:'mint', label:'Green', roles:['mint'] },
|
||||
{ id:'alert', label:'Attention / red', roles:['alert','attention'] }
|
||||
];
|
||||
function currentPalette() {
|
||||
const p = {...palettes[state.palette]};
|
||||
const edits = colorEdits.get(state.palette) || {};
|
||||
colorFields.forEach(field => {
|
||||
if (edits[field.id]) field.roles.forEach(role => { p[role] = edits[field.id]; });
|
||||
});
|
||||
return p;
|
||||
}
|
||||
function normalizeHex(value) {
|
||||
const hex = value.trim().replace(/^#/, '');
|
||||
if (/^[0-9a-f]{6}$/i.test(hex)) return '#' + hex.toLowerCase();
|
||||
if (/^[0-9a-f]{3}$/i.test(hex)) return '#' + [...hex].map(c => c + c).join('').toLowerCase();
|
||||
return null;
|
||||
}
|
||||
function editColor(field, value) {
|
||||
const edits = colorEdits.get(state.palette) || {};
|
||||
edits[field.id] = value;
|
||||
colorEdits.set(state.palette, edits);
|
||||
render();
|
||||
}
|
||||
function buildColorEditor() {
|
||||
colorFields.forEach(field => {
|
||||
const group = document.createElement('div'); group.className = 'lime-color-field';
|
||||
const label = document.createElement('label'); label.textContent = field.label;
|
||||
const inputs = document.createElement('div'); inputs.className = 'lime-color-inputs';
|
||||
const picker = document.createElement('input'); picker.type = 'color';
|
||||
picker.setAttribute('aria-label', field.label + ' color picker');
|
||||
const hex = document.createElement('input'); hex.type = 'text';
|
||||
hex.id = 'lime-color-' + field.id; label.htmlFor = hex.id;
|
||||
hex.spellcheck = false; hex.autocomplete = 'off';
|
||||
hex.setAttribute('autocapitalize', 'off');
|
||||
hex.setAttribute('aria-invalid', 'false');
|
||||
const error = document.createElement('span'); error.className = 'lime-color-error';
|
||||
error.id = hex.id + '-error'; error.hidden = true; error.setAttribute('role', 'alert');
|
||||
error.textContent = 'Use 3 or 6 hex digits, e.g. #FFAC54.';
|
||||
hex.setAttribute('aria-describedby', error.id);
|
||||
Object.assign(field, {picker, hex, error});
|
||||
hex.addEventListener('input', () => {
|
||||
const color = normalizeHex(hex.value);
|
||||
hex.setAttribute('aria-invalid', String(!color));
|
||||
error.hidden = true;
|
||||
if (color) editColor(field, color);
|
||||
});
|
||||
hex.addEventListener('blur', () => {
|
||||
const color = normalizeHex(hex.value);
|
||||
error.hidden = !!color;
|
||||
if (color) hex.value = color.toUpperCase();
|
||||
});
|
||||
picker.addEventListener('input', () => {
|
||||
hex.value = picker.value.toUpperCase();
|
||||
hex.setAttribute('aria-invalid', 'false'); error.hidden = true;
|
||||
editColor(field, picker.value);
|
||||
});
|
||||
inputs.append(picker, hex); group.append(label, inputs, error);
|
||||
root.querySelector(`[data-color-fields="${field.primary ? 'primary' : 'more'}"]`).append(group);
|
||||
});
|
||||
}
|
||||
const menu = root.querySelector('.lime-menu');
|
||||
const map = root.querySelector('.lime-map');
|
||||
const heading = root.querySelector('.lime-menu-heading');
|
||||
const back = root.querySelector('.lime-menu-back');
|
||||
let branch = null;
|
||||
const rootEntries = [['a','Activities'],['v','Views'],['w','Windows'],['l','Layout'],['h','Heads'],['r','Launch']];
|
||||
const branches = {
|
||||
Activities:[['n','New activity…'],['o','Open activity / view…']],
|
||||
Views:[['s','Save checkpoint…'],['u','Update checkpoint'],['o','Open view…']],
|
||||
Windows:[['a','Attention…'],['i','Show hidden window…'],['h','Hide focused window'],['n','Focus next'],['p','Focus previous'],['f','Toggle float']],
|
||||
Layout:[['m','Master/stack'],['o','Monocle'],['c','Cycle layout']],
|
||||
Heads:[['n','Select next Head'],['p','Select previous Head']],
|
||||
Launch:[['r','Run command…'],['t','Launch terminal'],['b','Launch browser']]
|
||||
};
|
||||
function renderMenu() {
|
||||
const entries = branch ? branches[branch] : rootEntries;
|
||||
heading.textContent = branch ? `Lime › ${branch}` : 'Lime';
|
||||
back.textContent = branch ? '← back' : 'Esc close';
|
||||
map.replaceChildren();
|
||||
entries.forEach(([key,label]) => {
|
||||
const button = document.createElement('button'); button.type = 'button';
|
||||
button.dataset.branch = String(!branch);
|
||||
const kbd = document.createElement('kbd'); kbd.textContent = key;
|
||||
const text = document.createElement('span'); text.className='lime-map-label'; text.textContent = label;
|
||||
button.append(kbd,text);
|
||||
if (!branch) {
|
||||
const more = document.createElement('span'); more.className='lime-map-plus'; more.textContent='+'; button.append(more);
|
||||
}
|
||||
button.addEventListener('click', () => {
|
||||
if (!branch) { branch = label; renderMenu(); }
|
||||
else if (label === 'Focus next' || label === 'Focus previous') {
|
||||
state.focused = state.focused === 'editor' ? 'repl' : 'editor'; render();
|
||||
} else { state.menu=false; branch=null; render(); renderMenu(); }
|
||||
});
|
||||
map.append(button);
|
||||
});
|
||||
}
|
||||
function render() {
|
||||
const p = currentPalette();
|
||||
Object.entries(p).forEach(([role,color])=>root.style.setProperty(`--lime-${role}`,color));
|
||||
const roleDefaults = {'bar-text':p.text,'bar-background':p.surface,'title-text':p['selection-ink'] || p.accent,logo:p['bar-text'] || p.text,attention:p.alert,separator:p.edge,'menu-label':p.text,key:p.accent,music:p['bar-text'] || p.text,volume:p['bar-text'] || p.text,clock:p['bar-text'] || p.text,'status-icon':p.muted};
|
||||
Object.entries(roleDefaults).forEach(([role,color])=>root.style.setProperty(`--lime-${role}`,p[role] || color));
|
||||
root.style.setProperty('--lime-selection-ink', p['selection-ink'] || p.accent);
|
||||
root.style.setProperty('--lime-app', state.matchedApps ? p.base : '#090f12');
|
||||
root.style.setProperty('--lime-app-text', state.matchedApps ? p.text : '#dce6e5');
|
||||
root.style.setProperty('--lime-app-muted', state.matchedApps ? p.muted : '#8ba3ae');
|
||||
menu.hidden = !state.menu;
|
||||
root.querySelector('.lime-logo').setAttribute('aria-expanded',String(state.menu));
|
||||
const edited = Object.keys(colorEdits.get(state.palette) || {}).length > 0;
|
||||
root.querySelector('.lime-palette-name').textContent = state.palette + (edited ? ' · edited' : '');
|
||||
root.querySelectorAll('[data-palette]').forEach(button => {
|
||||
button.setAttribute('aria-pressed', String(button.dataset.palette === state.palette));
|
||||
});
|
||||
colorFields.forEach(field => {
|
||||
const color = p[field.roles[0]];
|
||||
field.picker.value = color;
|
||||
if (document.activeElement !== field.hex) {
|
||||
field.hex.value = color.toUpperCase();
|
||||
field.hex.setAttribute('aria-invalid', 'false');
|
||||
field.error.hidden = true;
|
||||
}
|
||||
});
|
||||
root.querySelectorAll('[data-window]').forEach(el => {
|
||||
const focused=el.dataset.window===state.focused;
|
||||
el.dataset.selected=String(focused);
|
||||
el.setAttribute('aria-label',`${el.dataset.window}, ${focused?'focused':'unfocused'} window`);
|
||||
});
|
||||
root.querySelector('.lime-title').textContent = state.focused==='editor'?'attention.lisp — Emacs':'*sly-mrepl sbcl* — st';
|
||||
}
|
||||
root.querySelectorAll('[data-palette]').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
state.palette = button.dataset.palette;
|
||||
render();
|
||||
});
|
||||
});
|
||||
root.querySelector('.lime-logo').addEventListener('click',()=> { state.menu=!state.menu; branch=null; renderMenu(); render(); });
|
||||
back.addEventListener('click',()=> { if (branch) { branch=null; renderMenu(); } else { state.menu=false; render(); } });
|
||||
root.addEventListener('keydown',event=> { if(event.key==='Escape') {state.menu=false;render();} });
|
||||
buildColorEditor(); renderMenu(); render();
|
||||
if (globalThis.Tweak) {
|
||||
const tweak = new Tweak({container:root,onChange:render});
|
||||
tweak.addToggle(state,'menu',{label:'Which-key menu open'});
|
||||
tweak.addSelect(state,'focused',{label:'Focused window',options:[{label:'Editor',value:'editor'},{label:'Lisp REPL',value:'repl'}]});
|
||||
tweak.addToggle(state,'matchedApps',{label:'Coordinate application backgrounds'});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
Reference in New Issue
Block a user