mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-13 17:57:04 +01:00
ui: share view in the shell, icon rail, phone polish
- shared view uses the bar, porthole and status band; outline gets its own window on wide screens; j/k, gg/G, Ctrl-d/u scroll with a vim-style ruler - rail doors are line icons in groups with hover tooltips and keycaps - phone: number-only space pills, no nested rims, icon dock, toast messages, back button and one-line meta in the document header - keycaps (.kbd) wherever keys are shown, styled scrollbars in Chrome, outline tracks position on jumps, breakpoints unified at 767px
This commit is contained in:
1 parent
9391b10af1
commit
ecfbab0eaa
14 files changed
+796
-382
No files matched your search
+27
-13
@@ -41,18 +41,31 @@
|
||||
headings = found
|
||||
current = found[0]?.id ?? ''
|
||||
|
||||
// The section whose heading last crossed the upper third is the one being
|
||||
// read; a band rather than a line, so a short section still registers.
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) current = entry.target.id
|
||||
}
|
||||
},
|
||||
{ root: scroller, rootMargin: '-10% 0px -70% 0px' },
|
||||
)
|
||||
for (const element of elements) observer.observe(element)
|
||||
return () => observer.disconnect()
|
||||
// The section being read is the last one whose heading has passed the
|
||||
// upper third of the view — worked out from positions on every scroll,
|
||||
// so a jump with G or Ctrl-d lands on the right one too. Scrolled to the
|
||||
// very end, the last heading wins even if it never got that high.
|
||||
let frame = 0
|
||||
const spy = () => {
|
||||
frame = 0
|
||||
const top = scroller.getBoundingClientRect().top
|
||||
const line = top + scroller.clientHeight / 3
|
||||
const room = scroller.scrollHeight - scroller.clientHeight
|
||||
const end = room > 2 && scroller.scrollTop >= room - 2
|
||||
let id = found[0]?.id ?? ''
|
||||
for (const element of elements) {
|
||||
if (end || element.getBoundingClientRect().top <= line) id = element.id
|
||||
else break
|
||||
}
|
||||
current = id
|
||||
}
|
||||
const onscroll = () => (frame ||= requestAnimationFrame(spy))
|
||||
scroller.addEventListener('scroll', onscroll, { passive: true })
|
||||
spy()
|
||||
return () => {
|
||||
scroller.removeEventListener('scroll', onscroll)
|
||||
cancelAnimationFrame(frame)
|
||||
}
|
||||
})
|
||||
|
||||
function jump(id: string) {
|
||||
@@ -105,5 +118,6 @@
|
||||
button:focus-visible { background: var(--light); color: var(--ink); }
|
||||
|
||||
.marker { width: 5px; height: 5px; transform: translateY(-2px); }
|
||||
.text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
/* A margin is narrow: long headings wrap rather than lose their ends. */
|
||||
.text { min-width: 0; line-height: 1.4; overflow-wrap: anywhere; }
|
||||
</style>
|
||||
Reference in new issue
Block a user