for-humanity 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.7.1 — 2026-10-11
6
+
7
+ - Set Hangul in body text, labels, inline code and the site name in bundled IBM Plex Sans KR, the source of Monoplex KR's Hangul, at its natural width; Latin stays in Monoplex KR, and code blocks and flowcharts keep two-cell Hangul for the grid.
8
+ - Tighten letter spacing to -0.03em for body text, labels and inline code, -0.04em for h2 and parts and -0.045em for h1; code blocks and flowcharts stay at 0 for the grid.
9
+ - Narrow the document navigation and outline sidebars from 240px to 200px and let the body fill the rest of a page up to 1920px instead of a 900px column, keeping the 32px gaps; show the outline from 1360px so the body stays about 800px or wider.
10
+
5
11
  ## 0.7.0 — 2026-10-06
6
12
 
7
13
  - Replace Pretendard and JetBrains Mono with bundled Monoplex KR for body text, labels, code and flowcharts; align the flowchart grid to its 1:2 Latin–Hangul widths.
package/README.md CHANGED
@@ -33,7 +33,7 @@ Write Markdown. Keep the context. Share a static site.
33
33
  Node.js 22 or later and pnpm. Install the CLI in your document project:
34
34
 
35
35
  ```sh
36
- pnpm add -D --save-exact for-humanity@0.7.0
36
+ pnpm add -D --save-exact for-humanity@0.7.1
37
37
  mkdir docs
38
38
  ```
39
39
 
@@ -52,7 +52,7 @@ pnpm exec for-humanity preview docs
52
52
 
53
53
  If your Markdown files are in the project root, use `.` instead of `docs`. The root `README.md` becomes the home page; root `AGENTS.md` and `CLAUDE.md` stay out of the site.
54
54
 
