Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ This is the presentation framework layer. It owns the slide shell, scaling, navi

This is the slide content layer. It owns the concrete slide pages and their copy.

- `deckMeta.js`: Deck-level metadata. It owns the bilingual deck title, bilingual speaker information, and exported filename stem.
- `slides.jsx`: Slide registry. It controls slide order, slide titles, slide type, and the component used for each slide.
- `slides/OverviewSlide.jsx`: Cover slide example.
- `slides/ImageSlide.jsx`: Image layout example.
Expand All @@ -56,6 +57,8 @@ This is the slide content layer. It owns the concrete slide pages and their copy

To add a new slide, create a component in `src/content/slides/`, then register it in `src/content/slides.jsx`.

When changing deck-level title, speaker, or PDF filename information, update `src/content/deckMeta.js` instead of hard-coding those values inside slide components.

## `src/components/`

This is the reusable content component layer.
Expand Down
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ src/
exportPdf.js # Converts slides to JPG and combines them into a PDF
Toolbar.jsx # Theme, language, navigation, fullscreen, and export controls
content/
deckMeta.js # Deck title and exported filename stem
deckMeta.js # Deck title, speaker metadata, and exported filename stem
slides.jsx # Slide registry
slides/ # Individual slide content components
components/
Expand Down Expand Up @@ -93,9 +93,35 @@ export const slides = [

Every slide is a regular React component and can define its own layout. The framework handles canvas size, scaling, page numbers, theme state, and export.

## Edit Deck Metadata

Deck-level metadata lives in `src/content/deckMeta.js`. Update it when you need to change the deck title, cover speaker information, or exported PDF filename:

```js
export const deckMeta = {
title: {
zh: "Minimal Web Slides",
en: "Minimal Web Slides",
},
speaker: {
zh: {
name: "React Web Slides 模板",
title: "预览 · 主题 · 双语 · PDF",
},
en: {
name: "React Web Slides Template",
title: "Preview · themes · bilingual · PDF",
},
},
filenameStem: "minimal-web-slides",
};
```

The cover slide reads its title and speaker fields from this metadata, while PDF export uses `filenameStem`.

## Edit Bilingual Copy

Example slide copy is stored in a `copy` object near the top of each slide file:
Page-specific slide copy is stored in a `copy` object near the top of each slide file:

```jsx
const copy = {
Expand Down
30 changes: 28 additions & 2 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ src/
exportPdf.js # 将页面转 JPG 并合成 PDF
Toolbar.jsx # 主题、语言、翻页、全屏和导出控制
content/
deckMeta.js # 演示标题和导出文件名
deckMeta.js # 演示标题、讲者信息和导出文件名
slides.jsx # 幻灯片注册表
slides/ # 单页内容组件
components/
Expand Down Expand Up @@ -85,9 +85,35 @@ export const slides = [

每一页都是普通 React 组件,可以完全自定义布局。框架会自动处理画布、缩放、页码、主题和导出。

## 修改演示元信息

演示级别的元信息集中在 `src/content/deckMeta.js`。需要修改演示标题、封面讲者信息或导出 PDF 文件名时,优先修改这里:

```js
export const deckMeta = {
title: {
zh: "Minimal Web Slides",
en: "Minimal Web Slides",
},
speaker: {
zh: {
name: "React Web Slides 模板",
title: "预览 · 主题 · 双语 · PDF",
},
en: {
name: "React Web Slides Template",
title: "Preview · themes · bilingual · PDF",
},
},
filenameStem: "minimal-web-slides",
};
```

封面页会从这里读取标题和讲者字段,PDF 导出会使用 `filenameStem`。

## 修改中英文内容

示例页的中英文文案放在各自文件顶部的 `copy` 对象中:
页面自己的中英文文案放在各自文件顶部的 `copy` 对象中:

```jsx
const copy = {
Expand Down
23 changes: 19 additions & 4 deletions src/content/deckMeta.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
export const deckTitle = {
zh: "Minimal Web Slides",
en: "Minimal Web Slides",
export const deckMeta = {
title: {
zh: "Minimal Web Slides",
en: "Minimal Web Slides",
},
speaker: {
zh: {
name: "React Web Slides 模板",
title: "预览 · 主题 · 双语 · PDF",
},
en: {
name: "React Web Slides Template",
title: "Preview · themes · bilingual · PDF",
},
},
filenameStem: "minimal-web-slides",
};

export const deckFilenameStem = "minimal-web-slides";
export const deckTitle = deckMeta.title;
export const deckSpeaker = deckMeta.speaker;
export const deckFilenameStem = deckMeta.filenameStem;
27 changes: 7 additions & 20 deletions src/content/slides/OverviewSlide.jsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,21 @@
import { SlideTitle } from "../../components/Typography.jsx";
import { deckTitle } from "../deckMeta.js";

const copy = {
zh: {
title: deckTitle.zh,
speakerName: "React Web Slides 模板",
speakerTitle: "预览 · 主题 · 双语 · PDF",
},
en: {
title: deckTitle.en,
speakerName: "React Web Slides Template",
speakerTitle: "Preview · themes · bilingual · PDF",
},
};
import { deckSpeaker, deckTitle } from "../deckMeta.js";

export function OverviewSlide({ locale }) {
const t = copy[locale];
const hasSpeakerTitle = t.speakerName && t.speakerTitle;
const speaker = deckSpeaker[locale];
const hasSpeakerTitle = speaker?.name && speaker?.title;

return (
<div className="overview-slide">
<div className="overview-slide__cover">
<SlideTitle>{t.title}</SlideTitle>
<SlideTitle>{deckTitle[locale]}</SlideTitle>
{hasSpeakerTitle ? (
<div className="cover-speaker cover-speaker--split">
<span className="cover-speaker__name">{t.speakerName}</span>
<span className="cover-speaker__title">{t.speakerTitle}</span>
<span className="cover-speaker__name">{speaker.name}</span>
<span className="cover-speaker__title">{speaker.title}</span>
</div>
) : (
<p className="cover-speaker">{t.speaker}</p>
<p className="cover-speaker">{typeof speaker === 'string' ? speaker : speaker?.name}</p>
)}
Comment thread
hiyouga marked this conversation as resolved.
</div>
</div>
Expand Down
7 changes: 5 additions & 2 deletions src/presentation/SlideFrame.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ export function SlideFrame({ children, slide, slideIndex, slideCount, scale }) {
>
<div className="halo-mark" aria-hidden="true">
<span className="halo-mark__circle" />
<span className="halo-mark__dot halo-mark__dot--a" />
<span className="halo-mark__dot halo-mark__dot--b" />
<span className="halo-mark__dots">
<span className="halo-mark__dot halo-mark__dot--a" />
<span className="halo-mark__dot halo-mark__dot--b" />
<span className="halo-mark__dot halo-mark__dot--c" />
</span>
<span className="halo-mark__corner" />
</div>

Expand Down
42 changes: 28 additions & 14 deletions src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -279,17 +279,18 @@ button {
}

.halo-mark__circle,
.halo-mark__dots,
.halo-mark__dot,
.halo-mark__corner {
position: absolute;
display: block;
}

.halo-mark__circle {
top: 82px;
left: 76px;
width: 80px;
height: 80px;
top: 72px;
left: 72px;
width: 82px;
height: 82px;
border: 3px solid currentColor;
border-radius: 50%;
background: transparent;
Expand All @@ -300,23 +301,36 @@ button {
background: currentColor;
}

.halo-mark__dots {
inset: 0;
transform: rotate(-20deg);
transform-origin: 113px 113px;
}

.halo-mark__dot--a {
top: 72px;
left: 58px;
width: 11px;
height: 11px;
top: 46.5px;
left: 106.5px;
width: 13px;
height: 13px;
}

.halo-mark__dot--b {
top: 142px;
left: 168px;
width: 15px;
height: 15px;
top: 135px;
left: 157px;
width: 16px;
height: 16px;
}

.halo-mark__dot--c {
top: 136px;
left: 54px;
width: 14px;
height: 14px;
}

.halo-mark__corner {
top: 46px;
left: 136px;
top: 34px;
left: 148px;
width: 52px;
height: 52px;
border-top: 3px solid currentColor;
Expand Down
Loading