@limcpf/everything-is-a-markdown 0.4.0 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@limcpf/everything-is-a-markdown",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/build.ts CHANGED
@@ -1042,6 +1042,7 @@ function buildInitialView(doc: DocRecord, docs: DocRecord[], contentHtml: string
1042
1042
  async function writeShellPages(
1043
1043
  context: OutputWriteContext,
1044
1044
  docs: DocRecord[],
1045
+ manifest: Manifest,
1045
1046
  options: BuildOptions,
1046
1047
  runtimeAssets: RuntimeAssets,
1047
1048
  contentByDocId: Map<string, string>,
@@ -1053,6 +1054,7 @@ async function writeShellPages(
1053
1054
  buildShellMeta("/", null, options),
1054
1055
  buildAppShellAssetsForOutput(indexOutputPath, runtimeAssets),
1055
1056
  indexInitialView,
1057
+ manifest,
1056
1058
  );
1057
1059
  await writeOutputIfChanged(context, "_app/index.html", shell);
1058
1060
  await writeOutputIfChanged(context, indexOutputPath, shell);
@@ -1072,6 +1074,7 @@ async function writeShellPages(
1072
1074
  buildShellMeta(doc.route, doc, options),
1073
1075
  buildAppShellAssetsForOutput(routeOutputPath, runtimeAssets),
1074
1076
  initialView,
1077
+ manifest,
1075
1078
  ),
1076
1079
  );
1077
1080
  }
@@ -1256,7 +1259,7 @@ export async function buildSite(options: BuildOptions): Promise<BuildResult> {
1256
1259
  renderedDocs += 1;
1257
1260
  }
1258
1261
 
1259
- await writeShellPages(outputContext, docs, options, runtimeAssets, contentByDocId);
1262
+ await writeShellPages(outputContext, docs, manifest, options, runtimeAssets, contentByDocId);
1260
1263
  await writeSeoArtifacts(outputContext, docs, options);
1261
1264
 
1262
1265
  await writeCache(cachePath, nextCache);
@@ -5,8 +5,8 @@
5
5
  --latte-crust: #dce0e8;
6
6
  --latte-text: #4c4f69;
7
7
  --latte-subtext0: #6c6f85;
8
- --latte-subtext1: #5c5f77;
9
- --latte-overlay0: #9ca0b0;
8
+ --latte-subtext1: #555974;
9
+ --latte-overlay0: #5f637a;
10
10
  --latte-surface0: #ccd0da;
11
11
  --latte-surface1: #bcc0cc;
12
12
  --latte-surface2: #acb0be;
@@ -30,7 +30,7 @@
30
30
  --mocha-text: #cdd6f4;
31
31
  --mocha-subtext0: #a6adc8;
32
32
  --mocha-subtext1: #bac2de;
33
- --mocha-overlay0: #6c7086;
33
+ --mocha-overlay0: #a0a7c6;
34
34
  --mocha-surface0: #313244;
35
35
  --mocha-surface1: #45475a;
36
36
  --mocha-surface2: #585b70;
