@dsbasko/cookbook-engine 0.1.0

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.

Potentially problematic release.


This version of @dsbasko/cookbook-engine might be problematic. Click here for more details.

Files changed (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/assets/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2 +0 -0
  4. package/assets/fonts/jetbrains-mono/JetBrainsMono-BoldItalic.woff2 +0 -0
  5. package/assets/fonts/jetbrains-mono/JetBrainsMono-Italic.woff2 +0 -0
  6. package/assets/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 +0 -0
  7. package/assets/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
  8. package/assets/fonts/jetbrains-mono/JetBrainsMono-SemiBold.woff2 +0 -0
  9. package/package.json +92 -0
  10. package/scripts/check-course-coverage.mts +32 -0
  11. package/scripts/fix-static-image-extensions.mjs +78 -0
  12. package/scripts/generate-readme-toc.mts +32 -0
  13. package/scripts/resolve-course-paths.mjs +28 -0
  14. package/scripts/sync-images.mjs +88 -0
  15. package/src/components/AppShell/AppShell.module.css +40 -0
  16. package/src/components/AppShell/AppShell.tsx +135 -0
  17. package/src/components/AppShell/index.ts +1 -0
  18. package/src/components/Callout/Callout.module.css +68 -0
  19. package/src/components/Callout/Callout.tsx +83 -0
  20. package/src/components/Callout/index.ts +1 -0
  21. package/src/components/CodeBlock/CodeBlock.module.css +68 -0
  22. package/src/components/CodeBlock/CodeBlock.tsx +65 -0
  23. package/src/components/CodeBlock/index.ts +1 -0
  24. package/src/components/GateProvider/GateProvider.tsx +207 -0
  25. package/src/components/GateProvider/index.ts +1 -0
  26. package/src/components/Header/Breadcrumbs.tsx +50 -0
  27. package/src/components/Header/Header.module.css +131 -0
  28. package/src/components/Header/Header.tsx +26 -0
  29. package/src/components/Header/HeaderLessonNav.tsx +118 -0
  30. package/src/components/Header/index.ts +1 -0
  31. package/src/components/HomePage/HomePage.module.css +538 -0
  32. package/src/components/HomePage/HomePage.tsx +295 -0
  33. package/src/components/HomePage/index.ts +1 -0
  34. package/src/components/LessonAwareLink/LessonAwareLink.module.css +12 -0
  35. package/src/components/LessonAwareLink/LessonAwareLink.tsx +86 -0
  36. package/src/components/LessonAwareLink/index.ts +1 -0
  37. package/src/components/LessonLayout/LessonLayout.module.css +35 -0
  38. package/src/components/LessonLayout/LessonLayout.tsx +18 -0
  39. package/src/components/LessonLayout/index.ts +1 -0
  40. package/src/components/LessonLockedInterstitial/LessonLockedInterstitial.module.css +367 -0
  41. package/src/components/LessonLockedInterstitial/LessonLockedInterstitial.tsx +256 -0
  42. package/src/components/LessonLockedInterstitial/index.ts +1 -0
  43. package/src/components/LessonNav/LessonNav.module.css +84 -0
  44. package/src/components/LessonNav/LessonNav.tsx +64 -0
  45. package/src/components/LessonNav/index.ts +1 -0
  46. package/src/components/LessonPageLayout/LessonPageLayout.module.css +118 -0
  47. package/src/components/LessonPageLayout/LessonPageLayout.tsx +46 -0
  48. package/src/components/LessonPageLayout/index.ts +1 -0
  49. package/src/components/LessonSideMeta/LessonSideMeta.module.css +68 -0
  50. package/src/components/LessonSideMeta/LessonSideMeta.tsx +87 -0
  51. package/src/components/LessonSideMeta/index.ts +1 -0
  52. package/src/components/ModulePage/ModulePage.module.css +693 -0
  53. package/src/components/ModulePage/ModulePage.tsx +301 -0
  54. package/src/components/ModulePage/index.ts +1 -0
  55. package/src/components/ProgramDrawer/LockIcon.tsx +19 -0
  56. package/src/components/ProgramDrawer/ProgramDrawer.module.css +563 -0
  57. package/src/components/ProgramDrawer/ProgramDrawer.tsx +481 -0
  58. package/src/components/ProgramDrawer/index.ts +1 -0
  59. package/src/components/ProgressBar/ProgressBar.module.css +46 -0
  60. package/src/components/ProgressBar/ProgressBar.tsx +45 -0
  61. package/src/components/ProgressBar/index.ts +1 -0
  62. package/src/components/ProgressModeProvider/ProgressModeProvider.tsx +87 -0
  63. package/src/components/ProgressModeProvider/index.ts +1 -0
  64. package/src/components/ReadingPrefsProvider/ReadingPrefsProvider.tsx +100 -0
  65. package/src/components/ReadingPrefsProvider/index.ts +1 -0
  66. package/src/components/ReadingProgress/ReadingProgress.module.css +19 -0
  67. package/src/components/ReadingProgress/ReadingProgress.tsx +53 -0
  68. package/src/components/ReadingProgress/index.ts +1 -0
  69. package/src/components/SettingsToggle/SettingsToggle.module.css +888 -0
  70. package/src/components/SettingsToggle/SettingsToggle.tsx +688 -0
  71. package/src/components/SettingsToggle/index.ts +1 -0
  72. package/src/components/Sidebar/Sidebar.module.css +157 -0
  73. package/src/components/Sidebar/Sidebar.tsx +63 -0
  74. package/src/components/Sidebar/icons/GitHubIcon.tsx +17 -0
  75. package/src/components/Sidebar/icons/HomeIcon.tsx +22 -0
  76. package/src/components/Sidebar/icons/LanguageIcon.tsx +24 -0
  77. package/src/components/Sidebar/icons/ProgramIcon.tsx +23 -0
  78. package/src/components/Sidebar/icons/SettingsIcon.tsx +26 -0
  79. package/src/components/Sidebar/icons/ThemeIcon.tsx +22 -0
  80. package/src/components/Sidebar/icons/index.ts +6 -0
  81. package/src/components/Sidebar/index.ts +1 -0
  82. package/src/components/ThemeProvider/ThemeProvider.tsx +68 -0
  83. package/src/components/ThemeProvider/index.ts +1 -0
  84. package/src/components/Toc/Toc.module.css +78 -0
  85. package/src/components/Toc/Toc.tsx +92 -0
  86. package/src/components/Toc/index.ts +1 -0
  87. package/src/components/TranslationBanner/TranslationBanner.module.css +32 -0
  88. package/src/components/TranslationBanner/TranslationBanner.tsx +40 -0
  89. package/src/components/TranslationBanner/index.ts +1 -0
  90. package/src/config.d.mts +12 -0
  91. package/src/config.mjs +110 -0
  92. package/src/index.ts +62 -0
  93. package/src/layout/lang.tsx +44 -0
  94. package/src/layout/root.tsx +223 -0
  95. package/src/lib/course-loader.ts +33 -0
  96. package/src/lib/course.ts +429 -0
  97. package/src/lib/coverage.ts +141 -0
  98. package/src/lib/description.ts +43 -0
  99. package/src/lib/extract-toc.ts +59 -0
  100. package/src/lib/format.ts +55 -0
  101. package/src/lib/frontier-link.ts +37 -0
  102. package/src/lib/gate-init-script.ts +40 -0
  103. package/src/lib/gate-mark-script.ts +324 -0
  104. package/src/lib/i18n.ts +474 -0
  105. package/src/lib/lang.ts +90 -0
  106. package/src/lib/lesson-gate.ts +79 -0
  107. package/src/lib/lesson.ts +66 -0
  108. package/src/lib/markdown-components.tsx +51 -0
  109. package/src/lib/markdown.ts +180 -0
  110. package/src/lib/mdx-plugins/rehype-callout.ts +80 -0
  111. package/src/lib/mdx-plugins/remark-lesson-images.ts +109 -0
  112. package/src/lib/mdx-plugins/remark-link-rewrite.ts +231 -0
  113. package/src/lib/paths.ts +36 -0
  114. package/src/lib/program-drawer.ts +8 -0
  115. package/src/lib/progress-mode.ts +69 -0
  116. package/src/lib/progress.ts +182 -0
  117. package/src/lib/reading-prefs.ts +127 -0
  118. package/src/lib/readme-toc.ts +69 -0
  119. package/src/lib/site-url.ts +33 -0
  120. package/src/lib/sitemap.ts +112 -0
  121. package/src/lib/slug.ts +15 -0
  122. package/src/lib/theme.ts +78 -0
  123. package/src/lib/use-i18n.ts +25 -0
  124. package/src/og/icon.tsx +40 -0
  125. package/src/og/opengraph-image.tsx +126 -0
  126. package/src/pages/home.tsx +66 -0
  127. package/src/pages/lesson.tsx +260 -0
  128. package/src/pages/module.tsx +80 -0
  129. package/src/pages/not-found-lang.tsx +51 -0
  130. package/src/pages/not-found-root.tsx +48 -0
  131. package/src/pages/root.tsx +44 -0
  132. package/src/seo/robots.ts +16 -0
  133. package/src/seo/sitemap.ts +10 -0
  134. package/src/styles/globals.css +139 -0
  135. package/src/styles/markdown.css +265 -0
  136. package/src/styles/reset.css +89 -0
  137. package/src/styles/tokens.css +270 -0
@@ -0,0 +1,100 @@
1
+ 'use client';
2
+
3
+ import {
4
+ createContext,
5
+ useCallback,
6
+ useContext,
7
+ useEffect,
8
+ useRef,
9
+ useState,
10
+ type ReactNode,
11
+ } from 'react';
12
+ import {
13
+ applyPrefs,
14
+ DEFAULT_PREFS,
15
+ isCodeFont,
16
+ isProseFont,
17
+ isSizeStep,
18
+ readStoredPrefs,
19
+ READING_PREFS_STORAGE_KEY,
20
+ writeStoredPrefs,
21
+ type CodeFont,
22
+ type ProseFont,
23
+ type ReadingPrefs,
24
+ type SizeStep,
25
+ } from '@/lib/reading-prefs';
26
+
27
+ type ReadingPrefsContextValue = {
28
+ prefs: ReadingPrefs;
29
+ setProseSize: (next: SizeStep) => void;
30
+ setCodeSize: (next: SizeStep) => void;
31
+ setProseFont: (next: ProseFont) => void;
32
+ setCodeFont: (next: CodeFont) => void;
33
+ };
34
+
35
+ const ReadingPrefsContext = createContext<ReadingPrefsContextValue | null>(null);
36
+
37
+ function readFromHtml(): ReadingPrefs {
38
+ if (typeof document === 'undefined') return { ...DEFAULT_PREFS };
39
+ const ds = document.documentElement.dataset;
40
+ const proseSizeRaw = ds.proseSize != null ? Number(ds.proseSize) : null;
41
+ const codeSizeRaw = ds.codeSize != null ? Number(ds.codeSize) : null;
42
+ return {
43
+ proseSize: isSizeStep(proseSizeRaw) ? proseSizeRaw : DEFAULT_PREFS.proseSize,
44
+ codeSize: isSizeStep(codeSizeRaw) ? codeSizeRaw : DEFAULT_PREFS.codeSize,
45
+ proseFont: isProseFont(ds.proseFont) ? ds.proseFont : DEFAULT_PREFS.proseFont,
46
+ codeFont: isCodeFont(ds.codeFont) ? ds.codeFont : DEFAULT_PREFS.codeFont,
47
+ };
48
+ }
49
+
50
+ export function ReadingPrefsProvider({ children }: { children: ReactNode }) {
51
+ const [prefs, setPrefs] = useState<ReadingPrefs>(DEFAULT_PREFS);
52
+ const prefsRef = useRef<ReadingPrefs>(DEFAULT_PREFS);
53
+
54
+ useEffect(() => {
55
+ const next = readFromHtml();
56
+ prefsRef.current = next;
57
+ setPrefs(next);
58
+ }, []);
59
+
60
+ useEffect(() => {
61
+ function handleStorage(event: StorageEvent) {
62
+ if (event.key !== READING_PREFS_STORAGE_KEY) return;
63
+ const next = readStoredPrefs();
64
+ prefsRef.current = next;
65
+ applyPrefs(next);
66
+ setPrefs(next);
67
+ }
68
+ window.addEventListener('storage', handleStorage);
69
+ return () => window.removeEventListener('storage', handleStorage);
70
+ }, []);
71
+
72
+ const updateField = useCallback(<K extends keyof ReadingPrefs>(key: K, value: ReadingPrefs[K]) => {
73
+ const next: ReadingPrefs = { ...prefsRef.current, [key]: value };
74
+ prefsRef.current = next;
75
+ applyPrefs(next);
76
+ writeStoredPrefs(next);
77
+ setPrefs(next);
78
+ }, []);
79
+
80
+ const setProseSize = useCallback((next: SizeStep) => updateField('proseSize', next), [updateField]);
81
+ const setCodeSize = useCallback((next: SizeStep) => updateField('codeSize', next), [updateField]);
82
+ const setProseFont = useCallback((next: ProseFont) => updateField('proseFont', next), [updateField]);
83
+ const setCodeFont = useCallback((next: CodeFont) => updateField('codeFont', next), [updateField]);
84
+
85
+ return (
86
+ <ReadingPrefsContext.Provider
87
+ value={{ prefs, setProseSize, setCodeSize, setProseFont, setCodeFont }}
88
+ >
89
+ {children}
90
+ </ReadingPrefsContext.Provider>
91
+ );
92
+ }
93
+
94
+ export function useReadingPrefs(): ReadingPrefsContextValue {
95
+ const ctx = useContext(ReadingPrefsContext);
96
+ if (!ctx) {
97
+ throw new Error('useReadingPrefs must be used inside <ReadingPrefsProvider>');
98
+ }
99
+ return ctx;
100
+ }
@@ -0,0 +1 @@
1
+ export { ReadingPrefsProvider, useReadingPrefs } from './ReadingPrefsProvider';
@@ -0,0 +1,19 @@
1
+ .bar {
2
+ position: fixed;
3
+ top: 69px;
4
+ left: 63px;
5
+ height: 4px;
6
+ background: var(--accent-main);
7
+ z-index: calc(var(--z-header) + 1);
8
+ transition: width 80ms linear;
9
+ pointer-events: none;
10
+ }
11
+
12
+ /* Mobile hides the bar entirely — the desktop header it anchors to is also
13
+ hidden on this breakpoint, and the design's mobile lesson screen leaves the
14
+ reading-progress affordance off the page. */
15
+ @media (max-width: 1023px) {
16
+ .bar {
17
+ display: none;
18
+ }
19
+ }
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import { useT } from '@/lib/use-i18n';
5
+ import styles from './ReadingProgress.module.css';
6
+
7
+ type ReadingProgressProps = {
8
+ targetSelector?: string;
9
+ };
10
+
11
+ export function ReadingProgress({
12
+ targetSelector = '[data-reading-target]',
13
+ }: ReadingProgressProps) {
14
+ const t = useT();
15
+ const [pct, setPct] = useState(0);
16
+
17
+ useEffect(() => {
18
+ const compute = () => {
19
+ const target = document.querySelector(targetSelector) as HTMLElement | null;
20
+ if (!target) {
21
+ setPct(0);
22
+ return;
23
+ }
24
+ const rect = target.getBoundingClientRect();
25
+ const height = target.scrollHeight;
26
+ const viewport = window.innerHeight;
27
+ const scrolled = -rect.top;
28
+ const maxScroll = Math.max(1, height - viewport);
29
+ const ratio = Math.max(0, Math.min(1, scrolled / maxScroll));
30
+ setPct(ratio * 100);
31
+ };
32
+
33
+ compute();
34
+ window.addEventListener('scroll', compute, { passive: true });
35
+ window.addEventListener('resize', compute);
36
+ return () => {
37
+ window.removeEventListener('scroll', compute);
38
+ window.removeEventListener('resize', compute);
39
+ };
40
+ }, [targetSelector]);
41
+
42
+ return (
43
+ <div
44
+ className={styles.bar}
45
+ style={{ width: `${pct}%` }}
46
+ role="progressbar"
47
+ aria-label={t.readingProgressLabel}
48
+ aria-valuemin={0}
49
+ aria-valuemax={100}
50
+ aria-valuenow={Math.round(pct)}
51
+ />
52
+ );
53
+ }
@@ -0,0 +1 @@
1
+ export { ReadingProgress } from './ReadingProgress';