Fix: Clean headings/anchors; no IDs in text

This commit is contained in:
2025-09-14 22:32:02 -07:00
parent 68185d96ac
commit 51b98c1ba2

View File

@@ -16,18 +16,20 @@
.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{scrollbar-width:none} .no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{scrollbar-width:none}
.btn{transition:.15s transform}.btn:active{transform:scale(.98)} .btn{transition:.15s transform}.btn:active{transform:scale(.98)}
.anchor{scroll-margin-top:76px} .anchor{scroll-margin-top:76px}
pre{position:relative;border:1px solid #e5e7eb;border-radius:.75rem}
.code-actions{position:absolute;top:.5rem;right:.5rem;display:flex;gap:.5rem;align-items:center} .code-actions{position:absolute;top:.5rem;right:.5rem;display:flex;gap:.5rem;align-items:center}
.copy-btn{background:#0f172a;color:#fff;border-radius:.5rem;padding:.2rem .5rem;font-size:.75rem;opacity:.9} .copy-btn{background:#0f172a;color:#fff;border-radius:.5rem;padding:.2rem .5rem;font-size:.75rem;opacity:.9}
.char-c{font-size:.75rem;color:#64748b} .char-c{font-size:.75rem;color:#64748b}
pre{position:relative;border:1px solid #e5e7eb;border-radius:.75rem} @media (max-width:480px){.char-c{display:none}}
.anchor-link{margin-left:.5rem;color:#9ca3af;text-decoration:none}
.anchor-link:hover{color:#6b7280}
@media (min-width:1024px){.lg\:grid-cols-layout{grid-template-columns:var(--sbw) 1fr}} @media (min-width:1024px){.lg\:grid-cols-layout{grid-template-columns:var(--sbw) 1fr}}
</style> </style>
<script defer src="https://cdn.jsdelivr.net/npm/cash-dom/dist/cash.min.js"></script>
</head> </head>
<body class="bg-white text-gray-900 selection:bg-black/10"> <body class="bg-white text-gray-900 selection:bg-black/10">
<header class="sticky top-0 z-30 bg-white/80 backdrop-blur border-b border-gray-200"> <header class="sticky top-0 z-30 bg-white/80 backdrop-blur border-b border-gray-200">
<div class="mx-auto w-full px-4 py-3 grid grid-cols-3 items-center"> <div class="mx-auto w-full px-4 py-3 grid grid-cols-3 items-center">
<button id=menuBtn class="h-9 w-9 rounded-xl bg-gray-100 hover:bg-gray-200 flex items-center justify-center btn" title="Menu"><i data-lucide=panel-left class="h-5 w-5"></i></button> <button id=menuBtn class="h-9 w-9 rounded-xl bg-gray-100 hover:bg-gray-200 flex items-center justify-center btn" title="Menu"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M3 12h18M3 18h18"/></svg></button>
<div class="justify-self-center text-base font-semibold select-none pointer-events-none">Hi</div> <div class="justify-self-center text-base font-semibold select-none pointer-events-none">Hi</div>
<div class="justify-self-end"></div> <div class="justify-self-end"></div>
</div> </div>
@@ -45,7 +47,7 @@ pre{position:relative;border:1px solid #e5e7eb;border-radius:.75rem}
<h1 class="text-3xl sm:text-4xl font-bold tracking-tight">Hi — a corely symbolic language</h1> <h1 class="text-3xl sm:text-4xl font-bold tracking-tight">Hi — a corely symbolic language</h1>
<p class="mt-3 text-gray-600">Inspired by JavaScript. Few keywords, many symbols. Designed so the core reads naturally across languages, for the whole world.</p> <p class="mt-3 text-gray-600">Inspired by JavaScript. Few keywords, many symbols. Designed so the core reads naturally across languages, for the whole world.</p>
<div class="mt-4 flex flex-wrap gap-2"> <div class="mt-4 flex flex-wrap gap-2">
<a href="#hello" class="px-3 py-1.5 rounded-full bg-gray-900 text-white text-sm btn">Get started</a> <a href="#hello-world" class="px-3 py-1.5 rounded-full bg-gray-900 text-white text-sm btn">Get started</a>
<a href="https://github.com/hi-language" class="px-3 py-1.5 rounded-full bg-gray-100 hover:bg-gray-200 text-sm btn" target=_blank rel=noopener><svg xmlns="http://www.w3.org/2000/svg" class="inline -mt-0.5 mr-1" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .5A12 12 0 0 0 0 12.64a12.15 12.15 0 0 0 8.2 11.55c.6.11.82-.27.82-.6v-2.17c-3.34.74-4.05-1.65-4.05-1.65a3.29 3.29 0 0 0-1.36-1.82c-1.1-.78.09-.77.09-.77a2.6 2.6 0 0 1 1.89 1.29 2.64 2.64 0 0 0 3.61 1 2.66 2.66 0 0 1 .78-1.65c-2.67-.31-5.47-1.36-5.47-6.06A4.8 4.8 0 0 1 6 7.57a4.45 4.45 0 0 1 .12-3.29s1-.33 3.3 1.26a11.39 11.39 0 0 1 6 0c2.3-1.59 3.3-1.26 3.3-1.26.44 1.03.48 2.2.12 3.29a4.79 4.79 0 0 1 1.27 3.32c0 4.72-2.8 5.75-5.47 6.06a2.97 2.97 0 0 1 .84 2.31v3.43c0 .34.22.73.83.6A12.16 12.16 0 0 0 24 12.64 12 12 0 0 0 12 .5Z"/></svg>GitHub</a> <a href="https://github.com/hi-language" class="px-3 py-1.5 rounded-full bg-gray-100 hover:bg-gray-200 text-sm btn" target=_blank rel=noopener><svg xmlns="http://www.w3.org/2000/svg" class="inline -mt-0.5 mr-1" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 .5A12 12 0 0 0 0 12.64a12.15 12.15 0 0 0 8.2 11.55c.6.11.82-.27.82-.6v-2.17c-3.34.74-4.05-1.65-4.05-1.65a3.29 3.29 0 0 0-1.36-1.82c-1.1-.78.09-.77.09-.77a2.6 2.6 0 0 1 1.89 1.29 2.64 2.64 0 0 0 3.61 1 2.66 2.66 0 0 1 .78-1.65c-2.67-.31-5.47-1.36-5.47-6.06A4.8 4.8 0 0 1 6 7.57a4.45 4.45 0 0 1 .12-3.29s1-.33 3.3 1.26a11.39 11.39 0 0 1 6 0c2.3-1.59 3.3-1.26 3.3-1.26.44 1.03.48 2.2.12 3.29a4.79 4.79 0 0 1 1.27 3.32c0 4.72-2.8 5.75-5.47 6.06a2.97 2.97 0 0 1 .84 2.31v3.43c0 .34.22.73.83.6A12.16 12.16 0 0 0 24 12.64 12 12 0 0 0 12 .5Z"/></svg>GitHub</a>
</div> </div>
</div> </div>
@@ -61,14 +63,11 @@ pre{position:relative;border:1px solid #e5e7eb;border-radius:.75rem}
<nav id="sideNavMobile" class="p-2 text-sm overflow-y-auto no-scrollbar"></nav> <nav id="sideNavMobile" class="p-2 text-sm overflow-y-auto no-scrollbar"></nav>
</aside> </aside>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/markdown-it@14.1.0/dist/markdown-it.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/highlight.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.11.1/build/highlight.min.js"></script>
<!-- Author the docs below in Markdown; use ~~~ fences to avoid breaking outer code-block --> <!-- Author docs in Markdown; use ~~~ fences -->
<script id=md type="text/markdown"> <script id=md type="text/markdown">
# Hi
Meet Hi a corely symbolic language inspired by JavaScript. Meet Hi a corely symbolic language inspired by JavaScript.
It keeps the core mostly symbols and uses keywords only where theyre truly practical. It keeps the core mostly symbols and uses keywords only where theyre truly practical.
@@ -79,14 +78,14 @@ It keeps the core mostly symbols and uses keywords only where theyre truly pr
> Print helper: `_()` writes to the console. > Print helper: `_()` writes to the console.
## Hello, world {#hello} ## Hello, world
~~~js ~~~js
// Hello World in Hi // Hello World in Hi
_("Hi world") _("Hi world")
~~~ ~~~
## Declarations and Assignment {#decl} ## Declarations and Assignment
- `:` declares a name. - `:` declares a name.
- `=` assigns or mutates a value. - `=` assigns or mutates a value.
@@ -98,7 +97,7 @@ greeting = greeting + ", " + name
_(greeting) // "Hi, Orion" _(greeting) // "Hi, Orion"
~~~ ~~~
## Blocks (object + function in one) {#blocks} ## Blocks (object + function in one)
In Hi, `{}` is a Block. It can hold properties and executable code. In Hi, `{}` is a Block. It can hold properties and executable code.
A Block is both an object and a function at the same time. A Block is both an object and a function at the same time.
@@ -158,7 +157,7 @@ add: (a, b) { a + b }
_( add(2, 3) ) // 5 _( add(2, 3) ) // 5
~~~ ~~~
## Truthiness and Equality {#truth} ## Truthiness and Equality
Truthiness is value-based: Truthiness is value-based:
@@ -178,7 +177,7 @@ Equality:
== // equivalent to JS === == // equivalent to JS ===
~~~ ~~~
## Conditionals (ternary-style Blocks) {#conds} ## Conditionals (ternary-style Blocks)
A conditional is an expression that selects a Block. A conditional is an expression that selects a Block.
@@ -204,7 +203,7 @@ grade: (score > 90) ? { "A" }
_(grade) // "B" _(grade) // "B"
~~~ ~~~
## Arrays {#arrays} ## Arrays
~~~js ~~~js
primes: [2, 3, 5, 7] primes: [2, 3, 5, 7]
@@ -217,7 +216,7 @@ primes[0] = 1
_(primes) // [1, 3, 5, 7] _(primes) // [1, 3, 5, 7]
~~~ ~~~
## Loops {#loops} ## Loops
`* { ... }` after a loop header runs the Block each iteration. `* { ... }` after a loop header runs the Block each iteration.
@@ -238,7 +237,7 @@ _(primes) // [1, 3, 5, 7]
^ // break ^ // break
~~~ ~~~
## Bridging examples {#bridge} ## Bridging examples
Closures over private state: Closures over private state:
@@ -270,7 +269,7 @@ welcome("Ada") // "Hi, Ada!"
welcome("") // "Hi!" welcome("") // "Hi!"
~~~ ~~~
## Notes {#notes} ## Notes
- Comments use `//`. - Comments use `//`.
- Strings are `"..."`. - Strings are `"..."`.
@@ -286,24 +285,23 @@ Hi is still in active development. This page will grow with specs, a reference,
document.addEventListener('DOMContentLoaded',()=>{ document.addEventListener('DOMContentLoaded',()=>{
const $=s=>document.querySelector(s),$$=s=>[...document.querySelectorAll(s)] const $=s=>document.querySelector(s),$$=s=>[...document.querySelectorAll(s)]
const md=window.markdownit({html:false,linkify:true,typographer:true,breaks:false}) const md=window.markdownit({html:false,linkify:true,typographer:true,breaks:false})
const icons=()=>window.lucide&&lucide.createIcons()
const slug=s=>s.toLowerCase().trim().replace(/[^\w\- ]+/g,'').replace(/\s+/g,'-') const slug=s=>s.toLowerCase().trim().replace(/[^\w\- ]+/g,'').replace(/\s+/g,'-')
// Render markdown into suneHtml // Render markdown into suneHtml
const src=$('#md')?.textContent||'', html=md.render(src), root=$('#suneHtml') const root=$('#suneHtml'); root.className='markdown-body max-w-3xl mx-auto'
root.className='markdown-body max-w-3xl mx-auto'; root.innerHTML=html root.innerHTML=md.render($('#md')?.textContent||'')
// Headings: ids + anchors // Headings: ids + subtle anchor links
$$('#suneHtml h2, #suneHtml h3').forEach(h=>{ $$('#suneHtml h2, #suneHtml h3').forEach(h=>{
if(!h.id)h.id=slug(h.textContent) if(!h.id)h.id=slug((h.childNodes[0]?.nodeValue||h.textContent||'').trim())
h.classList.add('anchor') h.classList.add('anchor')
const a=document.createElement('a');a.href='#'+h.id;a.className='ml-2 text-gray-300 hover:text-gray-500 align-middle';a.innerHTML='#';h.appendChild(a) const a=document.createElement('a');a.href='#'+h.id;a.className='anchor-link';a.textContent='#';h.appendChild(a)
}) })
// Highlight + copy buttons // Highlight + copy buttons
document.querySelectorAll('#suneHtml pre>code').forEach(code=>{ document.querySelectorAll('#suneHtml pre>code').forEach(code=>{
if(window.hljs) hljs.highlightElement(code) window.hljs&&hljs.highlightElement(code)
const pre=code.parentElement, t=code.textContent||'', btn=document.createElement('button'), meta=document.createElement('span'), box=document.createElement('div') const pre=code.parentElement, t=code.textContent||'', box=document.createElement('div'), btn=document.createElement('button'), meta=document.createElement('span')
btn.className='copy-btn'; btn.textContent='Copy' btn.className='copy-btn'; btn.textContent='Copy'
btn.onclick=async e=>{e.stopPropagation();try{await navigator.clipboard.writeText(code.innerText);btn.textContent='Copied';setTimeout(()=>btn.textContent='Copy',1100)}catch{}} btn.onclick=async e=>{e.stopPropagation();try{await navigator.clipboard.writeText(code.innerText);btn.textContent='Copied';setTimeout(()=>btn.textContent='Copy',1100)}catch{}}
meta.className='char-c'; meta.textContent=(t.length>=1e3?(t.length/1e3).toFixed(1)+'K':t.length)+' chars' meta.className='char-c'; meta.textContent=(t.length>=1e3?(t.length/1e3).toFixed(1)+'K':t.length)+' chars'
@@ -311,13 +309,15 @@ document.addEventListener('DOMContentLoaded',()=>{
}) })
// Build side nav (desktop + mobile) // Build side nav (desktop + mobile)
const buildNav=(navSel)=>{ const heads=$$('#suneHtml h2,h3')
const nav=$(navSel); if(!nav)return; nav.innerHTML='' const buildNav=sel=>{
const nav=$(sel); if(!nav)return; nav.innerHTML=''
const frag=document.createDocumentFragment() const frag=document.createDocumentFragment()
$$('#suneHtml h2,h3').forEach(h=>{ heads.forEach(h=>{
const lvl=h.tagName==='H2'?0:1, a=document.createElement('a') const lvl=h.tagName==='H2'?0:1, a=document.createElement('a')
const title=(h.childNodes[0]?.nodeValue||h.textContent||'').replace(/\s*#\s*$/,'').trim()
a.href='#'+h.id; a.className=(lvl?'pl-6 ':'')+'block px-2 py-1 rounded-lg hover:bg-gray-100 text-gray-700' a.href='#'+h.id; a.className=(lvl?'pl-6 ':'')+'block px-2 py-1 rounded-lg hover:bg-gray-100 text-gray-700'
a.textContent=h.textContent.replace('#','').trim(); frag.appendChild(a) a.textContent=title; frag.appendChild(a)
}) })
nav.appendChild(frag) nav.appendChild(frag)
const links=[...nav.querySelectorAll('a')] const links=[...nav.querySelectorAll('a')]
@@ -329,12 +329,12 @@ document.addEventListener('DOMContentLoaded',()=>{
} }
}) })
},{rootMargin:'-50% 0px -40% 0px',threshold:[0,1]}) },{rootMargin:'-50% 0px -40% 0px',threshold:[0,1]})
$$('#suneHtml h2, #suneHtml h3').forEach(h=>io.observe(h)) heads.forEach(h=>io.observe(h))
links.forEach(L=>L.addEventListener('click',()=>{if(window.innerWidth<1024) setLeft(false)})) links.forEach(L=>L.addEventListener('click',()=>{if(window.innerWidth<1024) setLeft(false)}))
} }
buildNav('#sideNav'); buildNav('#sideNavMobile') buildNav('#sideNav'); buildNav('#sideNavMobile')
// Mobile sidebar controls (no Alpine) // Mobile sidebar controls
const overlay=$('#overlay'), side=$('#sidebarMobile'), menuBtn=$('#menuBtn') const overlay=$('#overlay'), side=$('#sidebarMobile'), menuBtn=$('#menuBtn')
const setLeft=v=>{ const setLeft=v=>{
overlay.classList.toggle('opacity-100',v) overlay.classList.toggle('opacity-100',v)
@@ -346,8 +346,6 @@ document.addEventListener('DOMContentLoaded',()=>{
menuBtn?.addEventListener('click',()=>setLeft(true)) menuBtn?.addEventListener('click',()=>setLeft(true))
overlay?.addEventListener('click',()=>setLeft(false)) overlay?.addEventListener('click',()=>setLeft(false))
document.addEventListener('keydown',e=>{if(e.key==='Escape')setLeft(false)}) document.addEventListener('keydown',e=>{if(e.key==='Escape')setLeft(false)})
icons()
}) })
</script> </script>
</body> </body>