@@ -121,7 +121,7 @@ body {
121
121
  body {
122
122
  background: var(--latte-base);
123
123
  color: var(--latte-text);
124
- font-family: "Inter", "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", -apple-system, BlinkMacSystemFont, sans-serif;
124
+ font-family: "Pretendard Variable", "Pretendard", "Noto Sans KR", "Apple SD Gothic Neo", "Malgun Gothic", "Segoe UI", sans-serif;
125
125
  -webkit-font-smoothing: antialiased;
126
126
  overflow: hidden;
127
127
  }
@@ -192,11 +192,21 @@ a:hover {
192
192
  }
193
193
 
194
194
  .material-symbols-outlined {
195
+ font-family: "Material Symbols Outlined", "Material Icons", sans-serif;
196
+ font-style: normal;
197
+ font-weight: 400;
198
+ letter-spacing: normal;
199
+ text-transform: none;
200
+ white-space: nowrap;
201
+ word-wrap: normal;
202
+ direction: ltr;
203
+ font-feature-settings: "liga";
204
+ -webkit-font-feature-settings: "liga";
195
205
  display: inline-flex;
196
206
  align-items: center;
197
207
  justify-content: center;
198
- width: 1em;
199
- height: 1em;
208
+ min-width: 1em;
209
+ min-height: 1em;
200
210
  flex: 0 0 auto;
201
211
  font-size: 20px;
202
212
  line-height: 1;
@@ -571,7 +581,7 @@ a:hover {
571
581
  }
572
582
 
573
583
  .status-encoding {
574
- font-family: "JetBrains Mono", monospace;
584
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
575
585
  color: var(--latte-overlay0);
576
586
  }
577
587
 
@@ -752,7 +762,7 @@ body.mobile-toggle-left .mobile-menu-toggle {
752
762
  align-items: center;
753
763
  gap: 4px;
754
764
  font-size: 0.85rem;
755
- font-family: "JetBrains Mono", monospace;
765
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
756
766
  color: var(--latte-overlay0);
757
767
  margin-bottom: 24px;
758
768
  flex-wrap: nowrap;
@@ -818,7 +828,7 @@ body.mobile-toggle-left .mobile-menu-toggle {
818
828
  gap: 16px;
819
829
  min-height: 22px;
820
830
  font-size: 0.85rem;
821
- font-family: "JetBrains Mono", monospace;
831
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
822
832
  color: var(--latte-subtext0);
823
833
  }
824
834
 
@@ -914,7 +924,7 @@ body.mobile-toggle-left .mobile-menu-toggle {
914
924
  border: 1px solid var(--latte-surface0);
915
925
  border-radius: 4px;
916
926
  padding: 2px 6px;
917
- font-family: "JetBrains Mono", monospace;
927
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
918
928
  font-size: 0.88em;
919
929
  color: var(--latte-mauve);
920
930
  }
@@ -955,7 +965,7 @@ body.mobile-toggle-left .mobile-menu-toggle {
955
965
 
956
966
  .code-filename {
957
967
  flex: 1;
958
- font-family: "JetBrains Mono", monospace;
968
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
959
969
  font-size: 0.75rem;
960
970
  color: #aeb7c2;
961
971
  text-align: center;
@@ -1000,7 +1010,7 @@ body.mobile-toggle-left .mobile-menu-toggle {
1000
1010
  display: block;
1001
1011
  padding: 18px 20px;
1002
1012
  overflow-x: auto;
1003
- font-family: "JetBrains Mono", monospace;
1013
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1004
1014
  font-size: 0.95rem;
1005
1015
  font-weight: 500;
1006
1016
  line-height: 1.72;
@@ -1041,7 +1051,7 @@ body.mobile-toggle-left .mobile-menu-toggle {
1041
1051
  display: block;
1042
1052
  padding: 16px;
1043
1053
  overflow-x: auto;
1044
- font-family: "JetBrains Mono", monospace;
1054
+ font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1045
1055
  font-size: 0.875rem;
1046
1056
  line-height: 1.6;
1047
1057
  }
@@ -82,6 +82,37 @@ function loadInitialViewData() {
82
82
  }
83
83
  }
84
84
 
85
+ function loadInitialManifestData() {
86
+ const script = document.getElementById("initial-manifest-data");
87
+ if (!(script instanceof HTMLScriptElement)) {
88
+ return null;
89
+ }
90
+
91
+ const raw = script.textContent;
92
+ if (!raw) {
93
+ return null;
94
+ }
95
+
96
+ try {
97
+ const parsed = JSON.parse(raw);
98
+ if (!parsed || typeof parsed !== "object") {
99
+ return null;
100
+ }
101
+
102
+ if (!Array.isArray(parsed.docs) || !Array.isArray(parsed.tree)) {
103
+ return null;
104
+ }
105
+
106
+ if (!parsed.routeMap || typeof parsed.routeMap !== "object") {
107
+ return null;
108
+ }
109
+
110
+ return parsed;
111
+ } catch {
112
+ return null;
113
+ }
114
+ }
115
+
85
116
  function resolveRouteFromLocation(routeMap) {
86
117
  const direct = normalizeRoute(location.pathname);
87
118
  if (routeMap[direct]) {
@@ -1077,12 +1108,14 @@ async function start() {
1077
1108
  }
1078
1109
  });
1079
1110
 
1080
- const manifestRes = await fetch("/manifest.json");
1081
- if (!manifestRes.ok) {
1082
- throw new Error(`Failed to load manifest: ${manifestRes.status}`);
1111
+ let manifest = loadInitialManifestData();
1112
+ if (!manifest) {
1113
+ const manifestRes = await fetch("/manifest.json");
1114
+ if (!manifestRes.ok) {
1115
+ throw new Error(`Failed to load manifest: ${manifestRes.status}`);
1116
+ }
1117
+ manifest = await manifestRes.json();
1083
1118
  }
1084
-
1085
- const manifest = await manifestRes.json();
1086
1119
  const defaultBranch = normalizeBranch(manifest.defaultBranch) || DEFAULT_BRANCH;
1087
1120
  const availableBranchSet = new Set([defaultBranch]);
1088
1121
  for (const doc of manifest.docs) {
package/src/template.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { escapeHtmlAttribute } from "./seo";
2
+ import type { Manifest } from "./types";
2
3
 
3
4
  const DEFAULT_TITLE = "File-System Blog";
4
5
  const DEFAULT_DESCRIPTION = "File-system style static blog with markdown explorer UI.";
@@ -44,6 +45,8 @@ interface AppShellInitialViewPayload {
44
45
  title: string;
45
46
  }
46
47
 
48
+ interface AppShellManifestPayload extends Manifest {}
49
+
47
50
  const DEFAULT_ASSETS: AppShellAssets = {
48
51
  cssHref: "/assets/app.css",
49
52
  jsSrc: "/assets/app.js",
@@ -137,14 +140,6 @@ function renderHeadMeta(meta: AppShellMeta): string {
137
140
  return headTags.join("\n");
138
141
  }
139
142
 
140
- function renderDeferredStylesheet(href: string): string {
141
- return [
142
- ` <link rel="preload" href="${escapeHtmlAttribute(href)}" as="style" />`,
143
- ` <link rel="stylesheet" href="${escapeHtmlAttribute(href)}" media="print" onload="this.media='all'" />`,
144
- ` <noscript><link rel="stylesheet" href="${escapeHtmlAttribute(href)}" /></noscript>`,
145
- ].join("\n");
146
- }
147
-
148
143
  function renderInitialViewScript(initialView: AppShellInitialView | null): string {
149
144
  if (!initialView) {
150
145
  return "";
@@ -164,17 +159,30 @@ function renderInitialViewScript(initialView: AppShellInitialView | null): strin
164
159
  return `\n <script id="initial-view-data" type="application/json">${payload}</script>`;
165
160
  }
166
161
 
162
+ function renderInitialManifestScript(manifest: AppShellManifestPayload | null): string {
163
+ if (!manifest) {
164
+ return "";
165
+ }
166
+
167
+ const payload = JSON.stringify(manifest)
168
+ .replaceAll("<", "\\u003c")
169
+ .replaceAll("\u2028", "\\u2028")
170
+ .replaceAll("\u2029", "\\u2029");
171
+
172
+ return `\n <script id="initial-manifest-data" type="application/json">${payload}</script>`;
173
+ }
174
+
167
175
  export function renderAppShellHtml(
168
176
  meta: AppShellMeta = {},
169
177
  assets: AppShellAssets = DEFAULT_ASSETS,
170
178
  initialView: AppShellInitialView | null = null,
179
+ manifest: AppShellManifestPayload | null = null,
171
180
  ): string {
172
181
  const headMeta = renderHeadMeta(meta);
173
182
  const initialViewScript = renderInitialViewScript(initialView);
174
- const textFontStylesheet =
175
- "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Noto+Sans+KR:wght@400;500;700&display=optional";
183
+ const initialManifestScript = renderInitialManifestScript(manifest);
176
184
  const symbolFontStylesheet =
177
- "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=optional";
185
+ "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap";
178
186
  const initialTitle = initialView ? escapeHtmlAttribute(initialView.title) : "문서를 선택하세요";
179
187
  const initialBreadcrumb = initialView ? initialView.breadcrumbHtml : "";
180
188
  const initialMeta = initialView ? initialView.metaHtml : "";
@@ -191,8 +199,7 @@ export function renderAppShellHtml(
191
199
  ${headMeta}
192
200
  <link rel="preconnect" href="https://fonts.googleapis.com" />
193
201
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
194
- ${renderDeferredStylesheet(textFontStylesheet)}
195
- ${renderDeferredStylesheet(symbolFontStylesheet)}
202
+ <link rel="stylesheet" href="${escapeHtmlAttribute(symbolFontStylesheet)}" />
196
203
  <link rel="stylesheet" href="${escapeHtmlAttribute(assets.cssHref)}" />
197
204
  </head>
198
205
  <body>
@@ -298,12 +305,13 @@ ${renderDeferredStylesheet(symbolFontStylesheet)}
298
305
  <div id="viewer-meta" class="viewer-meta">${initialMeta}</div>
299
306
  </header>
300
307
  <article id="viewer-content" class="viewer-content">${initialContent}</article>
301
- <nav id="viewer-nav" class="viewer-nav">${initialNav}</nav>
308
+ <nav id="viewer-nav" class="viewer-nav" aria-label="문서 이전/다음 탐색">${initialNav}</nav>
302
309
  </div>
303
310
  </main>
304
311
  </div>
305
312
  <div id="tree-label-tooltip" class="tree-label-tooltip" role="tooltip" hidden></div>
306
313
  ${initialViewScript}
314
+ ${initialManifestScript}
307
315
  <script type="module" src="${escapeHtmlAttribute(assets.jsSrc)}"></script>
308
316
  </body>
309
317
  </html>
@@ -311,10 +319,8 @@ ${initialViewScript}
311
319
  }
312
320
 
313
321
  export function render404Html(assets: AppShellAssets = DEFAULT_ASSETS): string {
314
- const textFontStylesheet =
315
- "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Noto+Sans+KR:wght@400;500;700&display=optional";
316
322
  const symbolFontStylesheet =
317
- "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=optional";
323
+ "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap";
318
324
 
319
325
  return `<!doctype html>
320
326
  <html lang="ko">
@@ -324,8 +330,7 @@ export function render404Html(assets: AppShellAssets = DEFAULT_ASSETS): string {
324
330
  <title>404 - File-System Blog</title>
325
331
  <link rel="preconnect" href="https://fonts.googleapis.com" />
326
332
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
327
- ${renderDeferredStylesheet(textFontStylesheet)}
328
- ${renderDeferredStylesheet(symbolFontStylesheet)}
333
+ <link rel="stylesheet" href="${escapeHtmlAttribute(symbolFontStylesheet)}" />
329
334
  <link rel="stylesheet" href="${escapeHtmlAttribute(assets.cssHref)}" />
330
335
  </head>
331
336
  <body>