Initial Lime window manager

This commit is contained in:
2026-10-02 14:14:47 -05:00
commit ccd691edd0
121 changed files with 29719 additions and 0 deletions

191
work/ui-layer-sketch.html Normal file
View File

@@ -0,0 +1,191 @@
<div id="lime-ui-sketch" aria-label="Lime command surface sketch">
<style>
#lime-ui-sketch {
color: light-dark(#1d232b, #e8edf3);
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
#lime-ui-sketch * { box-sizing: border-box; }
#lime-ui-sketch .lime-ui-window {
position: relative;
min-height: 760px;
overflow: hidden;
background: light-dark(#d9dfe7, #202733);
border: 1px solid light-dark(#aab4c1, #3d4859);
border-radius: 8px;
}
#lime-ui-sketch .lime-ui-status {
display: flex;
justify-content: space-between;
padding: 7px 11px;
color: light-dark(#f8fafc, #edf2f7);
background: light-dark(#39475a, #111827);
font-size: 12px;
}
#lime-ui-sketch .lime-ui-desktop {
display: grid;
grid-template-columns: 1.1fr .9fr;
gap: 10px;
min-height: 729px;
padding: 12px;
background: light-dark(#c9d2de, #1a202b);
}
#lime-ui-sketch .lime-ui-client {
min-height: 705px;
padding: 10px;
color: light-dark(#253040, #cbd5e1);
background: light-dark(#f5f7fa, #2b3443);
border: 1px solid light-dark(#b6c1ce, #435065);
border-radius: 4px;
font-size: 12px;
}
#lime-ui-sketch .lime-ui-client strong { color: light-dark(#111827, #f8fafc); font-weight: 500; }
#lime-ui-sketch .lime-ui-code { margin-top: 20px; color: light-dark(#516172, #9aacbe); line-height: 1.7; }
#lime-ui-sketch .lime-ui-music { display: grid; align-content: end; gap: 6px; }
#lime-ui-sketch .lime-ui-meter { height: 5px; background: light-dark(#c6d0db, #111827); }
#lime-ui-sketch .lime-ui-meter span { display: block; width: 61%; height: 100%; background: light-dark(#4b7ea8, #71b7f0); }
#lime-ui-sketch .lime-ui-palette {
position: absolute;
top: 43px;
right: 24px;
left: 24px;
margin: 0;
padding: 10px;
color: light-dark(#16202c, #e6edf5);
background: light-dark(#f9fbfd, #161d27);
border: 1px solid light-dark(#8c9bab, #526174);
border-radius: 6px;
box-shadow: 0 12px 28px light-dark(rgb(31 41 55 / .24), rgb(0 0 0 / .45));
}
#lime-ui-sketch .lime-ui-tabs { display: flex; gap: 6px; margin-bottom: 9px; }
#lime-ui-sketch button {
color: inherit;
font: inherit;
cursor: pointer;
}
#lime-ui-sketch .lime-ui-tab {
padding: 4px 7px;
background: transparent;
border: 0;
border-bottom: 2px solid transparent;
font-size: 12px;
}
#lime-ui-sketch .lime-ui-tab[aria-selected="true"] { border-bottom-color: light-dark(#2674a8, #7ac4f7); }
#lime-ui-sketch .lime-ui-query {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
background: light-dark(#e8eef4, #242e3d);
border: 1px solid light-dark(#a7b4c1, #4d5d73);
border-radius: 3px;
}
#lime-ui-sketch .lime-ui-query mark { color: light-dark(#21628d, #8ad1ff); background: transparent; }
#lime-ui-sketch input {
width: 100%;
color: inherit;
background: transparent;
border: 0;
font: inherit;
font-size: 13px;
outline: none;
}
#lime-ui-sketch .lime-ui-list { display: grid; gap: 2px; margin-top: 8px; }
#lime-ui-sketch .lime-ui-choice {
display: grid;
grid-template-columns: 1fr auto;
gap: 12px;
align-items: center;
width: 100%;
padding: 7px 8px;
text-align: left;
background: transparent;
border: 0;
border-radius: 3px;
font-size: 12px;
}
#lime-ui-sketch .lime-ui-choice:hover,
#lime-ui-sketch .lime-ui-choice:focus-visible { background: light-dark(#dceefa, #263d51); }
#lime-ui-sketch .lime-ui-choice.is-selected { background: light-dark(#d3e9fa, #1f4057); }
#lime-ui-sketch .lime-ui-hint { color: light-dark(#607286, #a4b5c8); }
#lime-ui-sketch .lime-ui-subtle { color: light-dark(#607286, #a4b5c8); }
#lime-ui-sketch .lime-ui-prefix { display: none; }
#lime-ui-sketch[data-mode="prefix"] .lime-ui-direct { display: none; }
#lime-ui-sketch[data-mode="prefix"] .lime-ui-prefix { display: block; }
#lime-ui-sketch .lime-ui-footer { display: flex; justify-content: space-between; margin-top: 9px; font-size: 11px; }
@media (max-width: 480px) {
#lime-ui-sketch .lime-ui-desktop { grid-template-columns: 1fr; }
#lime-ui-sketch .lime-ui-palette { margin-left: 10px; margin-right: 10px; }
}
</style>
<div class="lime-ui-window">
<div class="lime-ui-status"><span>Lime · development / Code</span><span>left head · dirty</span></div>
<div class="lime-ui-desktop" aria-hidden="true">
<div class="lime-ui-client"><strong>emacs — lime/core.lisp</strong><div class="lime-ui-code">(defstruct activity ...)<br> (view-id ...)<br> (presentation ...)</div></div>
<div class="lime-ui-client lime-ui-music"><strong>ncmpcpp</strong><span>Moon Safari — Air</span><div class="lime-ui-meter"><span></span></div></div>
</div>
<div class="lime-ui-palette" role="dialog" aria-label="Lime command surface">
<div class="lime-ui-tabs" role="tablist" aria-label="Command interaction">
<button class="lime-ui-tab" id="lime-ui-direct-tab" type="button" role="tab" aria-controls="lime-ui-direct-panel" aria-selected="true">Direct search</button>
<button class="lime-ui-tab" id="lime-ui-prefix-tab" type="button" role="tab" aria-controls="lime-ui-prefix-panel" aria-selected="false">Key path</button>
</div>
<div class="lime-ui-direct" id="lime-ui-direct-panel" role="tabpanel" aria-labelledby="lime-ui-direct-tab">
<label class="sr-only" for="lime-ui-search">Search commands, activities, or views</label>
<div class="lime-ui-query"><mark>⌘</mark><input id="lime-ui-search" value="switch to…" aria-label="Search commands, activities, or views"></div>
<div class="lime-ui-list">
<button class="lime-ui-choice is-selected" type="button"><span>View · development / <strong>Code</strong></span><span class="lime-ui-hint">Enter</span></button>
<button class="lime-ui-choice" type="button"><span>View · development / Debug</span><span class="lime-ui-hint">Enter</span></button>
<button class="lime-ui-choice" type="button"><span>Activity · game / Play</span><span class="lime-ui-hint">Enter</span></button>
<button class="lime-ui-choice" type="button"><span>New named Activity…</span><span class="lime-ui-hint">a</span></button>
</div>
</div>
<div class="lime-ui-prefix" id="lime-ui-prefix-panel" role="tabpanel" aria-labelledby="lime-ui-prefix-tab" hidden>
<div class="lime-ui-query"><mark>Super</mark><span id="lime-ui-path">then press…</span></div>
<div class="lime-ui-list">
<button class="lime-ui-choice" type="button" data-path="Activity"><span><strong>a</strong> · Activity</span><span class="lime-ui-hint">new / switch</span></button>
<button class="lime-ui-choice" type="button" data-path="View"><span><strong>v</strong> · View</span><span class="lime-ui-hint">save / switch</span></button>
<button class="lime-ui-choice" type="button" data-path="Window"><span><strong>w</strong> · Window</span><span class="lime-ui-hint">focus / move</span></button>
<button class="lime-ui-choice" type="button" data-path="Head"><span><strong>h</strong> · Head</span><span class="lime-ui-hint">select / send</span></button>
</div>
</div>
<div class="lime-ui-footer"><span id="lime-ui-state" aria-live="polite">Type to filter · Enter to run</span><span>Esc cancel</span></div>
</div>
</div>
<script>
(() => {
const root = document.getElementById('lime-ui-sketch');
const directTab = document.getElementById('lime-ui-direct-tab');
const prefixTab = document.getElementById('lime-ui-prefix-tab');
const directPanel = document.getElementById('lime-ui-direct-panel');
const prefixPanel = document.getElementById('lime-ui-prefix-panel');
const search = document.getElementById('lime-ui-search');
const state = document.getElementById('lime-ui-state');
const path = document.getElementById('lime-ui-path');
function select(mode) {
const direct = mode === 'direct';
root.dataset.mode = mode;
directTab.setAttribute('aria-selected', String(direct));
prefixTab.setAttribute('aria-selected', String(!direct));
directPanel.hidden = !direct;
prefixPanel.hidden = direct;
if (direct) { search.focus(); state.textContent = 'Type to filter · Enter to run'; }
else { state.textContent = 'Choose a branch · Esc cancel'; }
}
directTab.addEventListener('click', () => select('direct'));
prefixTab.addEventListener('click', () => select('prefix'));
root.querySelectorAll('[data-path]').forEach(button => button.addEventListener('click', () => {
path.textContent = button.dataset.path + ' · choose command…';
state.textContent = button.dataset.path + ' menu opened';
}));
root.querySelectorAll('.lime-ui-direct .lime-ui-choice').forEach(button => button.addEventListener('click', () => {
root.querySelectorAll('.lime-ui-direct .lime-ui-choice').forEach(choice => choice.classList.remove('is-selected'));
button.classList.add('is-selected');
state.textContent = button.textContent.trim() + ' selected';
}));
})();
</script>
</div>