thibaud frere commited on
Commit
fef84f3
·
1 Parent(s): fc7711a
app/.astro/astro/content.d.ts CHANGED
@@ -1,164 +0,0 @@
1
- declare module 'astro:content' {
2
- interface Render {
3
- '.mdx': Promise<{
4
- Content: import('astro').MarkdownInstance<{}>['Content'];
5
- headings: import('astro').MarkdownHeading[];
6
- remarkPluginFrontmatter: Record<string, any>;
7
- components: import('astro').MDXInstance<{}>['components'];
8
- }>;
9
- }
10
- }
11
-
12
- declare module 'astro:content' {
13
- interface RenderResult {
14
- Content: import('astro/runtime/server/index.js').AstroComponentFactory;
15
- headings: import('astro').MarkdownHeading[];
16
- remarkPluginFrontmatter: Record<string, any>;
17
- }
18
- interface Render {
19
- '.md': Promise<RenderResult>;
20
- }
21
-
22
- export interface RenderedContent {
23
- html: string;
24
- metadata?: {
25
- imagePaths: Array<string>;
26
- [key: string]: unknown;
27
- };
28
- }
29
- }
30
-
31
- declare module 'astro:content' {
32
- type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
33
-
34
- export type CollectionKey = keyof AnyEntryMap;
35
- export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
36
-
37
- export type ContentCollectionKey = keyof ContentEntryMap;
38
- export type DataCollectionKey = keyof DataEntryMap;
39
-
40
- type AllValuesOf<T> = T extends any ? T[keyof T] : never;
41
- type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
42
- ContentEntryMap[C]
43
- >['slug'];
44
-
45
- /** @deprecated Use `getEntry` instead. */
46
- export function getEntryBySlug<
47
- C extends keyof ContentEntryMap,
48
- E extends ValidContentEntrySlug<C> | (string & {}),
49
- >(
50
- collection: C,
51
- // Note that this has to accept a regular string too, for SSR
52
- entrySlug: E,
53
- ): E extends ValidContentEntrySlug<C>
54
- ? Promise<CollectionEntry<C>>
55
- : Promise<CollectionEntry<C> | undefined>;
56
-
57
- /** @deprecated Use `getEntry` instead. */
58
- export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
59
- collection: C,
60
- entryId: E,
61
- ): Promise<CollectionEntry<C>>;
62
-
63
- export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
64
- collection: C,
65
- filter?: (entry: CollectionEntry<C>) => entry is E,
66
- ): Promise<E[]>;
67
- export function getCollection<C extends keyof AnyEntryMap>(
68
- collection: C,
69
- filter?: (entry: CollectionEntry<C>) => unknown,
70
- ): Promise<CollectionEntry<C>[]>;
71
-
72
- export function getEntry<
73
- C extends keyof ContentEntryMap,
74
- E extends ValidContentEntrySlug<C> | (string & {}),
75
- >(entry: {
76
- collection: C;
77
- slug: E;
78
- }): E extends ValidContentEntrySlug<C>
79
- ? Promise<CollectionEntry<C>>
80
- : Promise<CollectionEntry<C> | undefined>;
81
- export function getEntry<
82
- C extends keyof DataEntryMap,
83
- E extends keyof DataEntryMap[C] | (string & {}),
84
- >(entry: {
85
- collection: C;
86
- id: E;
87
- }): E extends keyof DataEntryMap[C]
88
- ? Promise<DataEntryMap[C][E]>
89
- : Promise<CollectionEntry<C> | undefined>;
90
- export function getEntry<
91
- C extends keyof ContentEntryMap,
92
- E extends ValidContentEntrySlug<C> | (string & {}),
93
- >(
94
- collection: C,
95
- slug: E,
96
- ): E extends ValidContentEntrySlug<C>
97
- ? Promise<CollectionEntry<C>>
98
- : Promise<CollectionEntry<C> | undefined>;
99
- export function getEntry<
100
- C extends keyof DataEntryMap,
101
- E extends keyof DataEntryMap[C] | (string & {}),
102
- >(
103
- collection: C,
104
- id: E,
105
- ): E extends keyof DataEntryMap[C]
106
- ? Promise<DataEntryMap[C][E]>
107
- : Promise<CollectionEntry<C> | undefined>;
108
-
109
- /** Resolve an array of entry references from the same collection */
110
- export function getEntries<C extends keyof ContentEntryMap>(
111
- entries: {
112
- collection: C;
113
- slug: ValidContentEntrySlug<C>;
114
- }[],
115
- ): Promise<CollectionEntry<C>[]>;
116
- export function getEntries<C extends keyof DataEntryMap>(
117
- entries: {
118
- collection: C;
119
- id: keyof DataEntryMap[C];
120
- }[],
121
- ): Promise<CollectionEntry<C>[]>;
122
-
123
- export function render<C extends keyof AnyEntryMap>(
124
- entry: AnyEntryMap[C][string],
125
- ): Promise<RenderResult>;
126
-
127
- export function reference<C extends keyof AnyEntryMap>(
128
- collection: C,
129
- ): import('astro/zod').ZodEffects<
130
- import('astro/zod').ZodString,
131
- C extends keyof ContentEntryMap
132
- ? {
133
- collection: C;
134
- slug: ValidContentEntrySlug<C>;
135
- }
136
- : {
137
- collection: C;
138
- id: keyof DataEntryMap[C];
139
- }
140
- >;
141
- // Allow generic `string` to avoid excessive type errors in the config
142
- // if `dev` is not running to update as you edit.
143
- // Invalid collection names will be caught at build time.
144
- export function reference<C extends string>(
145
- collection: C,
146
- ): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
147
-
148
- type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
149
- type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
150
- ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
151
- >;
152
-
153
- type ContentEntryMap = {
154
-
155
- };
156
-
157
- type DataEntryMap = {
158
-
159
- };
160
-
161
- type AnyEntryMap = ContentEntryMap & DataEntryMap;
162
-
163
- export type ContentConfig = never;
164
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/astro.config.mjs CHANGED
@@ -7,13 +7,21 @@ import remarkFootnotes from 'remark-footnotes';
7
  import rehypeSlug from 'rehype-slug';