55
- Version `0.7.0` supports `dev`, `build` and `preview`. `init` is planned; see the [Roadmap](https://github.com/minu-ha/for-humanity/blob/main/templates/document/roadmap.md) and [Changelog](https://github.com/minu-ha/for-humanity/blob/main/CHANGELOG.md).
55
+ Version `0.7.1` supports `dev`, `build` and `preview`. `init` is planned; see the [Roadmap](https://github.com/minu-ha/for-humanity/blob/main/templates/document/roadmap.md) and [Changelog](https://github.com/minu-ha/for-humanity/blob/main/CHANGELOG.md).
56
56
  Cloudflare Pages can host the generated site. See [Deployment](https://github.com/minu-ha/for-humanity/blob/main/templates/document/deployment.md) for the build settings.
57
57
  Set an optional public root `url` in the site configuration to generate `robots.txt` and `sitemap.xml`; projects without a URL emit neither file. See [Crawling](https://github.com/minu-ha/for-humanity/blob/main/templates/document/crawling.md).
58
58
 
@@ -75,7 +75,7 @@ pnpm preview # Preview the static site
75
75
  pnpm build:pages # Add Cloudflare Pages headers and a 404 page
76
76
  ```
77
77
 
78
- Changes pushed to `main` update the documentation site. A stable version tag such as `v0.7.0` runs checks, publishes the package to npm, then creates a GitHub Release with the same package file.
78
+ Changes pushed to `main` update the documentation site. A stable version tag such as `v0.7.1` runs checks, publishes the package to npm, then creates a GitHub Release with the same package file.
79
79
  The npm README updates with each package release. See [Maintenance](https://github.com/minu-ha/for-humanity/blob/main/templates/document/maintenance.md#packaging-and-release) for the release steps.
80
80
 
81
81
  ## Make it yours
package/dist/browser.js CHANGED
@@ -34,6 +34,6 @@ d.replaceWith(c.content)
34
34
  ${Math.max(0,Math.min(r.current.x+16,document.documentElement.clientWidth-s.width-16))}px,
35
35
  ${Math.max(0,Math.min(r.current.y+16,document.documentElement.clientHeight-s.height-16))}px,
36
36
  0
37
- )`,s.classList.add("wg_cursorFace__root--visible"))}))},c=s=>{if(!n.current?.matches||s.pointerType!=="mouse"){o();return}r.current.x=s.clientX,r.current.y=s.clientY,a()},f=()=>{t.current?.classList.contains("wg_cursorFace__root--visible")&&a()},u=()=>{if(t.current?.classList.contains("wg_cursorFace__root--visible"))try{sessionStorage.setItem(mt,JSON.stringify({x:r.current.x,y:r.current.y}))}catch{}},p=()=>{try{let s=sessionStorage.getItem(mt);if(sessionStorage.removeItem(mt),s===null||!n.current?.matches)return;let l=JSON.parse(s);typeof l=="object"&&l!==null&&"x"in l&&"y"in l&&typeof l.x=="number"&&typeof l.y=="number"&&Number.isFinite(l.x)&&Number.isFinite(l.y)&&(r.current.x=l.x,r.current.y=l.y,a())}catch{}};return I(()=>{if(!e.ready)return;let s=new AbortController,l=matchMedia("(hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference)");return n.current=l,p(),document.addEventListener("pointermove",c,{passive:!0,signal:s.signal}),document.addEventListener("pointerdown",c,{passive:!0,signal:s.signal}),document.documentElement.addEventListener("pointerleave",o,{signal:s.signal}),addEventListener("blur",o,{signal:s.signal}),addEventListener("resize",f,{signal:s.signal}),addEventListener("pagehide",u,{signal:s.signal}),addEventListener("pageshow",p,{signal:s.signal}),l.addEventListener("change",i,{signal:s.signal}),()=>{s.abort(),n.current=null,o()}},[e.ready]),g("img",{ref:e.ready?t:void 0,className:x("wg_cursorFace__root"),src:so,width:24,height:24,alt:"","aria-hidden":"true",draggable:!1,"data-cursor-face":""})};var fn="(width < 1024px)",pn="(width >= 1536px)";var uo=e=>{let t=document.querySelector("[data-navigation]"),n=document.querySelector('[data-navigation-scroll="documents"]'),r=document.querySelector('[data-navigation-scroll="outline"]');if(!(!t||!n||!r)){t.dataset.navigationLayout=e.layout;try{let o=sessionStorage.getItem(e.key),i=o===null?void 0:JSON.parse(o),a=typeof i=="object"&&i!==null&&"version"in i&&i.version===e.version&&"state"in i?e.toState(i.state):{positions:{}},c=sessionStorage.getItem(`${e.key}:${e.layout==="drawer"?"drawer":"desktop"}`),f=a.positions[e.layout]===void 0&&c!==null?e.toState({positions:{[e.layout]:JSON.parse(c)}}).positions[e.layout]:void 0,u=a.positions[e.layout]??f,p=[...t.querySelectorAll(".wg_navigationNav__root a[href]")].map(s=>`${s.pathname}:${s.textContent}`).join(`
37
+ )`,s.classList.add("wg_cursorFace__root--visible"))}))},c=s=>{if(!n.current?.matches||s.pointerType!=="mouse"){o();return}r.current.x=s.clientX,r.current.y=s.clientY,a()},f=()=>{t.current?.classList.contains("wg_cursorFace__root--visible")&&a()},u=()=>{if(t.current?.classList.contains("wg_cursorFace__root--visible"))try{sessionStorage.setItem(mt,JSON.stringify({x:r.current.x,y:r.current.y}))}catch{}},p=()=>{try{let s=sessionStorage.getItem(mt);if(sessionStorage.removeItem(mt),s===null||!n.current?.matches)return;let l=JSON.parse(s);typeof l=="object"&&l!==null&&"x"in l&&"y"in l&&typeof l.x=="number"&&typeof l.y=="number"&&Number.isFinite(l.x)&&Number.isFinite(l.y)&&(r.current.x=l.x,r.current.y=l.y,a())}catch{}};return I(()=>{if(!e.ready)return;let s=new AbortController,l=matchMedia("(hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference)");return n.current=l,p(),document.addEventListener("pointermove",c,{passive:!0,signal:s.signal}),document.addEventListener("pointerdown",c,{passive:!0,signal:s.signal}),document.documentElement.addEventListener("pointerleave",o,{signal:s.signal}),addEventListener("blur",o,{signal:s.signal}),addEventListener("resize",f,{signal:s.signal}),addEventListener("pagehide",u,{signal:s.signal}),addEventListener("pageshow",p,{signal:s.signal}),l.addEventListener("change",i,{signal:s.signal}),()=>{s.abort(),n.current=null,o()}},[e.ready]),g("img",{ref:e.ready?t:void 0,className:x("wg_cursorFace__root"),src:so,width:24,height:24,alt:"","aria-hidden":"true",draggable:!1,"data-cursor-face":""})};var fn="(width < 1024px)",pn="(width >= 1360px)";var uo=e=>{let t=document.querySelector("[data-navigation]"),n=document.querySelector('[data-navigation-scroll="documents"]'),r=document.querySelector('[data-navigation-scroll="outline"]');if(!(!t||!n||!r)){t.dataset.navigationLayout=e.layout;try{let o=sessionStorage.getItem(e.key),i=o===null?void 0:JSON.parse(o),a=typeof i=="object"&&i!==null&&"version"in i&&i.version===e.version&&"state"in i?e.toState(i.state):{positions:{}},c=sessionStorage.getItem(`${e.key}:${e.layout==="drawer"?"drawer":"desktop"}`),f=a.positions[e.layout]===void 0&&c!==null?e.toState({positions:{[e.layout]:JSON.parse(c)}}).positions[e.layout]:void 0,u=a.positions[e.layout]??f,p=[...t.querySelectorAll(".wg_navigationNav__root a[href]")].map(s=>`${s.pathname}:${s.textContent}`).join(`
38
38
  `);if(u===void 0||u.navigation!==p)return;n.scrollTop=u.documents,u.pathname===location.pathname&&(r.scrollTop=u.outline)}catch{}}};var gt=e=>{let t=[...e.group.docs.map(n=>({kind:"document",key:`doc:${n.id}`,doc:n})),...e.group.groups.map(n=>({kind:"group",key:`group:${JSON.stringify(n.path)}`,group:n}))];return g("ul",{className:x("wg_navigationNavList__root"),"aria-label":e.group.name,children:t.map(n=>g("li",{className:x("wg_navigationNavList__item"),children:[n.kind==="document"&&g(R,{children:[g("a",{className:x("wg_navigationNavList__link",{"wg_navigationNavList__link--active":n.doc.active}),href:`/${n.doc.id}/`,title:n.doc.label,"aria-current":n.doc.active?"page":void 0,children:n.doc.name}),n.doc.children.length>0&&g(gt,{group:{name:n.doc.name,path:e.group.path,docs:n.doc.children,groups:[]}})]}),n.kind==="group"&&g(R,{children:[g("span",{className:x("wg_navigationNavList__branch"),children:n.group.name}),g(gt,{group:n.group})]})]},n.key))})};var lo="Document navigation",fo="Open navigation",po="Close navigation",mo="Navigation";var dn="On this page";var mn=e=>g("nav",{className:x("wg_navigationNav__root"),"aria-label":lo,children:g("div",{className:x("wg_navigationNav__docs"),children:e.groups.map(t=>g("section",{className:x("wg_navigationNav__docGroup"),"aria-label":t.name,children:[g("div",{className:x("wg_navigationNav__group"),children:t.name}),g(gt,{group:t})]},JSON.stringify(t.path)))})});var _t=e=>{let[t,n]=O({above:!1,below:!1}),r=E(0),o=()=>{if(r.current=0,e.portRef.current===null)return;let c=e.portRef.current.scrollTop>1,f=e.portRef.current.scrollHeight-e.portRef.current.clientHeight-e.portRef.current.scrollTop>1;n(u=>u.above===c&&u.below===f?u:{above:c,below:f})},i=()=>{r.current===0&&(r.current=requestAnimationFrame(o))},a=c=>{e.onScroll?.(),i()};return I(()=>{if(!e.ready||e.portRef.current===null)return;let c=new ResizeObserver(i);c.observe(e.portRef.current),e.portRef.current.firstElementChild!==null&&c.observe(e.portRef.current.firstElementChild);let f=!0;return addEventListener("pageshow",i),e.portRef.current.isConnected?o():queueMicrotask(()=>{f&&o()}),()=>{f=!1,c.disconnect(),removeEventListener("pageshow",i),cancelAnimationFrame(r.current),r.current=0}},[e.portRef,e.ready]),I(()=>{e.ready&&e.portRef.current?.isConnected&&o()},[e.children,e.ready]),g("div",{ref:e.ready?e.portRef:void 0,className:x("wg_navigation__scroll",e.kind==="documents"&&"wg_navigation__documents",e.kind==="outline"&&"wg_navigation__headings",e.ready&&"wg_navigation__scroll--ready",e.ready&&t.above&&"wg_navigation__scroll--above",e.ready&&t.below&&"wg_navigation__scroll--below"),"data-navigation-scroll":e.kind,onClick:e.onClick,onScroll:a,children:e.children})};var vt=e=>{if(!e)return null;try{return document.getElementById(decodeURIComponent(e.slice(1)))}catch(t){if(t instanceof URIError)return null;throw t}};var ho=e=>{let[t,n]=O();return I(()=>{let o=e.groups.flatMap(f=>f.sections).flatMap(f=>[f.heading,...f.subs.map(u=>u.heading)]),i={id:0},a=()=>{i.id=0;let f=o.flatMap(u=>{let p=vt(`#${u.slug}`);return p?.checkVisibility()?[{slug:u.slug,top:p.getBoundingClientRect().top-Number.parseFloat(getComputedStyle(p).scrollMarginTop)}]:[]});n(f.findLast(u=>u.top<=1)?.slug??f[0]?.slug)},c=()=>{i.id===0&&(i.id=requestAnimationFrame(a))};return addEventListener("scroll",c,{passive:!0}),addEventListener("resize",c),addEventListener("toggle",c,!0),addEventListener("pageshow",c),document.addEventListener("DOMContentLoaded",c),document.readyState!=="loading"&&a(),()=>{cancelAnimationFrame(i.id),removeEventListener("scroll",c),removeEventListener("resize",c),removeEventListener("toggle",c,!0),removeEventListener("pageshow",c),document.removeEventListener("DOMContentLoaded",c)}},[e.groups]),g("nav",{className:x("wg_navigationToc__root"),"aria-label":dn,children:[g("div",{className:x("wg_navigationToc__label"),children:dn}),e.groups.map(r=>g("div",{className:x("wg_navigationToc__groupSection",{"wg_navigationToc__groupSection--named":r.part!==void 0}),children:[r.part!==void 0&&g("div",{className:x("wg_navigationToc__group"),children:r.part}),g("ul",{className:x("wg_navigationToc__list"),children:r.sections.map(o=>g("li",{className:x("wg_navigationToc__item"),children:[g("a",{className:x("wg_navigationToc__link",{"wg_navigationToc__link--active":o.heading.slug===t}),href:`#${o.heading.slug}`,"data-toc-link":"","aria-current":o.heading.slug===t?"location":void 0,children:o.heading.text}),o.subs.length>0&&g("ul",{className:x("wg_navigationToc__sub"),children:o.subs.map(i=>g("li",{className:x("wg_navigationToc__subItem"),children:g("a",{className:x("wg_navigationToc__subLink",{"wg_navigationToc__subLink--active":i.heading.slug===t}),href:`#${i.heading.slug}`,"data-toc-sub-link":"","aria-current":i.heading.slug===t?"location":void 0,children:i.heading.text})},i.heading.slug))})]},o.heading.slug))})]},r.sections[0].heading.slug))]})};var yt="for-humanity:navigation-scroll";var xt=e=>{let t=r=>{if(!(typeof r!="object"||r===null||!("navigation"in r)||typeof r.navigation!="string"||!("pathname"in r)||typeof r.pathname!="string"||!("documents"in r)||typeof r.documents!="number"||!Number.isFinite(r.documents)||r.documents<0||!("outline"in r)||typeof r.outline!="number"||!Number.isFinite(r.outline)||r.outline<0))return{navigation:r.navigation,pathname:r.pathname,documents:r.documents,outline:r.outline}};if(typeof e!="object"||e===null||!("positions"in e)||typeof e.positions!="object"||e.positions===null)return{positions:{}};let n={wide:t("wide"in e.positions?e.positions.wide:void 0),desktop:t("desktop"in e.positions?e.positions.desktop:void 0),drawer:t("drawer"in e.positions?e.positions.drawer:void 0)};return{positions:Object.fromEntries(Object.entries(n).filter(r=>r[1]!==void 0))}};var ge=e=>{let t=vt(e);for(let n=t?.closest("details");n;n=n.parentElement?.closest("details"))n.open=!0;return t};var go=e=>{let[t,n]=O(()=>e.stores===void 0?"desktop":matchMedia(fn).matches?"drawer":matchMedia(pn).matches?"wide":"desktop"),[r,o]=O(!1),i=E(null),a=E(null),c=E(null),f=E(null),u=E(null),p=E(null),s=E(null),l=E(null),d=E(null),m=E(null),h=E(t),_=E(null),z=E(!0),w=()=>d.current===null||m.current===null?h.current:d.current.matches?"drawer":m.current.matches?"wide":"desktop",A=()=>h.current==="drawer"?c.current:i.current,v=()=>h.current==="drawer"?f.current:a.current,$=()=>{let b=A();if(b!==null)return[...b.querySelectorAll(".wg_navigationNav__root a[href]")].map(Z=>`${Z.pathname}:${Z.textContent}`).join(`
39
39
  `)},y=()=>{let b=v();if(e.stores===void 0||b===null||u.current===null||z.current||h.current!==w()||h.current==="drawer"&&p.current?.open!==!0)return;let Z=$();if(Z===void 0)return;let j={navigation:Z,pathname:location.pathname,documents:b.scrollTop,outline:u.current.scrollTop};e.stores.scroll.setState(K=>({positions:{...K.positions,[h.current]:j}}))},P=()=>{h.current=w();let b=v(),Z=A();if(e.stores===void 0||b===null||u.current===null||Z===null||h.current==="drawer"&&p.current?.open!==!0)return;let j=$();if(j===void 0)return;let K=e.stores.scroll.getState().positions[h.current];b.scrollTop=0,u.current.scrollTop=0,K===void 0?uo({key:yt,version:1,layout:h.current,toState:xt}):K.navigation===j&&(b.scrollTop=K.documents,K.pathname===location.pathname&&(u.current.scrollTop=K.outline)),Z.dataset.navigationLayout=h.current,z.current=!1,y(),b.dispatchEvent(new Event("scroll")),u.current.dispatchEvent(new Event("scroll"))},L=b=>{p.current?.open!==!0&&(document.body.classList.remove("wg_shell__root--drawerOpen"),o(!1))},ce=()=>{y(),p.current?.close(),document.body.classList.remove("wg_shell__root--drawerOpen"),o(!1)},Q=b=>{w()!=="drawer"||p.current===null||p.current.open||(p.current.showModal(),document.body.classList.add("wg_shell__root--drawerOpen"),o(!0),P())},ze=b=>{ce()},V=b=>{b.preventDefault(),ce()},We=b=>{if(p.current===null||b.target!==p.current)return;let Z=p.current.getBoundingClientRect();(b.clientX<Z.left||b.clientX>Z.right||b.clientY<Z.top||b.clientY>Z.bottom)&&ce()},Ge=b=>{if(y(),p.current?.open!==!0||b.defaultPrevented||b.button!==0||b.metaKey||b.ctrlKey||b.shiftKey||b.altKey||!(b.target instanceof Element))return;let Z=b.target.closest("a[href]");if(!(!(Z instanceof HTMLAnchorElement)||Z.target!==""&&Z.target!=="_self"||Z.hasAttribute("download"))&&(ce(),Z.origin===location.origin&&Z.pathname===location.pathname&&Z.search===location.search&&Z.hash)){let j=ge(Z.hash);j!==null&&(j.tabIndex=-1,j.focus({preventScroll:!0}))}},ae=()=>{let b=w();b!==h.current&&(document.activeElement instanceof HTMLElement&&(_.current={navigation:document.activeElement.closest("[data-navigation]")!==null,drawer:document.activeElement===s.current||document.activeElement.closest("[data-navigation-drawer]")!==null,href:document.activeElement.getAttribute("href")}),b!=="drawer"&&ce(),z.current=!0,h.current=b,at(()=>n(b)))},yn=b=>{!b.persisted||e.stores===void 0||(z.current=!0,at(()=>e.stores?.scroll.persist.rehydrate()),ae(),P())};return I(()=>{if(e.stores!==void 0)return d.current=matchMedia(fn),m.current=matchMedia(pn),d.current.addEventListener("change",ae),m.current.addEventListener("change",ae),addEventListener("pagehide",y),addEventListener("pageshow",yn),()=>{d.current?.removeEventListener("change",ae),m.current?.removeEventListener("change",ae),d.current=null,m.current=null,removeEventListener("pagehide",y),removeEventListener("pageshow",yn),document.body.classList.remove("wg_shell__root--drawerOpen")}},[e.stores]),I(()=>{if(e.stores===void 0)return;let b=!0,Z=()=>{if(!b||(P(),_.current===null))return;let j=A();if(t==="drawer")_.current.navigation&&s.current?.focus({preventScroll:!0});else if(_.current.navigation&&j!==null){let K=_.current.href;[...j.querySelectorAll("a[href]")].find(So=>So.getAttribute("href")===K)?.focus({preventScroll:!0})}else _.current.drawer&&l.current?.focus({preventScroll:!0});_.current=null};return v()?.isConnected?Z():queueMicrotask(Z),()=>{b=!1}},[t,e.stores]),g(R,{children:[g("div",{className:x("wg_navigation__sidebar",e.stores!==void 0&&"wg_navigation__sidebar--navigationReady"),children:[g("div",{className:x("wg_navigation__brandRow"),children:[g("a",{ref:e.stores===void 0?void 0:l,className:x("wg_navigation__brand"),href:"/","aria-current":e.data.home?"page":void 0,children:e.data.title}),g("button",{ref:e.stores===void 0?void 0:s,className:x("wg_navigation__menuToggle",e.stores!==void 0&&t==="drawer"&&"wg_navigation__menuToggle--visible"),type:"button","aria-label":fo,"aria-controls":"fh-navigation-drawer","aria-expanded":String(r),"data-navigation-open":"",onClick:Q,children:g("svg",{className:x("wg_navigation__menuIcon"),viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",children:g("path",{d:"M4 6h16M4 12h16M4 18h16"})})})]}),t!=="drawer"&&g("div",{ref:e.stores===void 0?void 0:i,className:x("wg_navigation__navigation"),"data-navigation":"",children:g(_t,{portRef:a,kind:"documents",ready:e.stores!==void 0,onScroll:y,onClick:Ge,children:g(mn,{groups:e.data.groups})})})]}),g("aside",{className:x("wg_navigation__tocRail"),"data-navigation-rail":"",children:g("div",{className:x("wg_navigation__outline"),"data-navigation-outline":"",children:g(_t,{portRef:u,kind:"outline",ready:e.stores!==void 0,onScroll:y,onClick:Ge,children:e.data.outline.length>0&&g(ho,{groups:e.data.outline})})})}),g("dialog",{ref:e.stores===void 0?void 0:p,className:x("wg_navigation__drawer"),id:"fh-navigation-drawer","aria-labelledby":"fh-navigation-title","data-navigation-drawer":"",onClose:L,onCancel:V,onClick:We,children:[g("div",{className:x("wg_navigation__drawerHeader"),children:[g("h2",{className:x("wg_navigation__drawerTitle"),id:"fh-navigation-title",children:mo}),g("button",{className:x("wg_navigation__drawerClose"),type:"button","aria-label":po,"data-navigation-close":"",onClick:ze,children:g("svg",{className:x("wg_navigation__menuIcon"),viewBox:"0 0 24 24","aria-hidden":"true",focusable:"false",children:g("path",{d:"m6 6 12 12M18 6 6 18"})})})]}),g("div",{className:x("wg_navigation__drawerContent"),"data-navigation-content":"",children:t==="drawer"&&g("div",{ref:e.stores===void 0?void 0:c,className:x("wg_navigation__navigation"),"data-navigation":"",children:g(_t,{portRef:f,kind:"documents",ready:e.stores!==void 0,onScroll:y,onClick:Ge,children:g(mn,{groups:e.data.groups})})})})]})]})};var vo=e=>{let t=E(null),n=E(0),r=E(null),o=E(null),i=E(null),a=()=>{clearTimeout(n.current),n.current=0,r.current?.abort(),r.current=null,t.current?.classList.remove("wg_prose__headingText--highlighted"),t.current=null},c=m=>{m.target===document&&(clearTimeout(n.current),r.current?.abort(),r.current=null,n.current=window.setTimeout(a,3e3))},f=m=>{a(),t.current=m===null?null:m.querySelector(".wg_prose__headingText"),t.current!==null&&(t.current.classList.add("wg_prose__headingText--highlighted"),n.current=window.setTimeout(a,3e3),r.current=new AbortController,document.addEventListener("scrollend",c,{signal:r.current.signal}))},u=m=>{if(m.defaultPrevented||m.button!==0||m.metaKey||m.ctrlKey||m.shiftKey||m.altKey)return;let h=m.target instanceof Element?m.target.closest("a[href]"):null;if(h instanceof HTMLAnchorElement&&(h.target===""||h.target==="_self")&&!h.hasAttribute("download")&&h.origin===location.origin&&h.pathname===location.pathname&&h.search===location.search&&h.hash){let _=ge(h.hash);h.hash===location.hash&&f(_)}},p=()=>{let m=ge(location.hash);m?.scrollIntoView(),f(m)},s=()=>{i.current?.abort()},l=async()=>{let m=o.current,h=location.hash,_=ge(h);await document.fonts.ready,!(m===null||m.signal.aborted)&&(_!==null&&!i.current?.signal.aborted&&h===location.hash&&(_.scrollIntoView({behavior:"instant"}),f(_)),document.documentElement.style.removeProperty("scroll-behavior"))},d=()=>{ge(location.hash),document.readyState==="complete"&&l()};return I(()=>{let m=new AbortController;o.current=m,i.current=new AbortController,document.documentElement.style.scrollBehavior="auto",document.addEventListener("click",u,{signal:m.signal}),addEventListener("hashchange",p,{signal:m.signal}),addEventListener("load",l,{once:!0,signal:m.signal});for(let h of["wheel","touchmove","keydown","mousedown"])addEventListener(h,s,{once:!0,passive:!0,signal:m.signal});return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",d,{once:!0,signal:m.signal}):d(),()=>{m.abort(),o.current=null,i.current?.abort(),i.current=null,a(),document.documentElement.style.removeProperty("scroll-behavior")}},[]),nt(()=>{if(!e.reload||o.current===null)return;let m=new EventSource(io);return m.onmessage=()=>location.reload(),()=>m.close()},[e.reload]),g(R,{children:[g("div",{className:x("wg_shellControls__navigation"),children:g(go,{data:e.data,stores:e.stores})}),g(ao,{ready:e.stores!==void 0})]})};function _n(e,t){let n;try{n=e()}catch{return}return{getItem:o=>{var i;let a=f=>f===null?null:JSON.parse(f,t?.reviver),c=(i=n.getItem(o))!=null?i:null;return c instanceof Promise?c.then(a):a(c)},setItem:(o,i)=>n.setItem(o,JSON.stringify(i,t?.replacer)),removeItem:o=>n.removeItem(o)}}var gn=e=>t=>{try{let n=e(t);return n instanceof Promise?n:{then(r){return gn(r)(n)},catch(r){return this}}}catch(n){return{then(r){return this},catch(r){return gn(r)(n)}}}},us=(e,t)=>(n,r,o)=>{let i={storage:_n(()=>window.localStorage),partialize:_=>_,version:0,merge:(_,z)=>({...z,..._}),...t},a=!1,c=0,f=new Set,u=new Set,p=i.storage;if(!p)return e((..._)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(..._)},r,o);let s=()=>{let _=i.partialize({...r()});return p.setItem(i.name,{state:_,version:i.version})},l=o.setState;o.setState=(_,z)=>(l(_,z),s());let d=e((..._)=>(n(..._),s()),r,o);o.getInitialState=()=>d;let m,h=()=>{var _,z;if(!p)return;let w=++c;a=!1,f.forEach(v=>{var $;return v(($=r())!=null?$:d)});let A=((z=i.onRehydrateStorage)==null?void 0:z.call(i,(_=r())!=null?_:d))||void 0;return gn(p.getItem.bind(p))(i.name).then(v=>{if(v)if(typeof v.version=="number"&&v.version!==i.version){if(i.migrate){let $=i.migrate(v.state,v.version);return $ instanceof Promise?$.then(y=>[!0,y]):[!0,$]}console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,v.state];return[!1,void 0]}).then(v=>{var $;if(w!==c)return;let[y,P]=v;if(m=i.merge(P,($=r())!=null?$:d),n(m,!0),y)return s()}).then(()=>{w===c&&(A?.(r(),void 0),m=r(),a=!0,u.forEach(v=>v(m)))}).catch(v=>{w===c&&A?.(void 0,v)})};return o.persist={setOptions:_=>{i={...i,..._},_.storage&&(p=_.storage)},clearStorage:()=>{++c,p?.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>h(),hasHydrated:()=>a,onHydrate:_=>(f.add(_),()=>{f.delete(_)}),onFinishHydration:_=>(u.add(_),()=>{u.delete(_)})},i.skipHydration||h(),m||d},yo=us;var xo=e=>{let t,n=new Set,r=(u,p)=>{let s=typeof u=="function"?u(t):u;if(!Object.is(s,t)){let l=t;t=p??(typeof s!="object"||s===null)?s:Object.assign({},t,s),n.forEach(d=>d(t,l))}},o=()=>t,c={setState:r,getState:o,getInitialState:()=>f,subscribe:u=>(n.add(u),()=>n.delete(u))},f=t=e(r,o,c);return c},bo=(e=>e?xo(e):xo);var wo=e=>{let t=n=>({getItem:r=>n().getItem(r),setItem:(r,o)=>{try{return n().setItem(r,o)}catch{}},removeItem:r=>{try{return n().removeItem(r)}catch{}}});return{scroll:bo()(yo(()=>({positions:{}}),{name:yt,version:1,storage:_n(()=>t(e.session)),merge:n=>xt(n),migrate:()=>({positions:{}})}))}};var vn=document.querySelector("[data-shell-browser-root]"),$o=document.getElementById("fh-navigation-data");if(vn!==null&&$o!==null)try{let e=JSON.parse($o.textContent),t=Fr.parse(e),n=wo({session:()=>sessionStorage});Jn(vn).render(g(vo,{data:t,stores:n,reload:vn.hasAttribute("data-shell-reload")}))}catch(e){console.error("for-humanity browser initialization failed",e)}})();
package/dist/cli.css CHANGED
@@ -106,7 +106,7 @@
106
106
  border-radius: var(--app-radius-inline);
107
107
  background: var(--app-color-code);
108
108
  color: var(--app-color-text-strong);
109
- font-family: var(--app-font-mono);
109
+ font-family: inherit;
110
110
  font-size: 1em;
111
111
  }
112
112
  & pre {
@@ -119,6 +119,7 @@
119
119
  font-family: var(--app-font-mono);
120
120
  font-size: var(--app-font-size-detail);
121
121
  line-height: var(--app-line-height-code);
122
+ letter-spacing: 0;
122
123
  }
123
124
  & pre code {
124
125
  padding: 0;
@@ -247,6 +248,7 @@
247
248
  overflow-x: auto;
248
249
  margin: var(--app-space-block) 0;
249
250
  padding: var(--app-space-block) 0;
251
+ letter-spacing: 0;
250
252
  & svg {
251
253
  display: block;
252
254
  max-width: 100%;
@@ -656,7 +658,7 @@
656
658
  scrollbar-color: auto;
657
659
  }
658
660
  }
659
- @media (width < 1536px) {
661
+ @media (width < 1360px) {
660
662
  .wg_navigation__tocRail {
661
663
  display: none;
662
664
  }
@@ -745,7 +747,8 @@
745
747
  "Monoplex KR",
746
748
  ui-monospace,
747
749
  monospace;
748
- --app-font-brand: "Architects Daughter", var(--app-font-mono);
750
+ --app-font-body: "IBM Plex Sans KR", var(--app-font-mono);
751
+ --app-font-brand: "Architects Daughter", var(--app-font-body);
749
752
  --app-font-size-group: 11px;
750
753
  --app-font-size-detail: 12px;
751
754
  --app-font-size-dense: 12px;
@@ -763,9 +766,10 @@
763
766
  --app-line-height-tight: 1.4;
764
767
  --app-line-height-code: 1.65;
765
768
  --app-line-height-body: 1.7;
769
+ --app-letter-spacing-body: -0.03em;
766
770
  --app-letter-spacing-brand: 0;
767
- --app-letter-spacing-heading: -0.01em;
768
- --app-letter-spacing-title: -0.015em;
771
+ --app-letter-spacing-heading: -0.04em;
772
+ --app-letter-spacing-title: -0.045em;
769
773
  --app-space-inline: 6px;
770
774
  --app-space-stack: 10px;
771
775
  --app-space-block: 14px;
@@ -779,9 +783,8 @@
779
783
  --app-space-gutter: 28px;
780
784
  --app-space-column: 32px;
781
785
  --app-space-sidebar-gap: 32px;
782
- --app-size-sidebar: 240px;
783
- --app-size-main: 900px;
784
- --app-size-page: calc(var(--app-size-main) + (var(--app-size-sidebar) + var(--app-space-sidebar-gap) + var(--app-space-gutter)) * 2);
786
+ --app-size-sidebar: 200px;
787
+ --app-size-page: 1920px;
785
788
  --app-size-brand: calc(var(--app-font-size-title) * var(--app-line-height-title) + var(--app-space-page-top) + var(--app-space-group));
786
789
  --app-size-mobile-header: 56px;
787
790
  --app-size-menu-button: 44px;
@@ -830,12 +833,13 @@
830
833
  max-width: var(--app-size-page);
831
834
  margin: 0 auto;
832
835
  padding: 0 var(--app-space-gutter);
833
- grid-template: "nav main outline" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, var(--app-size-main)) calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap));
836
+ grid-template: "nav main outline" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, 1fr) calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap));
834
837
  background: var(--app-color-ground);
835
838
  color: var(--app-color-text);
836
- font-family: var(--app-font-mono);
839
+ font-family: var(--app-font-body);
837
840
  font-size: var(--app-font-size-body);
838
841
  line-height: var(--app-line-height-body);
842
+ letter-spacing: var(--app-letter-spacing-body);
839
843
  word-break: keep-all;
840
844
  overflow-wrap: break-word;
841
845
  text-wrap: pretty;
@@ -850,19 +854,17 @@
850
854
  .wg_shell__main {
851
855
  grid-area: main;
852
856
  min-width: 0;
853
- max-width: var(--app-size-main);
854
857
  border-inline: 1px solid var(--app-color-border-layout);
855
858
  padding-block: var(--app-size-brand) calc(100vh - var(--app-space-anchor));
856
859
  padding-inline: var(--app-space-column);
857
860
  }
858
- @media (width < 1536px) {
861
+ @media (width < 1360px) {
859
862
  .wg_shell__root {
860
- grid-template: "nav main ." 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, var(--app-size-main)) minmax(0, 1fr);
863
+ grid-template: "nav main" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, 1fr);
861
864
  }
862
865
  }
863
866
  @media (width < 1024px) {
864
867
  .wg_shell__root {
865
- max-width: calc(var(--app-size-main) + var(--app-space-gutter) * 2);
866
868
  grid-template: "nav" auto "main" 1fr / minmax(0, 1fr);
867
869
  }
868
870
  .wg_shell__main {
package/dist/cli.js CHANGED
@@ -67,6 +67,7 @@ var copy_error_asset = "\uC790\uC6D0\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uB2E4
67
67
 
68
68
  // src/constant/font.ts
69
69
  var font_mono_css = "src/asset/font/monoplex-kr/monoplex-kr.css";
70
+ var font_body_css = "src/asset/font/ibm-plex-sans-kr/ibm-plex-sans-kr.css";
70
71
  var font_brand_css = "src/asset/font/architects-daughter/architects-daughter.css";
71
72
  var font_display_strategy = "optional";
72
73
  var font_hash_length = 12;
@@ -342,7 +343,7 @@ import { flushSync } from "hono/jsx/dom";
342
343
 
343
344
  // src/component/widget/navigation/_constant/navigation.ts
344
345
  var navigation_mobile_query = "(width < 1024px)";
345
- var navigation_wide_query = "(width >= 1536px)";
346
+ var navigation_wide_query = "(width >= 1360px)";
346
347
 
347
348
  // src/component/widget/navigation/_function/restore-navigation-scroll.ts
348
349
  var restoreNavigationScroll = (options) => {
@@ -2055,11 +2056,18 @@ var main = async () => {
2055
2056
  }
2056
2057
  const siteConfig = parsedConfig.data;
2057
2058
  const mono = toFontCss({ css: join4(kitRoot, font_mono_css), fontDir: asset_font_dir });
2059
+ const body = toFontCss({ css: join4(kitRoot, font_body_css), fontDir: asset_font_dir });
2058
2060
  const brand = toFontCss({ css: join4(kitRoot, font_brand_css), fontDir: asset_font_dir });
2059
- const fontCss = [mono.css, brand.css].join("\n");
2061
+ const fontCss = [mono.css, body.css, brand.css].join("\n");
2060
2062
  const stylePath = toAssetPath({ path: asset_style_path, file: join4(kitRoot, "dist/cli.css") });
2061
2063
  const browserScript = readFileSync3(join4(kitRoot, "dist/browser.js"), "utf8");
2062
- const kitFiles = new Map([[stylePath, join4(kitRoot, "dist/cli.css")], [asset_favicon_path, join4(kitRoot, "src/asset/favicon.svg")], ...mono.files, ...brand.files]);
2064
+ const kitFiles = new Map([
2065
+ [stylePath, join4(kitRoot, "dist/cli.css")],
2066
+ [asset_favicon_path, join4(kitRoot, "src/asset/favicon.svg")],
2067
+ ...mono.files,
2068
+ ...body.files,
2069
+ ...brand.files
2070
+ ]);
2063
2071
  const files = new Map(kitFiles);
2064
2072
  const processor = createProcessor({ site: siteConfig, root: docsRoot, files });
2065
2073
  const [docs, home] = await Promise.all([
@@ -2071,7 +2079,7 @@ var main = async () => {
2071
2079
  const app = createApp({
2072
2080
  site: siteConfig,
2073
2081
  store,
2074
- assets: { stylePath, browserScript, fontCss, preload: [...brand.files.keys(), ...mono.files.keys()], reload: command === "dev" }
2082
+ assets: { stylePath, browserScript, fontCss, preload: [...brand.files.keys(), ...mono.files.keys(), ...body.files.keys()], reload: command === "dev" }
2075
2083
  });
2076
2084
  if (command === "build") {
2077
2085
  await rm(outDir, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "for-humanity",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Documents written for humans to read: a docs kit with a sidebar, parts, sections and flowcharts, built on Hono JSX",
5
5
  "keywords": [
6
6
  "docs",
@@ -0,0 +1,93 @@
1
+ Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+
5
+ This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,22 @@
1
+ /*
2
+ * IBM Plex Sans KR 1.003 · npm @ibm/plex-sans-kr 1.1.0 · https://github.com/IBM/plex
3
+ * 배포 WOFF2(fonts/complete/woff2/hinted) 원본 그대로 · 라이선스는 옆의 LICENSE.txt
4
+ * 본문의 한글 음절·호환 자모만 담당 · Monoplex KR 한글과 같은 글자의 원래 폭
5
+ */
6
+ @font-face {
7
+ font-family: "IBM Plex Sans KR";
8
+ font-style: normal;
9
+ font-display: swap;
10
+ font-weight: 400;
11
+ src: url(./IBMPlexSansKR-Regular.woff2) format("woff2");
12
+ unicode-range: U+3131-318E, U+AC00-D7A3;
13
+ }
14
+
15
+ @font-face {
16
+ font-family: "IBM Plex Sans KR";
17
+ font-style: normal;
18
+ font-display: swap;
19
+ font-weight: 600;
20
+ src: url(./IBMPlexSansKR-SemiBold.woff2) format("woff2");
21
+ unicode-range: U+3131-318E, U+AC00-D7A3;
22
+ }
@@ -4,6 +4,6 @@
4
4
  export const navigation_mobile_query = "(width < 1024px)";
5
5
 
6
6
  /**
7
- * 양쪽 240px 탐색·본문 900px·간격 120px와 스크롤바가 들어가는 3열 기준
7
+ * 양쪽 200px 탐색·간격 120px·최소 800px 본문과 스크롤바가 들어가는 3열 기준
8
8
  */
9
- export const navigation_wide_query = "(width >= 1536px)";
9
+ export const navigation_wide_query = "(width >= 1360px)";
@@ -242,7 +242,7 @@
242
242
  }
243
243
 
244
244
  /* 와이드 화면에서만 현재 문서 목차 표시 */
245
- @media (width < 1536px) {
245
+ @media (width < 1360px) {
246
246
  .wg_navigation__tocRail {
247
247
  display: none;
248
248
  }
@@ -135,7 +135,9 @@
135
135
  border-radius: var(--app-radius-inline);
136
136
  background: var(--app-color-code);
137
137
  color: var(--app-color-text-strong);
138
- font-family: var(--app-font-mono);
138
+
139
+ /* UA monospace 대신 부모 글꼴 · 문단은 본문 정책, 코드 블록은 pre의 고정폭·자간 0 */
140
+ font-family: inherit;
139
141
  font-size: 1em;
140
142
  }
141
143
 
@@ -150,6 +152,7 @@
150
152
  font-family: var(--app-font-mono);
151
153
  font-size: var(--app-font-size-detail);
152
154
  line-height: var(--app-line-height-code);
155
+ letter-spacing: 0;
153
156
  }
154
157
 
155
158
  & pre code {
@@ -320,6 +323,9 @@
320
323
  margin: var(--app-space-block) 0;
321
324
  padding: var(--app-space-block) 0;
322
325
 
326
+ /* 라벨 위치는 자간 0의 격자로 계산 */
327
+ letter-spacing: 0;
328
+
323
329
  /* stylelint-disable-next-line selector-disallowed-list -- 외부 렌더러 생성 SVG */
324
330
  & svg {
325
331
  display: block;
@@ -1,20 +1,18 @@
1
1
  /*
2
- * 넓은 화면은 같은 폭의 양쪽 탐색 · 좁은 화면은 문서 탐색만 표시
2
+ * 넓은 화면은 같은 폭의 양쪽 탐색 사이를 본문이 채움 · 좁은 화면은 문서 탐색만 표시
3
3
  */
4
4
  .wg_shell__root {
5
5
  display: grid;
6
6
  max-width: var(--app-size-page);
7
7
  margin: 0 auto;
8
8
  padding: 0 var(--app-space-gutter);
9
- grid-template: "nav main outline" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, var(--app-size-main)) calc(
10
- var(--app-size-sidebar) +
11
- var(--app-space-sidebar-gap)
12
- );
9
+ grid-template: "nav main outline" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, 1fr) calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap));
13
10
  background: var(--app-color-ground);
14
11
  color: var(--app-color-text);
15
- font-family: var(--app-font-mono);
12
+ font-family: var(--app-font-body);
16
13
  font-size: var(--app-font-size-body);
17
14
  line-height: var(--app-line-height-body);
15
+ letter-spacing: var(--app-letter-spacing-body);
18
16
 
19
17
  /* 한국어 낱말 단위 줄바꿈 · 긴 식별자만 예외 */
20
18
  word-break: keep-all;
@@ -35,7 +33,6 @@
35
33
  .wg_shell__main {
36
34
  grid-area: main;
37
35
  min-width: 0;
38
- max-width: var(--app-size-main);
39
36
  border-inline: 1px solid var(--app-color-border-layout);
40
37
 
41
38
  /* 문서 목록의 시작선 · 마지막 절도 읽는 선까지 이동 가능한 끝 여백 */
@@ -43,17 +40,16 @@
43
40
  padding-inline: var(--app-space-column);
44
41
  }
45
42
 
46
- /* 오른쪽 목차를 숨기는 화면에서 본문과 문서 목록의 간격 유지 */
47
- @media (width < 1536px) {
43
+ /* 본문 최소 약 800px을 남기도록 목차 숨김 · 본문이 오른쪽 여백까지 채움 */
44
+ @media (width < 1360px) {
48
45
  .wg_shell__root {
49
- grid-template: "nav main ." 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, var(--app-size-main)) minmax(0, 1fr);
46
+ grid-template: "nav main" 1fr / calc(var(--app-size-sidebar) + var(--app-space-sidebar-gap)) minmax(0, 1fr);
50
47
  }
51
48
  }
52
49
 
53
50
  /* 모바일의 브랜드·본문은 한 열 배치 */
54
51
  @media (width < 1024px) {
55
52
  .wg_shell__root {
56
- max-width: calc(var(--app-size-main) + var(--app-space-gutter) * 2);
57
53
  grid-template:
58
54
  "nav" auto
59
55
  "main" 1fr / minmax(0, 1fr);
@@ -4,10 +4,15 @@
4
4
  */
5
5
 
6
6
  /**
7
- * 본문·코드 글꼴 CSS · 패키지 기준 경로 · Regular·SemiBold 두 파일
7
+ * 본문 영문·코드·흐름도 글꼴 CSS · 패키지 기준 경로 · Regular·SemiBold 두 파일
8
8
  */
9
9
  export const font_mono_css = "src/asset/font/monoplex-kr/monoplex-kr.css";
10
10
 
11
+ /**
12
+ * 본문 한글 글꼴 CSS · IBM Plex Sans KR Regular·SemiBold · 한글 unicode-range
13
+ */
14
+ export const font_body_css = "src/asset/font/ibm-plex-sans-kr/ibm-plex-sans-kr.css";
15
+
11
16
  /**
12
17
  * 사이트 이름 글꼴 CSS · Architects Daughter Regular · 라틴 subset
13
18
  */
@@ -16,7 +16,7 @@ import {Hono} from "hono";
16
16
  import {toSSG} from "hono/ssg";
17
17
  import {asset_favicon_path, asset_font_dir, asset_media_extensions, asset_style_path} from "@/constant/asset";
18
18
  import {copy_error_config, copy_error_prefix, copy_error_unknown_command} from "@/constant/copy";
19
- import {font_brand_css, font_cache_control, font_mono_css} from "@/constant/font";
19
+ import {font_body_css, font_brand_css, font_cache_control, font_mono_css} from "@/constant/font";
20
20
  import {site_config_absent} from "@/constant/site";
21
21
  import {cli_config_file_name, cli_default_command, cli_default_docs_dir, cli_dev_port, cli_reload_delay_ms} from "@/entry/cli/_constant/cli";
22
22
  import {crawling_reserved_roots} from "@/entry/cli/_constant/crawling";
@@ -78,12 +78,19 @@ const main = async () => {
78
78
  const siteConfig = parsedConfig.data;
79
79
  // 내장 @font-face와 파일 수집 · font-family는 token.css 소유
80
80
  const mono = toFontCss({css: join(kitRoot, font_mono_css), fontDir: asset_font_dir});
81
+ const body = toFontCss({css: join(kitRoot, font_body_css), fontDir: asset_font_dir});
81
82
  const brand = toFontCss({css: join(kitRoot, font_brand_css), fontDir: asset_font_dir});
82
83
 
83
- const fontCss = [mono.css, brand.css].join("\n");
84
+ const fontCss = [mono.css, body.css, brand.css].join("\n");
84
85
  const stylePath = toAssetPath({path: asset_style_path, file: join(kitRoot, "dist/cli.css")});
85
86
  const browserScript = readFileSync(join(kitRoot, "dist/browser.js"), "utf8");
86
- const kitFiles = new Map([[stylePath, join(kitRoot, "dist/cli.css")], [asset_favicon_path, join(kitRoot, "src/asset/favicon.svg")], ...mono.files, ...brand.files]);
87
+ const kitFiles = new Map([
88
+ [stylePath, join(kitRoot, "dist/cli.css")],
89
+ [asset_favicon_path, join(kitRoot, "src/asset/favicon.svg")],
90
+ ...mono.files,
91
+ ...body.files,
92
+ ...brand.files,
93
+ ]);
87
94
  const files = new Map(kitFiles);
88
95
  const processor = createProcessor({site: siteConfig, root: docsRoot, files});
89
96
  const [docs, home] = await Promise.all([
@@ -95,7 +102,7 @@ const main = async () => {
95
102
  const app = createApp({
96
103
  site: siteConfig,
97
104
  store,
98
- assets: {stylePath, browserScript, fontCss, preload: [...brand.files.keys(), ...mono.files.keys()], reload: command === "dev"},
105
+ assets: {stylePath, browserScript, fontCss, preload: [...brand.files.keys(), ...mono.files.keys(), ...body.files.keys()], reload: command === "dev"},
99
106
  });
100
107
 
101
108
  if (command === "build") {
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * 공통 토큰의 단일 출처 · --app-종류-쓰임
3
3
  * 사용 기준: templates/document/design.md · 테마 분기는 color-scheme에 한정
4
- * 폭 기준 1536px·1024px·640px · 양쪽 탐색과 본문 배치
4
+ * 폭 기준 1360px·1024px·640px · 양쪽 탐색과 본문 배치
5
5
  */
6
6
 
7
7
  :root {
@@ -48,11 +48,13 @@
48
48
 
49
49
  /*
50
50
  * 내장 글꼴 · CLI는 @font-face와 자원 URL 생성
51
- * 본문·라벨·코드·흐름도 Monoplex KR · 사이트 이름 Architects Daughter
52
- * 영문 폭 0.528em = 흐름도 12px 격자의 6.336px · 한글은 정확히 2칸
51
+ * 본문·라벨·인라인 코드 한글 IBM Plex Sans KR·영문 Monoplex KR · 코드 블록·흐름도 Monoplex KR · 사이트 이름 Architects Daughter
52
+ * 영문 폭 0.528em = 흐름도 12px 격자의 6.336px · 코드 블록·흐름도의 한글은 정확히 2칸
53
+ * 본문 맨 앞의 IBM Plex Sans KR은 한글 unicode-range만 담당 · 영문·숫자·기호는 다음 순서의 Monoplex KR
53
54
  */
54
55
  --app-font-mono: "Monoplex KR", ui-monospace, monospace;
55
- --app-font-brand: "Architects Daughter", var(--app-font-mono);
56
+ --app-font-body: "IBM Plex Sans KR", var(--app-font-mono);
57
+ --app-font-brand: "Architects Daughter", var(--app-font-body);
56
58
 
57
59
  /* 글자 크기 · 11px 비상호작용 묶음 · 12px 기본과 역할별 제목 크기 */
58
60
  --app-font-size-group: 11px;
@@ -77,10 +79,11 @@
77
79
  --app-line-height-code: 1.65;
78
80
  --app-line-height-body: 1.7;
79
81
 
80
- /* 자간 · 사이트 이름은 기본 폭, 제목만 미세하게 조임 */
82
+ /* 자간 · 본문·라벨·인라인 코드를 조이고 제목은 그보다 조금 더 · 사이트 이름은 기본 폭 · 코드 블록·흐름도는 격자를 위해 0 */
83
+ --app-letter-spacing-body: -0.03em;
81
84
  --app-letter-spacing-brand: 0;
82
- --app-letter-spacing-heading: -0.01em;
83
- --app-letter-spacing-title: -0.015em;
85
+ --app-letter-spacing-heading: -0.04em;
86
+ --app-letter-spacing-title: -0.045em;
84
87
 
85
88
  /* 공통 간격 · margin·padding·gap의 리듬 · 단독 보정은 지역 값 */
86
89
  --app-space-inline: 6px;
@@ -100,9 +103,10 @@
100
103
  --app-space-gutter: 28px;
101
104
  --app-space-column: 32px;
102
105
  --app-space-sidebar-gap: 32px;
103
- --app-size-sidebar: 240px;
104
- --app-size-main: 900px;
105
- --app-size-page: calc(var(--app-size-main) + (var(--app-size-sidebar) + var(--app-space-sidebar-gap) + var(--app-space-gutter)) * 2);
106
+ --app-size-sidebar: 200px;
107
+
108
+ /* 페이지 최대 폭 · 본문은 사이드바·간격을 뺀 나머지 전체 */
109
+ --app-size-page: 1920px;
106
110
  --app-size-brand: calc(var(--app-font-size-title) * var(--app-line-height-title) + var(--app-space-page-top) + var(--app-space-group));
107
111
  --app-size-mobile-header: 56px;
108
112
  --app-size-menu-button: 44px;
@@ -4,11 +4,11 @@ import {tmpdir} from "node:os";
4
4
  import {join} from "node:path";
5
5
  import {test} from "node:test";
6
6
  import {asset_font_dir} from "@/constant/asset";
7
- import {font_brand_css, font_mono_css} from "@/constant/font";
7
+ import {font_body_css, font_brand_css, font_mono_css} from "@/constant/font";
8
8
  import {toFontCss} from "@/util/font/to-font-css";
9
9
 
10
10
  test("bundled fonts prevent a late swap after fallback text is visible", () => {
11
- for (const css of [font_mono_css, font_brand_css]) {
11
+ for (const css of [font_mono_css, font_body_css, font_brand_css]) {
12
12
  const result = toFontCss({css: join(process.cwd(), css), fontDir: asset_font_dir});
13
13
 
14
14
  assert.match(result.css, /font-display:\s*optional;/);