@kadal/theme-folio 0.0.0-stage → 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/LICENSE +661 -0
- package/README.md +66 -2
- package/index.tsx +115 -0
- package/package.json +106 -4
- package/style.css +729 -0
package/README.md
CHANGED
|
@@ -1,3 +1,67 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kadal/theme-folio
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Folio**, a theme for [Kadal Deck](https://deck.kadal.cc). An editorial theme for essays and keynotes. Warm paper and ink, Playfair Display for the display lines, Newsreader for reading text, IBM Plex Mono for code; one oxblood accent and a gilt second. Generous margins, a measure kept to reading length, booktabs tables, an asterism for a rule, small capitals for labels, a fleuron over a section.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Use it
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @kadal/theme-folio
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
---
|
|
15
|
+
theme: folio
|
|
16
|
+
themeConfig: # all optional
|
|
17
|
+
paper: "#f6f0e4"
|
|
18
|
+
accent: "#9b2c1c"
|
|
19
|
+
accentDark: "#e8957c"
|
|
20
|
+
---
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The deck plugin brings the stylesheet and the module in; nothing to import. The prebuilt shell (the hosted builder, published decks) bundles this theme already. Schemes: light and dark. Fonts: Playfair Display (headings), Newsreader (text, `--deck-serif-font`), IBM Plex Mono (code), loaded through the theme's `config.fonts`. Code colours: Shiki's gruvbox-light-soft / gruvbox-dark-soft. To show it beside other themes in the theme menu (<kbd>T</kbd>), list it: `themes: [folio, minimal]`.
|
|
24
|
+
|
|
25
|
+
## themeConfig
|
|
26
|
+
|
|
27
|
+
Every key arrives on the deck root as a CSS variable (`accentDark` → `--theme-accent-dark`); the theme reads them with fallbacks, so set only what you change.
|
|
28
|
+
|
|
29
|
+
| key | type | default | what it does |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| `paper` | colour | `#f6f0e4` | The light page's colour. |
|
|
32
|
+
| `accent` | colour | `#9b2c1c` | The light scheme's accent (oxblood). |
|
|
33
|
+
| `accentDark` | colour | `#e8957c` | The dark scheme's accent. Without it, a set `accent` is lifted towards white. |
|
|
34
|
+
|
|
35
|
+
## Layouts
|
|
36
|
+
|
|
37
|
+
Every built-in layout is styled (`default`, `center`, `cover`, `intro`, `section`, `end`, `fact`, `quote`, `statement`, `full`, `two-cols`, `two-cols-header`, `image`, `image-left`, `image-right`, `iframe`, `iframe-left`, `iframe-right`), and the theme adds:
|
|
38
|
+
|
|
39
|
+
| layout | what |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `pull-quote` | The line that carries the piece, between an accent rule and a hairline; `by:` sets the attribution. |
|
|
42
|
+
| `essay` | One column at reading measure with a drop cap; an `::aside::` slot becomes a note in the margin. |
|
|
43
|
+
| `chapter` | A chapter opener: "Chapter" and its roman numeral (counted from the deck's chapter slides, or `n:`; `label:` changes the word), the title, and an epigraph if the slide has a blockquote. |
|
|
44
|
+
|
|
45
|
+
## Components
|
|
46
|
+
|
|
47
|
+
| component | what |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `<Byline author date place />` | Author, date and place between two hairlines, in small capitals. |
|
|
50
|
+
| `<Lede>…</Lede>` | The opening paragraph, larger, with a drop cap. |
|
|
51
|
+
|
|
52
|
+
## Preview
|
|
53
|
+
|
|
54
|
+
`preview/deck.mdx` walks through every layout and component (`theme: ../`). In this repository:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
bun run --filter @kadal/theme-folio dev # the preview deck, live
|
|
58
|
+
node tools/theme-shots.mjs folio # screenshots in light and dark, contrast and overflow checks
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Accessibility and print
|
|
62
|
+
|
|
63
|
+
Body and muted text meet WCAG AA (4.5:1) on the page and on cards in every scheme the theme draws (checked by `tools/theme-shots.mjs`). Anything that moves stands still under `prefers-reduced-motion` and on a still copy; printed pages and exports drop shadows and glows.
|
|
64
|
+
|
|
65
|
+
## Licence
|
|
66
|
+
|
|
67
|
+
AGPL-3.0-or-later, like the engine (see LICENSE); a commercial licence is available — see [LICENSING](https://github.com/kadalcc/deck/blob/main/LICENSING.md).
|
package/index.tsx
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import { type LayoutProps, useDeck, useSlideOptional } from "@kadal/deck";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
* Folio's module: the layouts an essay or a keynote reaches for, and two pieces of furniture.
|
|
8
|
+
*
|
|
9
|
+
* layout: pull-quote the line that carries the piece, between an accent rule and a hairline;
|
|
10
|
+
* `by:` sets the attribution
|
|
11
|
+
* layout: essay one column at reading measure with a drop cap; `::aside::` is a note
|
|
12
|
+
* in the margin
|
|
13
|
+
* layout: chapter a chapter opener: "Chapter" and its roman numeral (counted, or `n:`),
|
|
14
|
+
* the title, and an epigraph if the slide has a blockquote
|
|
15
|
+
* <Byline> author, date and place between two hairlines, in small capitals
|
|
16
|
+
* <Lede> the opening paragraph, larger, with a drop cap
|
|
17
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const str = (v: unknown) => (typeof v === "string" && v.trim() ? v.trim() : null);
|
|
21
|
+
|
|
22
|
+
function PullQuote({ children, frontmatter }: LayoutProps) {
|
|
23
|
+
const by = str(frontmatter.by);
|
|
24
|
+
return (
|
|
25
|
+
<div className="deck-layout deck-layout-pull-quote">
|
|
26
|
+
<figure className="folio-pull">
|
|
27
|
+
{children}
|
|
28
|
+
{by ? <figcaption className="folio-pull-by">{by}</figcaption> : null}
|
|
29
|
+
</figure>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function Essay({ children }: LayoutProps) {
|
|
35
|
+
return <div className="deck-layout deck-layout-essay">{children}</div>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const ROMAN: Array<[number, string]> = [
|
|
39
|
+
[1000, "M"],
|
|
40
|
+
[900, "CM"],
|
|
41
|
+
[500, "D"],
|
|
42
|
+
[400, "CD"],
|
|
43
|
+
[100, "C"],
|
|
44
|
+
[90, "XC"],
|
|
45
|
+
[50, "L"],
|
|
46
|
+
[40, "XL"],
|
|
47
|
+
[10, "X"],
|
|
48
|
+
[9, "IX"],
|
|
49
|
+
[5, "V"],
|
|
50
|
+
[4, "IV"],
|
|
51
|
+
[1, "I"],
|
|
52
|
+
];
|
|
53
|
+
function roman(n: number): string {
|
|
54
|
+
let out = "";
|
|
55
|
+
let left = Math.max(1, Math.floor(n));
|
|
56
|
+
for (const [v, s] of ROMAN)
|
|
57
|
+
while (left >= v) {
|
|
58
|
+
out += s;
|
|
59
|
+
left -= v;
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Chapter({ children, frontmatter }: LayoutProps) {
|
|
65
|
+
const deck = useDeck();
|
|
66
|
+
const index = useSlideOptional()?.meta.index ?? 0;
|
|
67
|
+
const counted = deck.manifest.slides.filter(
|
|
68
|
+
(s) => s.index <= index && s.frontmatter.layout === "chapter",
|
|
69
|
+
).length;
|
|
70
|
+
const given = frontmatter.n == null ? "" : String(frontmatter.n).trim();
|
|
71
|
+
const numeral = given ? (/^\d+$/.test(given) ? roman(Number(given)) : given) : roman(counted);
|
|
72
|
+
return (
|
|
73
|
+
<div className="deck-layout deck-layout-chapter">
|
|
74
|
+
<div className="folio-chapter-number">
|
|
75
|
+
{str(frontmatter.label) ?? "Chapter"}
|
|
76
|
+
<b>{numeral}</b>
|
|
77
|
+
</div>
|
|
78
|
+
{children}
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function Byline({
|
|
84
|
+
author,
|
|
85
|
+
date,
|
|
86
|
+
place,
|
|
87
|
+
children,
|
|
88
|
+
}: {
|
|
89
|
+
author?: string;
|
|
90
|
+
date?: string;
|
|
91
|
+
place?: string;
|
|
92
|
+
children?: ReactNode;
|
|
93
|
+
}) {
|
|
94
|
+
return (
|
|
95
|
+
<div className="folio-byline">
|
|
96
|
+
{author ? (
|
|
97
|
+
<span>
|
|
98
|
+
By <b>{author}</b>
|
|
99
|
+
</span>
|
|
100
|
+
) : null}
|
|
101
|
+
{date ? <span>{date}</span> : null}
|
|
102
|
+
{place ? <span>{place}</span> : null}
|
|
103
|
+
{children}
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function Lede({ children }: { children?: ReactNode }) {
|
|
109
|
+
return <div className="folio-lede">{children}</div>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export default {
|
|
113
|
+
layouts: { "pull-quote": PullQuote, essay: Essay, chapter: Chapter },
|
|
114
|
+
components: { Byline, Lede },
|
|
115
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,108 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kadal/theme-folio",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "Folio, a theme for Kadal Deck (@kadal/deck). An editorial serif theme for essays and keynotes: warm paper, a high-contrast display serif, generous whitespace.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"kadal-theme",
|
|
7
|
+
"kadal-deck",
|
|
8
|
+
"presentation",
|
|
9
|
+
"slides",
|
|
10
|
+
"theme",
|
|
11
|
+
"editorial",
|
|
12
|
+
"serif",
|
|
13
|
+
"essay",
|
|
14
|
+
"keynote"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://deck.kadal.cc/docs/",
|
|
17
|
+
"funding": {
|
|
18
|
+
"type": "github",
|
|
19
|
+
"url": "https://github.com/sponsors/pmithunish"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/kadalcc/deck.git",
|
|
24
|
+
"directory": "packages/theme-folio"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/kadalcc/deck/issues"
|
|
28
|
+
},
|
|
29
|
+
"license": "AGPL-3.0-or-later",
|
|
30
|
+
"author": "Mithunish Prabhakaran <pmithunish@gmail.com>",
|
|
31
|
+
"type": "module",
|
|
32
|
+
"sideEffects": [
|
|
33
|
+
"*.css"
|
|
34
|
+
],
|
|
35
|
+
"files": [
|
|
36
|
+
"style.css",
|
|
37
|
+
"index.tsx",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"exports": {
|
|
42
|
+
".": "./index.tsx",
|
|
43
|
+
"./style.css": "./style.css",
|
|
44
|
+
"./package.json": "./package.json"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public",
|
|
48
|
+
"provenance": true
|
|
49
|
+
},
|
|
50
|
+
"kadal": {
|
|
51
|
+
"theme": {
|
|
52
|
+
"name": "folio",
|
|
53
|
+
"title": "Folio",
|
|
54
|
+
"description": "An editorial serif theme for essays and keynotes: warm paper, a high-contrast display serif, generous whitespace.",
|
|
55
|
+
"colorScheme": "both",
|
|
56
|
+
"config": {
|
|
57
|
+
"transition": "fade",
|
|
58
|
+
"fonts": {
|
|
59
|
+
"heading": "Playfair Display, Georgia, serif",
|
|
60
|
+
"serif": "Newsreader, Georgia",
|
|
61
|
+
"mono": "IBM Plex Mono",
|
|
62
|
+
"local": [
|
|
63
|
+
"Georgia"
|
|
64
|
+
],
|
|
65
|
+
"weights": "400,500,600,700",
|
|
66
|
+
"italic": true
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"themeConfig": {
|
|
70
|
+
"paper": "#f6f0e4"
|
|
71
|
+
},
|
|
72
|
+
"shiki": {
|
|
73
|
+
"light": "gruvbox-light-soft",
|
|
74
|
+
"dark": "gruvbox-dark-soft"
|
|
75
|
+
},
|
|
76
|
+
"defaults": {},
|
|
77
|
+
"layouts": [
|
|
78
|
+
"pull-quote",
|
|
79
|
+
"essay",
|
|
80
|
+
"chapter"
|
|
81
|
+
],
|
|
82
|
+
"components": [
|
|
83
|
+
"Byline",
|
|
84
|
+
"Lede"
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"scripts": {
|
|
89
|
+
"dev": "kadal-deck dev -C preview",
|
|
90
|
+
"check": "kadal-deck check -C preview",
|
|
91
|
+
"typecheck": "tsc --noEmit",
|
|
92
|
+
"test": "bun test"
|
|
93
|
+
},
|
|
94
|
+
"peerDependencies": {
|
|
95
|
+
"@kadal/deck": "^0.4.1",
|
|
96
|
+
"react": "^19.2.0"
|
|
97
|
+
},
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"@kadal/deck": "workspace:*",
|
|
100
|
+
"@types/react": "^19.2.0",
|
|
101
|
+
"@types/react-dom": "^19.2.0",
|
|
102
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
103
|
+
"react": "^19.2.7",
|
|
104
|
+
"react-dom": "^19.2.7",
|
|
105
|
+
"typescript": "^6.0.3",
|
|
106
|
+
"vite": "^8.0.16"
|
|
107
|
+
}
|
|
108
|
+
}
|