8
  import rehypeAutolinkHeadings from 'rehype-autolink-headings';
9
  import rehypeCitation from 'rehype-citation';
10
- import rehypePrettyCode from 'rehype-pretty-code';
11
 
12
  export default defineConfig({
13
  output: 'static',
14
  integrations: [mdx()]
15
  ,
16
  markdown: {
 
 
 
 
 
 
 
 
17
  remarkPlugins: [
18
  [remarkToc, { heading: 'Table of Contents', maxDepth: 3 }],
19
  remarkMath,
@@ -23,14 +31,6 @@ export default defineConfig({
23
  rehypeSlug,
24
  [rehypeAutolinkHeadings, { behavior: 'wrap' }],
25
  rehypeKatex,
26
- [rehypePrettyCode, {
27
- theme: {
28
- light: 'github-light',
29
- dark: 'github-dark'
30
- },
31
- keepBackground: false,
32
- defaultLang: 'text'
33
- }],
34
  [rehypeCitation, {
35
  bibliography: 'src/content/bibliography.bib',
36
  linkCitations: true
 
7
  import rehypeSlug from 'rehype-slug';
8
  import rehypeAutolinkHeadings from 'rehype-autolink-headings';
9
  import rehypeCitation from 'rehype-citation';
10
+ // Shiki intégré (dual themes) — pas de rehype-pretty-code
11
 
12
  export default defineConfig({
13
  output: 'static',
14
  integrations: [mdx()]
15
  ,
16
  markdown: {
17
+ shikiConfig: {
18
+ themes: {
19
+ light: 'github-light',
20
+ dark: 'github-dark'
21
+ },
22
+ defaultColor: false,
23
+ wrap: true
24
+ },
25
  remarkPlugins: [
26
  [remarkToc, { heading: 'Table of Contents', maxDepth: 3 }],
27
  remarkMath,
 
31
  rehypeSlug,
32
  [rehypeAutolinkHeadings, { behavior: 'wrap' }],
33
  rehypeKatex,
 
 
 
 
 
 
 
 
34
  [rehypeCitation, {
35
  bibliography: 'src/content/bibliography.bib',
36
  linkCitations: true
app/src/components/FullBleed.astro ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ const { class: className, ...props } = Astro.props;
3
+ const wrapperClass = ["full-bleed", className].filter(Boolean).join(" ");
4
+ ---
5
+ <div class={wrapperClass} {...props}>
6
+ <slot />
7
+ </div>
8
+
9
+
app/src/components/ThemeToggle.astro CHANGED
@@ -15,7 +15,7 @@ import moonIconUrl from "../assets/images/moon.svg?url";
15
  document.documentElement.dataset.theme = mode;
16
  };
17
 
18
- // Initial mode: localStorage overrides system preference
19
  apply(saved || (prefersDark ? 'dark' : 'light'));
20
 
21
  // If user hasn't chosen manually, follow system changes
 
15
  document.documentElement.dataset.theme = mode;
16
  };
17
 
18
+ // Initial mode: default to light, then use localStorage, else system
19
  apply(saved || (prefersDark ? 'dark' : 'light'));
20
 
21
  // If user hasn't chosen manually, follow system changes
app/src/components/Wide.astro ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ const { class: className, ...props } = Astro.props;
3
+ const wrapperClass = ["wide", className].filter(Boolean).join(" ");
4
+ ---
5
+ <div class={wrapperClass} {...props}>
6
+ <slot />
7
+ </div>
8
+
9
+
app/src/pages/article.mdx CHANGED
@@ -14,28 +14,31 @@ ogImage: "https://example.com/your-og-image.png"
14
  ---
15
 
16
  import HtmlFragment from "../components/HtmlFragment.astro";
 
 
17
  import { Image } from 'astro:assets';
18
  import placeholder from "../assets/images/placeholder.jpg";
19
  import audioDemo from "../assets/audio/audio-example.wav";
20
  import Aside from "../components/Aside.astro";
21
  import visualPoster from "../assets/images/visual-vocabulary-poster.png";
22
 
23
-
24
  <Aside>
25
- Welcome to this single-page research article template built with Astro and MDX.
26
- It’s designed to help you write clear, modern, and interactive technical articles with minimal setup.
27
  Whether you cover machine learning, data science, physics, or software topics, this template keeps the authoring flow simple while offering robust features out of the box.
28
  <Fragment slot="aside">
29
  Reading time: 10–15 minutes.
30
  </Fragment>
31
  In this guide, you’ll learn how to install the template,
32
  write content (math, citations, images, code, asides, interactive fragments),
33
- customize styles and behavior, and follow a few best practices for publishing.
34
  <Fragment slot="aside">
35
  If you have questions or remarks open a discussion on the <a href="https://huggingface.co/spaces/tfrere/science-blog-template/discussions?status=open&type=discussion">Community tab</a>!
36
  </Fragment>
37
  </Aside>
38
 
 
 
39
  ## Features
40
 
41
  <div className="tag-list">
@@ -55,32 +58,60 @@ import visualPoster from "../assets/images/visual-vocabulary-poster.png";
55
 
56
  ## Getting Started
57
 
58
- Installation:
59
 
60
  ```bash
 
 
 
61
  npm install
 
 
 
 
 
 
62
  npm run dev
63
  ```
64
 
65
- Build for production:
66
 
67
  ```bash
68
  npm run build
69
  ```
70
 
71
- Deployment: serve the `dist/` directory on any static host. A Docker/Nginx setup is included and works well on Spaces or similar environments.
 
 
 
 
 
 
 
 
72
 
73
- Large assets: track binaries (e.g., `.png`, `.wav`) with Git LFS to keep the repository lean. This project is preconfigured to store such files via LFS.
74
 
75
  ## Writing Your Content
76
 
77
- Author content in MDX. Below are minimal examples for the core elements.
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- ### MDX: frontmatter and imports (minimal example)
80
 
81
  The initial skeleton of this article looks like this:
82
 
83
  ```mdx
 
84
  ---
85
  title: "The science template:\nCraft Beautiful Blogs"
86
  description: "A modern, MDX-first research article template with math, citations, and interactive figures."
@@ -96,14 +127,14 @@ tags:
96
  ogImage: "https://example.com/your-og-image.png"
97
  ---
98
 
99
- import HtmlFragment from "../components/HtmlFragment.astro";
100
  import { Image } from 'astro:assets';
 
 
101
  import placeholder from "../assets/images/placeholder.png";
102
  import audioDemo from "../assets/audio/audio-example.wav";
103
- import Aside from "../components/Aside.astro";
104
- import visualPoster from "../assets/images/visual-vocabulary-poster.png";
105
-
106
 
 
107
  <Aside>
108
  Welcome to this single-page research article template built with Astro and MDX.
109
  It’s designed to help you write clear, modern, and interactive technical articles with minimal setup.
@@ -122,20 +153,40 @@ import visualPoster from "../assets/images/visual-vocabulary-poster.png";
122
 
123
  ```
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  ### Math
126
 
127
  Inline example: $x^2 + y^2 = z^2$.
128
 
129
- Block (scaled dot-product attention):
130
 
131
  $$
132
- \mathrm{Attention}(Q, K, V) = \mathrm{softmax}\!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right) V
133
  $$
134
 
135
  ```mdx
136
- Inline: $x^2 + y^2 = z^2$
137
 
138
- Block:
139
  $$
140
  \mathrm{Attention}(Q,K,V)=\mathrm{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V
141
  $$
@@ -147,6 +198,8 @@ Responsive images automatically generate an optimized `srcset` and `sizes` so th
147
 
148
  **Optional:** Zoomable (Medium-like lightbox): add `data-zoomable` to opt-in. Only images with this attribute will open full-screen on click.
149
 
 
 
150
  <figure>
151
  <Image
152
  src={placeholder}
@@ -199,35 +252,6 @@ greet("Astro")
199
  ```
200
  ````
201
 
202
-
203
- ### GitHub code embeds
204
-
205
- Finally, if you want to include code from GitHub you can use emgithub.com and, for example, create a collapsible widget like this:
206
-
207
- ```html
208
- <details style="background: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; margin: 1em 0;">
209
- <summary style="padding: 12px; cursor: pointer; user-select: none; background: #f3f4f6; border-bottom: 1px solid #d0d7de;">
210
- 👉 Naive DP implementation with overlap in Picotron (Click to expand)
211
- </summary>
212
- <div class="code-embed-container" style="margin: 0; border-radius: 0; overflow-x: scroll; width: max-content; min-width: 100%; font-size: 8px;"></div>
213
- <script
214
- src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Fhuggingface%2Fpicotron%2Fblob%2F0035cce0e04afd6192763b11efe50010d8ad0f71%2Fpicotron%2Fdata_parallel%2Fdata_parallel.py%23L10-L60&style=github&type=code&showBorder=off&showLineNumbers=on&showFileMeta=on&showCopy=on&showFullPath=on">
215
- </script>
216
- </details>
217
- ```
218
-
219
- Which will display as follows:
220
-
221
- <details style="background: #f6f8fa; border: 1px solid #d0d7de; border-radius: 6px; margin: 1em 0;">
222
- <summary style="padding: 12px; cursor: pointer; user-select: none; background: #f3f4f6; border-bottom: 1px solid #d0d7de;">
223
- 👉 Naive DP implementation with overlap in Picotron (Click to expand)
224
- </summary>
225
- <div class="code-embed-container" style="margin: 0; border-radius: 0; overflow-x: scroll; width: max-content; min-width: 100%; font-size: 8px;"></div>
226
- <script
227
- src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Fhuggingface%2Fpicotron%2Fblob%2F0035cce0e04afd6192763b11efe50010d8ad0f71%2Fpicotron%2Fdata_parallel%2Fdata_parallel.py%23L10-L60&style=github&type=code&showBorder=off&showLineNumbers=on&showFileMeta=on&showCopy=on&showFullPath=on">
228
- </script>
229
- </details>
230
-
231
  ### Citations and notes
232
 
233
  Here are a few variations using the same bibliography:
@@ -251,20 +275,6 @@ Here are a few variations using the same bibliography:
251
  ```
252
 
253
 
254
- ### Interactive fragments
255
-
256
- Plotly example (line):
257
-
258
- <div className="plot-card">
259
- <HtmlFragment src="line.html" />
260
- </div>
261
-
262
- ```mdx
263
- import HtmlFragment from '../components/HtmlFragment.astro'
264
-
265
- <HtmlFragment src="line.html" />
266
- ```
267
-
268
  ### Asides
269
 
270
  <Aside>
@@ -283,6 +293,39 @@ import Aside from '../components/Aside.astro'
283
  </Aside>
284
  ```
285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  ### Minimal table
287
 
288
  | Method | Score |
@@ -311,20 +354,52 @@ import audioDemo from '../assets/audio/audio-example.wav'
311
  </audio>
312
  ```
313
 
314
- ### Tracking training metrics with TrackIO
315
 
316
- TrackIO is a lightweight dashboard to monitor ML experiments. The embed below opens a demo project and shows a couple of metrics. You can customize the query parameters (`project`, `metrics`, `sidebar`) to fit your setup.
317
 
318
- <div style="margin-top: 8px;">
319
- <iframe src="https://trackio-documentation.hf.space/?project=fake-training-750735&metrics=train_loss,train_accuracy&sidebar=hidden" width="100%" height="600" frameborder="0"></iframe>
 
 
 
 
 
 
 
320
  </div>
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  To embed TrackIO in your own page, copy the following HTML and adjust the `src` parameters:
323
 
 
 
 
 
 
 
 
 
 
 
324
  ```html
325
- <iframe src="https://org_name-space_name.hf.space/?project=fake-training&metrics=train_loss,train_accuracy&sidebar=hidden" width="100%" height="600" frameBorder="0"></iframe>
 
 
 
326
  ```
327
 
 
328
  ## Best Practices
329
 
330
  - Keep sections short and focused.
 
14
  ---
15
 
16
  import HtmlFragment from "../components/HtmlFragment.astro";
17
+ import Wide from "../components/Wide.astro";
18
+ import FullBleed from "../components/FullBleed.astro";
19
  import { Image } from 'astro:assets';
20
  import placeholder from "../assets/images/placeholder.jpg";
21
  import audioDemo from "../assets/audio/audio-example.wav";
22
  import Aside from "../components/Aside.astro";
23
  import visualPoster from "../assets/images/visual-vocabulary-poster.png";
24
 
 
25
  <Aside>
26
+ Welcome to this single-page research article template built with **Astro** and **MDX**.
27
+ It’s designed to help you write clear, modern, and **interactive** technical articles with **minimal setup**.
28
  Whether you cover machine learning, data science, physics, or software topics, this template keeps the authoring flow simple while offering robust features out of the box.
29
  <Fragment slot="aside">
30
  Reading time: 10–15 minutes.
31
  </Fragment>
32
  In this guide, you’ll learn how to install the template,
33
  write content (math, citations, images, code, asides, interactive fragments),
34
+ customize styles and behavior, and follow a few **best practices** for publishing.
35
  <Fragment slot="aside">
36
  If you have questions or remarks open a discussion on the <a href="https://huggingface.co/spaces/tfrere/science-blog-template/discussions?status=open&type=discussion">Community tab</a>!
37
  </Fragment>
38
  </Aside>
39
 
40
+ Ce template est heavely inspired by distill.
41
+
42
  ## Features
43
 
44
  <div className="tag-list">
 
58
 
59
  ## Getting Started
60
 
61
+ ### Installation
62
 
63
  ```bash
64
+ git lfs install
65
+ git lfs pull
66
+ cd app
67
  npm install
68
+ ```
69
+
70
+
71
+ ### Development
72
+
73
+ ```bash
74
  npm run dev
75
  ```
76
 
77
+ ### Build
78
 
79
  ```bash
80
  npm run build
81
  ```
82
 
83
+ Serving the `dist/` directory on any static host is enough to deliver the site.
84
+
85
+ ### Deploy
86
+
87
+ The easiest way to get online is to clone [this Hugging Face Space](https://huggingface.co/spaces/tfrere/science-blog-template) and push your changes; every push triggers an automatic build and deploy.
88
+
89
+ ### Large files (Git LFS)
90
+
91
+ Track binaries (e.g., `.png`, `.wav`) with Git LFS to keep the repository lean. This project is preconfigured to store such files via LFS.
92
 
 
93
 
94
  ## Writing Your Content
95
 
96
+ ### MDX
97
+
98
+ Author your content in MDX for a pleasant, productive writing flow that combines familiar Markdown with reusable components when needed.
99
+ Below are minimal examples of the core elements.
100
+
101
+
102
+ Don't forget to enable syntax highlighting for MDX to make your editing experience even smoother!
103
+
104
+ ```bash
105
+ # For VS Code but alternatively, use the Extensions marketplace UI and search for "MDX" by unifiedjs.
106
+ code --install-extension unifiedjs.vscode-mdx
107
+ ```
108
+
109
 
 
110
 
111
  The initial skeleton of this article looks like this:
112
 
113
  ```mdx
114
+ {/* HEADER */}
115
  ---
116
  title: "The science template:\nCraft Beautiful Blogs"
117
  description: "A modern, MDX-first research article template with math, citations, and interactive figures."
 
127
  ogImage: "https://example.com/your-og-image.png"
128
  ---
129
 
130
+ {/* IMPORTS */}
131
  import { Image } from 'astro:assets';
132
+ import Aside from "../components/Aside.astro";
133
+ import HtmlFragment from "../components/HtmlFragment.astro";
134
  import placeholder from "../assets/images/placeholder.png";
135
  import audioDemo from "../assets/audio/audio-example.wav";
 
 
 
136
 
137
+ {/* CONTENT */}
138
  <Aside>
139
  Welcome to this single-page research article template built with Astro and MDX.
140
  It’s designed to help you write clear, modern, and interactive technical articles with minimal setup.
 
153
 
154
  ```
155
 
156
+ It is composed of three parts:
157
+
158
+ - **Header**: which contains the title and the article's metadata.
159
+ - **Imports**: the imports of the different modules / images used in the article
160
+ - **Content**: the content of the article
161
+
162
+ **Available blocs**:
163
+
164
+ <div className="tag-list">
165
+ <a className="tag" href="#math">Math</a>
166
+ <a className="tag" href="#images">Images</a>
167
+ <a className="tag" href="#code-blocks">Code</a>
168
+ <a className="tag" href="#citations-and-notes">Citations & notes</a>
169
+ <a className="tag" href="#asides">Asides</a>
170
+ <a className="tag" href="#minimal-table">Array</a>
171
+ <a className="tag" href="#audio">Audio</a>
172
+ <a className="tag" href="#interactive-fragments">Interactive fragments</a>
173
+ <a className="tag" href="#tracking-training-metrics-with-trackio">TrackIO</a>
174
+ </div>
175
+
176
  ### Math
177
 
178
  Inline example: $x^2 + y^2 = z^2$.
179
 
180
+ Block example:
181
 
182
  $$
183
+ x^2 + y^2 = z^2
184
  $$
185
 
186
  ```mdx
187
+ Inline example: $x^2 + y^2 = z^2$
188
 
189
+ Block example:
190
  $$
191
  \mathrm{Attention}(Q,K,V)=\mathrm{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V
192
  $$
 
198
 
199
  **Optional:** Zoomable (Medium-like lightbox): add `data-zoomable` to opt-in. Only images with this attribute will open full-screen on click.
200
 
201
+ **Optional:** Figcaption and credits
202
+
203
  <figure>
204
  <Image
205
  src={placeholder}
 
252
  ```
253
  ````
254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  ### Citations and notes
256
 
257
  Here are a few variations using the same bibliography:
 
275
  ```
276
 
277
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  ### Asides
279
 
280
  <Aside>
 
293
  </Aside>
294
  ```
295
 
296
+ ### Width helpers
297
+
298
+ Use these helpers to expand content beyond the main column when needed. They will always be centered and displayed above every other content.
299
+
300
+ **Wide example**
301
+
302
+ <Wide>
303
+ <div className="demo-wide">demo wide</div>
304
+ </Wide>
305
+
306
+ ```mdx
307
+ import Wide from '../components/Wide.astro'
308
+
309
+ <Wide>
310
+ Your content here...
311
+ </Wide>
312
+ ```
313
+
314
+ **Full-bleed example**
315
+
316
+ <FullBleed>
317
+ <div className="demo-full-bleed">demo full-bleed</div>
318
+ </FullBleed>
319
+
320
+ ```mdx
321
+ import FullBleed from '../components/FullBleed.astro'
322
+
323
+ <FullBleed>
324
+ Your content here...
325
+ </FullBleed>
326
+ ```
327
+
328
+
329
  ### Minimal table
330
 
331
  | Method | Score |
 
354
  </audio>
355
  ```
356
 
 
357
 
 
358
 
359
+ ### Embeds
360
+
361
+
362
+ #### HtmlFragments
363
+
364
+ The main purpose of the ```HtmlFragment``` component is to embed a plotly or d3 chart in your article. Libraries are already imported in the template.
365
+
366
+ <div className="plot-card">
367
+ <HtmlFragment src="line.html" />
368
  </div>
369
 
370
+ ```mdx
371
+ import HtmlFragment from '../components/HtmlFragment.astro'
372
+
373
+ <HtmlFragment src="line.html" />
374
+
375
+ ```
376
+
377
+ #### Iframes
378
+
379
+ You can embed external content in your article using **iframes**. For example, TrackIO—a lightweight dashboard to monitor machine learning experiments—can be used this way. The example below opens a demo project and displays a couple of metrics. You can customize the query parameters (`project`, `metrics`, `sidebar`, etc.) to fit your needs.
380
+
381
+ <iframe className="plot-card" src="https://trackio-documentation.hf.space/?project=fake-training-750735&metrics=train_loss,train_accuracy&sidebar=hidden&lang=en" width="100%" height="600" frameborder="0"></iframe>
382
+
383
  To embed TrackIO in your own page, copy the following HTML and adjust the `src` parameters:
384
 
385
+ #### GitHub code embeds
386
+
387
+ Finally, if you want to include code from GitHub you can use emgithub.com and, for example, create a collapsible widget like this:
388
+
389
+
390
+ <div class="code-embed-container"></div>
391
+ <script
392
+ src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Fhuggingface%2Fpicotron%2Fblob%2F0035cce0e04afd6192763b11efe50010d8ad0f71%2Fpicotron%2Fdata_parallel%2Fdata_parallel.py%23L10-L60&style=github&type=code&showBorder=off&showLineNumbers=on&showFileMeta=on&showCopy=on&showFullPath=on">
393
+ </script>
394
+
395
  ```html
396
+ <div class="code-embed-container"></div>
397
+ <script
398
+ src="https://emgithub.com/embed-v2.js?target=https%3A%2F%2Fgithub.com%2Fhuggingface%2Fpicotron%2Fblob%2F0035cce0e04afd6192763b11efe50010d8ad0f71%2Fpicotron%2Fdata_parallel%2Fdata_parallel.py%23L10-L60&style=github&type=code&showBorder=off&showLineNumbers=on&showFileMeta=on&showCopy=on&showFullPath=on">
399
+ </script>
400
  ```
401
 
402
+
403
  ## Best Practices
404
 
405
  - Keep sections short and focused.
app/src/pages/index.astro CHANGED
@@ -48,12 +48,23 @@ const keyTitle = titleFlat.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_
48
  const bibKey = `${keyAuthor}${year ?? ''}_${keyTitle}`;
49
  const bibtex = `@misc{${bibKey},\n title={${titleFlat}},\n author={${authorsBib}},\n ${year ? `year={${year}}` : ''}\n}`;
50
  ---
51
- <html lang="en">
52
  <head>
53
  <meta charset="utf-8" />
54
  <meta name="viewport" content="width=device-width, initial-scale=1" />
55
  <title>{docTitle}</title>
56
  <SeoHead title={docTitle} description={description} authors={authors} published={published} tags={tags} image={imageAbs} />
 
 
 
 
 
 
 
 
 
 
 
57
 
58
  <script src="https://cdn.plot.ly/plotly-3.0.0.min.js" charset="utf-8"></script>
59
  </head>
@@ -154,6 +165,8 @@ const bibtex = `@misc{${bibKey},\n title={${titleFlat}},\n author={${authorsBi
154
  else window.addEventListener('load', bootstrap, { once: true });
155
  })();
156
  </script>
 
 
157
  <script>
158
  // Open external links in a new tab; keep internal anchors in-page
159
  const setExternalTargets = () => {
 
48
  const bibKey = `${keyAuthor}${year ?? ''}_${keyTitle}`;
49
  const bibtex = `@misc{${bibKey},\n title={${titleFlat}},\n author={${authorsBib}},\n ${year ? `year={${year}}` : ''}\n}`;
50
  ---
51
+ <html lang="en" data-theme="light">
52
  <head>
53
  <meta charset="utf-8" />
54
  <meta name="viewport" content="width=device-width, initial-scale=1" />
55
  <title>{docTitle}</title>
56
  <SeoHead title={docTitle} description={description} authors={authors} published={published} tags={tags} image={imageAbs} />
57
+ <script is:inline>
58
+ (() => {
59
+ try {
60
+ const saved = localStorage.getItem('theme');
61
+ const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
62
+ const theme = saved || (prefersDark ? 'dark' : 'light');
63
+ document.documentElement.setAttribute('data-theme', theme);
64
+ } catch {}
65
+ })();
66
+ </script>
67
+
68
 
69
  <script src="https://cdn.plot.ly/plotly-3.0.0.min.js" charset="utf-8"></script>
70
  </head>
 
165
  else window.addEventListener('load', bootstrap, { once: true });
166
  })();
167
  </script>
168
+
169
+
170
  <script>
171
  // Open external links in a new tab; keep internal anchors in-page
172
  const setExternalTargets = () => {
app/src/styles/{components/_base.scss → _base.scss} RENAMED
@@ -22,7 +22,7 @@ html { font-size: 14px; line-height: 1.6; }
22
  font-weight: 600;
23
  font-size: clamp(22px, 2.6vw, 32px);
24
  line-height: 1.2;
25
- margin: var(--spacing-5) 0 var(--spacing-3);
26
  padding-bottom: var(--spacing-2);
27
  border-bottom: 1px solid var(--border-color);
28
  }
@@ -31,7 +31,7 @@ html { font-size: 14px; line-height: 1.6; }
31
  font-weight: 700;
32
  font-size: clamp(18px, 2.1vw, 22px);
33
  line-height: 1.25;
34
- margin: var(--spacing-4) 0 var(--spacing-2);
35
  }
36
 
37
  .content-grid main h4 {
@@ -39,7 +39,7 @@ html { font-size: 14px; line-height: 1.6; }
39
  text-transform: uppercase;
40
  font-size: 14px;
41
  line-height: 1.2;
42
- margin: var(--spacing-3) 0 var(--spacing-2);
43
  }
44
 
45
  .content-grid main a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--link-underline); }
@@ -66,8 +66,53 @@ html { font-size: 14px; line-height: 1.6; }
66
  margin: var(--spacing-4) 0;
67
  }
68
 
69
- .content-grid main pre { background: var(--code-bg); border: 1px solid var(--border-color); border-radius: 6px; padding: var(--spacing-3); font-size: 14px; overflow: auto; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  .content-grid main code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  /* Pretty-code language label (visible chip at top-right) */
73
  .content-grid main pre:has(code[data-language]),
@@ -112,7 +157,14 @@ html { font-size: 14px; line-height: 1.6; }
112
  .content-grid main hr { border: none; border-bottom: 1px solid var(--border-color); margin: var(--spacing-5) 0; }
113
 
114
 
115
-
 
 
 
 
 
 
 
116
 
117
  // ============================================================================
118
  // Media / Figures
 
22
  font-weight: 600;
23
  font-size: clamp(22px, 2.6vw, 32px);
24
  line-height: 1.2;
25
+ margin: var(--spacing-10) 0 var(--spacing-5);
26
  padding-bottom: var(--spacing-2);
27
  border-bottom: 1px solid var(--border-color);
28
  }
 
31
  font-weight: 700;
32
  font-size: clamp(18px, 2.1vw, 22px);
33
  line-height: 1.25;
34
+ margin: var(--spacing-8) 0 var(--spacing-4);
35
  }
36
 
37
  .content-grid main h4 {
 
39
  text-transform: uppercase;
40
  font-size: 14px;
41
  line-height: 1.2;
42
+ margin: var(--spacing-8) 0 var(--spacing-4);
43
  }
44
 
45
  .content-grid main a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--link-underline); }
 
66
  margin: var(--spacing-4) 0;
67
  }
68
 
69
+ .content-grid main pre:not(.astro-code) { background: var(--code-bg); border: 1px solid var(--border-color); border-radius: 6px; padding: var(--spacing-3); font-size: 14px; overflow: auto; }
70
+
71
+ /* Sync Shiki variables with current theme */
72
+ /* Standard wrapper look for code blocks */
73
+ .astro-code { border: 1px solid var(--border-color); border-radius: 6px; padding: var(--spacing-3); padding-left: calc(var(--spacing-3) + 6px); font-size: 14px; }
74
+
75
+ html[data-theme='light'] .astro-code { background-color: var(--code-bg); }
76
+
77
+ html[data-theme='dark'] .astro-code { background-color: var(--shiki-dark-bg); }
78
+
79
+ /* Apply token color from per-span vars exposed by Shiki dual themes */
80
+ html[data-theme='light'] .astro-code span { color: var(--shiki-light) !important; }
81
+ html[data-theme='dark'] .astro-code span { color: var(--shiki-dark) !important; }
82
+
83
+ /* Token color remapping using Shiki CSS variables on the wrapper */
84
+ /* Optionnel: booster le contraste light */
85
+ html[data-theme='light'] .astro-code {
86
+ --shiki-foreground: #24292f;
87
+ --shiki-background: #ffffff;
88
+ }
89
+
90
+ /* Rely on Shiki's own token spans; no class remap */
91
  .content-grid main code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
92
+ /* Placeholder block (discreet centered text) */
93
+ .placeholder-block {
94
+ display: grid;
95
+ place-items: center;
96
+ min-height: 120px;
97
+ color: var(--muted-color);
98
+ font-size: 12px;
99
+ border: 1px dashed var(--border-color);
100
+ border-radius: 8px;
101
+ background: var(--surface-bg);
102
+ }
103
+
104
+ /* Demo blocks for width helpers */
105
+ .demo-wide,
106
+ .demo-full-bleed {
107
+ display: grid;
108
+ place-items: center;
109
+ min-height: 150px;
110
+ color: var(--muted-color);
111
+ font-size: 12px;
112
+ border: 1px dashed var(--border-color);
113
+ border-radius: 8px;
114
+ background: var(--surface-bg);
115
+ }
116
 
117
  /* Pretty-code language label (visible chip at top-right) */
118
  .content-grid main pre:has(code[data-language]),
 
157
  .content-grid main hr { border: none; border-bottom: 1px solid var(--border-color); margin: var(--spacing-5) 0; }
158
 
159
 
160
+ .code-block {
161
+ background: var(--code-bg);
162
+ border: 1px solid var(--border-color);
163
+ border-radius: 6px;
164
+ padding: var(--spacing-3);
165
+ font-size: 14px;
166
+ overflow: auto;
167
+ }
168
 
169
  // ============================================================================
170
  // Media / Figures
app/src/styles/{components/_layout.scss → _layout.scss} RENAMED
@@ -30,4 +30,66 @@ main > nav:first-of-type { display: none; }
30
  .toc { position: static; }
31
  .right-aside { display: none; }
32
  main > nav:first-of-type { display: block; }
33
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  .toc { position: static; }
31
  .right-aside { display: none; }
32
  main > nav:first-of-type { display: block; }
33
+ }
34
+
35
+
36
+
37
+ .margin-aside { position: relative; margin: 12px 0; }
38
+
39
+ .margin-aside__aside {
40
+ position: absolute;
41
+ top: 0;
42
+ right: -260px; /* push into the right grid column (width 260 + gap 32) */
43
+ width: 260px;
44
+ border-radius: 8px;
45
+ padding: 0 10px;
46
+ font-size: 0.9rem;
47
+ color: var(--muted-color);
48
+ }
49
+ @media (max-width: 1100px) {
50
+ .margin-aside__aside {
51
+ position: static;
52
+ width: auto;
53
+ margin-top: 8px;
54
+ }
55
+ }
56
+
57
+
58
+ // ============================================================================
59
+ // Width helpers – slightly wider than main column, and full-bleed to viewport
60
+ // ----------------------------------------------------------------------------
61
+ // Usage in MDX:
62
+ // <div className="wide"> ... </div>
63
+ // <div className="full-bleed"> ... </div>
64
+ // These center the content relative to the viewport while keeping it responsive.
65
+ //
66
+ // Notes:
67
+ // - These helpers work inside the main article column; they break out visually
68
+ // to be wider or fully span the viewport. On small screens, they fall back to 100%.
69
+ // - Adjust the target width in .wide if desired.
70
+ .wide,
71
+ .full-bleed { box-sizing: border-box; }
72
+
73
+ .wide {
74
+ /* Target up to ~1100px while staying within viewport minus page gutters */
75
+ width: min(1100px, 100vw - 32px);
76
+ margin-left: 50%;
77
+ transform: translateX(-50%);
78
+ }
79
+
80
+ .full-bleed {
81
+ /* Span the full viewport width */
82
+ width: 100vw;
83
+ margin-left: 50%;
84
+ transform: translateX(-50%);
85
+ }
86
+
87
+ @media (max-width: 1100px) {
88
+ .wide,
89
+ .full-bleed {
90
+ width: 100%;
91
+ margin-left: 0;
92
+ transform: none;
93
+ }
94
+ }
95
+
app/src/styles/{components/_variables.scss → _variables.scss} RENAMED
@@ -23,6 +23,11 @@
23
  --spacing-3: 16px;
24
  --spacing-4: 24px;
25
  --spacing-5: 32px;
 
 
 
 
 
26
  }
27
  // Theme tokens for dark mode
28
  [data-theme="dark"] {
 
23
  --spacing-3: 16px;
24
  --spacing-4: 24px;
25
  --spacing-5: 32px;
26
+ --spacing-6: 40px;
27
+ --spacing-7: 48px;
28
+ --spacing-8: 56px;
29
+ --spacing-9: 64px;
30
+ --spacing-10: 72px;
31
  }
32
  // Theme tokens for dark mode
33
  [data-theme="dark"] {
app/src/styles/components/_footer.scss ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ .distill-footer { margin-top: 40px; border-top: 1px solid var(--border-color); }
2
+ .footer-inner { max-width: 680px; margin: 0 auto; padding: 24px 16px; }
3
+ .citation-block h3 { margin: 0 0 8px; }
4
+ .citation-block h4 { margin: 16px 0 8px; font-size: 14px; text-transform: uppercase; color: var(--muted-color); }
5
+ .citation-text, .citation-bibtex { width: 100%; min-height: 44px; border: 1px solid var(--border-color); border-radius: 6px; background: var(--surface-bg); padding: 8px; resize: none; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 13px; color: var(--text-color); white-space: pre-wrap; overflow-y: hidden; line-height: 1.4; }
6
+ .references-block h3 { margin: 24px 0 8px; }
7
+ .references-block .footnotes { margin-top: 8px; }
8
+ .references-block .bibliography { margin-top: 8px; }
app/src/styles/global.scss CHANGED
@@ -1,6 +1,8 @@
1
- @import "./components/variables";
2
- @import "./components/base";
3
- @import "./components/layout";
 
 
4
  /* Dark-mode form tweak */
5
  [data-theme="dark"] .plotly_input_container > select { background-color: #1a1f27; border-color: var(--border-color); color: var(--text-color); }
6
 
@@ -12,29 +14,6 @@
12
  [data-theme="dark"] .citation-text,
13
  [data-theme="dark"] .citation-bibtex { background: #12151b; border-color: rgba(255,255,255,.15); color: var(--text-color); }
14
 
15
-
16
- .margin-aside { position: relative; margin: 12px 0; }
17
-
18
- .margin-aside__main { /* main text stays full width of the main column */ }
19
- .margin-aside__aside {
20
- position: absolute;
21
- top: 0;
22
- right: -260px; /* push into the right grid column (width 260 + gap 32) */
23
- width: 260px;
24
- border-radius: 8px;
25
- padding: 10px;
26
- font-size: 0.9rem;
27
- color: var(--muted-color);
28
- }
29
- @media (max-width: 1100px) {
30
- .margin-aside__aside {
31
- position: static;
32
- width: auto;
33
- margin-top: 8px;
34
- }
35
- }
36
-
37
-
38
  /* Opt-in zoomable images */
39
  img[data-zoomable] { cursor: zoom-in; }
40
  .medium-zoom--opened img[data-zoomable] { cursor: zoom-out; }
@@ -110,3 +89,4 @@ img[data-zoomable] { cursor: zoom-in; }
110
  [data-theme="dark"] #theme-toggle .icon.light { display: none; }
111
  [data-theme="dark"] #theme-toggle .icon.dark { display: inline; }
112
  [data-theme="dark"] #theme-toggle .icon { filter: invert(1) brightness(1.2); }
 
 
1
+ @use "./variables" as *;
2
+ @use "./base" as *;
3
+ @use "./layout" as *;
4
+ @use "./components/footer" as *;
5
+
6
  /* Dark-mode form tweak */
7
  [data-theme="dark"] .plotly_input_container > select { background-color: #1a1f27; border-color: var(--border-color); color: var(--text-color); }
8
 
 
14
  [data-theme="dark"] .citation-text,
15
  [data-theme="dark"] .citation-bibtex { background: #12151b; border-color: rgba(255,255,255,.15); color: var(--text-color); }
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  /* Opt-in zoomable images */
18
  img[data-zoomable] { cursor: zoom-in; }
19
  .medium-zoom--opened img[data-zoomable] { cursor: zoom-out; }
 
89
  [data-theme="dark"] #theme-toggle .icon.light { display: none; }
90
  [data-theme="dark"] #theme-toggle .icon.dark { display: inline; }
91
  [data-theme="dark"] #theme-toggle .icon { filter: invert(1) brightness(1.2); }
92
+