@awesomephant/reactcake 0.0.1 → 1.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.
- package/.github/workflows/release.yml +1 -1
- package/Readme.md +1 -1
- package/lib/Html/index.tsx +7 -6
- package/package.json +1 -1
- package/site/src/components/Example.astro +1 -1
- package/site/src/examples/AxisX/index.tsx +106 -0
- package/site/src/examples/AxisX/styles.module.css +31 -0
- package/site/src/examples/AxisY/index.tsx +76 -0
- package/site/src/examples/AxisY/styles.module.css +33 -0
- package/site/src/examples/ColumnChart.tsx +32 -17
- package/site/src/examples/Columns.tsx +17 -19
- package/site/src/examples/Gantt.tsx +39 -0
- package/site/src/examples/OrdinalKey/index.tsx +55 -0
- package/site/src/examples/OrdinalKey/styles.css +47 -0
- package/site/src/layouts/Base.astro +9 -0
- package/site/src/pages/index.mdx +0 -2
- package/site/tsconfig.json +1 -1
- package/site/.astro/content.d.ts +0 -170
- package/site/.astro/dev.json +0 -14
- package/site/.astro/settings.json +0 -8
- package/site/.astro/types.d.ts +0 -2
- package/site/src/examples/AxisX.tsx +0 -1
package/Readme.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A headless chart framework for React inspired by [Layercake](https://layercake.graphics/). See [documentation](https://reactcake.maxkohler.com/) for usage and motivation.
|
|
4
4
|
|
|
5
|
-
[](https://github.com/awesomephant/reactcake/actions/workflows/release.yml)
|
|
5
|
+
 [](https://github.com/awesomephant/reactcake/actions/workflows/release.yml)
|
|
6
6
|
|
|
7
7
|
## Contributing
|
|
8
8
|
|
package/lib/Html/index.tsx
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
+
import { useReactCake } from "../ReactCake";
|
|
2
3
|
|
|
3
4
|
interface HtmlProps {
|
|
4
5
|
children?: ReactNode;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
const Html = ({ children }: HtmlProps) => {
|
|
9
|
+
const { padding } = useReactCake();
|
|
10
|
+
|
|
8
11
|
return (
|
|
9
12
|
<div
|
|
10
13
|
className="reactcake-html"
|
|
11
14
|
style={{
|
|
12
15
|
position: "absolute",
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
right: 0,
|
|
18
|
-
bottom: 0,
|
|
16
|
+
top: padding.top,
|
|
17
|
+
left: padding.left,
|
|
18
|
+
right: padding.right,
|
|
19
|
+
bottom: padding.bottom,
|
|
19
20
|
}}
|
|
20
21
|
>
|
|
21
22
|
{children}
|
package/package.json
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Fragment } from "react";
|
|
2
|
+
import { useReactCake } from "../../../../lib";
|
|
3
|
+
import styles from "./styles.module.css";
|
|
4
|
+
|
|
5
|
+
interface AxisProps {
|
|
6
|
+
position?: "top" | "bottom";
|
|
7
|
+
count?: number;
|
|
8
|
+
format?: (d: unknown) => string;
|
|
9
|
+
label?: string;
|
|
10
|
+
ticksValues?: number | DatumValue[] | ((ticks: unknown[]) => unknown[]);
|
|
11
|
+
showBaseline?: boolean;
|
|
12
|
+
grid?: boolean;
|
|
13
|
+
snapLabels?: boolean;
|
|
14
|
+
tickLength?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const AxisX = ({
|
|
18
|
+
ticks,
|
|
19
|
+
showBaseline = true,
|
|
20
|
+
position = "bottom",
|
|
21
|
+
grid = false,
|
|
22
|
+
format = (d) => String(d),
|
|
23
|
+
tickLength = 8,
|
|
24
|
+
}: AxisProps) => {
|
|
25
|
+
const { xScale } = useReactCake();
|
|
26
|
+
|
|
27
|
+
if (!xScale) return <></>;
|
|
28
|
+
|
|
29
|
+
const isBandwidth = typeof xScale.bandwidth === "function";
|
|
30
|
+
|
|
31
|
+
const tickVals = Array.isArray(ticks)
|
|
32
|
+
? ticks
|
|
33
|
+
: isBandwidth
|
|
34
|
+
? xScale.domain()
|
|
35
|
+
: typeof ticks === "function"
|
|
36
|
+
? ticks(xScale.ticks())
|
|
37
|
+
: xScale.ticks(ticks);
|
|
38
|
+
|
|
39
|
+
const halfBand = isBandwidth ? xScale.bandwidth() / 2 : 0;
|
|
40
|
+
|
|
41
|
+
const tickEls = tickVals.map((v) => {
|
|
42
|
+
const x = xScale(v);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Fragment key={`tick-${v.toString()}`}>
|
|
46
|
+
{grid && (
|
|
47
|
+
<div
|
|
48
|
+
className={styles.gridline}
|
|
49
|
+
style={{
|
|
50
|
+
top: 0,
|
|
51
|
+
bottom: 0,
|
|
52
|
+
left: `${x + halfBand}%`,
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
)}
|
|
56
|
+
<div
|
|
57
|
+
className={styles.tick}
|
|
58
|
+
style={{
|
|
59
|
+
left: `${x + halfBand}%`,
|
|
60
|
+
bottom: position === "bottom" ? -tickLength : "auto",
|
|
61
|
+
top: position === "top" ? -tickLength + 1 : "auto",
|
|
62
|
+
height: `${tickLength}px`,
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<span className={styles.tick_mark}></span>
|
|
66
|
+
<span
|
|
67
|
+
className={styles.tick__text}
|
|
68
|
+
style={{
|
|
69
|
+
top: position === "bottom" ? `${tickLength}px` : "auto",
|
|
70
|
+
left: 0,
|
|
71
|
+
bottom: position === "top" ? `${tickLength + 2}px` : "auto",
|
|
72
|
+
transform: `translateX(-50%) ${position === "top" ? "translateY(-50%)" : ""}`,
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
{format(v)}
|
|
76
|
+
</span>
|
|
77
|
+
</div>
|
|
78
|
+
</Fragment>
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div
|
|
84
|
+
className={styles.axis}
|
|
85
|
+
style={{
|
|
86
|
+
bottom: position === "bottom" ? 0 : "auto",
|
|
87
|
+
top: position === "top" ? 0 : "auto",
|
|
88
|
+
}}
|
|
89
|
+
>
|
|
90
|
+
{tickEls}
|
|
91
|
+
{showBaseline && (
|
|
92
|
+
<div
|
|
93
|
+
className={styles.baseline}
|
|
94
|
+
style={{
|
|
95
|
+
bottom: position === "bottom" ? 0 : "auto",
|
|
96
|
+
top: position === "top" ? 0 : "auto",
|
|
97
|
+
left: 0,
|
|
98
|
+
right: 0,
|
|
99
|
+
}}
|
|
100
|
+
></div>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export default AxisX;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
.axis {
|
|
2
|
+
width: 100%;
|
|
3
|
+
height: 100%;
|
|
4
|
+
position: absolute;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.tick {
|
|
8
|
+
position: absolute;
|
|
9
|
+
border-left: 1px solid var(--blue-50);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.gridline {
|
|
13
|
+
bottom: 0;
|
|
14
|
+
position: absolute;
|
|
15
|
+
border-left: 1px dotted var(--blue-50);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
.baseline {
|
|
20
|
+
position: absolute;
|
|
21
|
+
border-bottom: 1px solid var(--blue-50);
|
|
22
|
+
width: 100%;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.tick__text {
|
|
26
|
+
display: block;
|
|
27
|
+
font-size: var(--ms--1);
|
|
28
|
+
color: var(--blue-50);
|
|
29
|
+
position: relative;
|
|
30
|
+
white-space: nowrap;
|
|
31
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Fragment } from "react";
|
|
2
|
+
import { useReactCake } from "../../../../lib";
|
|
3
|
+
import styles from "./styles.module.css";
|
|
4
|
+
|
|
5
|
+
interface AxisYProps {
|
|
6
|
+
position?: "left" | "right";
|
|
7
|
+
format?: (d: unknown) => string;
|
|
8
|
+
label?: string;
|
|
9
|
+
ticks?: number | DatumValue[] | ((ticks: unknown[]) => unknown[]);
|
|
10
|
+
showBaseline?: boolean;
|
|
11
|
+
grid?: boolean;
|
|
12
|
+
showTicks?: boolean;
|
|
13
|
+
snapLabels?: boolean;
|
|
14
|
+
tickLength?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const AxisY = ({
|
|
18
|
+
ticks,
|
|
19
|
+
showBaseline = true,
|
|
20
|
+
grid = true,
|
|
21
|
+
showTicks = true,
|
|
22
|
+
tickLength = 8,
|
|
23
|
+
tickGutter = 3,
|
|
24
|
+
format = (d) => String(d),
|
|
25
|
+
}: AxisYProps) => {
|
|
26
|
+
const { yScale, padding } = useReactCake();
|
|
27
|
+
const isBandwidth = typeof yScale.bandwidth === "function";
|
|
28
|
+
|
|
29
|
+
const tickVals = Array.isArray(ticks)
|
|
30
|
+
? ticks
|
|
31
|
+
: isBandwidth
|
|
32
|
+
? yScale.domain()
|
|
33
|
+
: typeof ticks === "function"
|
|
34
|
+
? ticks(yScale.ticks())
|
|
35
|
+
: yScale.ticks(ticks);
|
|
36
|
+
|
|
37
|
+
const halfBand = isBandwidth ? yScale.bandwidth() / 2 : 0;
|
|
38
|
+
|
|
39
|
+
const tickEls = tickVals.map((v, i) => {
|
|
40
|
+
const y = yScale(v);
|
|
41
|
+
return (
|
|
42
|
+
<Fragment key={`tick-${i}`}>
|
|
43
|
+
{grid && y + halfBand > 0 && (
|
|
44
|
+
<div className={styles.gridline} style={{ bottom: `${y + halfBand}%`, left: 0 }}></div>
|
|
45
|
+
)}
|
|
46
|
+
{format(v) !== "" && (
|
|
47
|
+
<div
|
|
48
|
+
className={styles.tick}
|
|
49
|
+
style={{
|
|
50
|
+
width: `${tickLength}px`,
|
|
51
|
+
bottom: `${y + halfBand}%`,
|
|
52
|
+
left: -tickLength,
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
{showTicks && <span className={styles.mark}></span>}
|
|
56
|
+
<span
|
|
57
|
+
className={styles.text}
|
|
58
|
+
style={{ position: "absolute", right: `calc(100% + ${tickGutter}px)` }}
|
|
59
|
+
>
|
|
60
|
+
{format(v)}
|
|
61
|
+
</span>
|
|
62
|
+
</div>
|
|
63
|
+
)}
|
|
64
|
+
</Fragment>
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div className={styles.axis} style={{ bottom: 0, top: 0 }}>
|
|
70
|
+
{tickEls}
|
|
71
|
+
{showBaseline && <div className={styles.baseline} style={{ left: 0 }}></div>}
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export default AxisY;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.axis {
|
|
2
|
+
width: 100%;
|
|
3
|
+
height: 100%;
|
|
4
|
+
position: absolute;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.tick {
|
|
8
|
+
position: absolute;
|
|
9
|
+
border-top: 1px solid var(--blue-50);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
.gridline {
|
|
14
|
+
left: 0;
|
|
15
|
+
right: 0;
|
|
16
|
+
position: absolute;
|
|
17
|
+
border-top: 1px dotted var(--blue-50);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
.baseline {
|
|
22
|
+
position: absolute;
|
|
23
|
+
border-left: 1px solid var(--blue-50);
|
|
24
|
+
height: 100%;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.text {
|
|
28
|
+
display: block;
|
|
29
|
+
font-size: var(--ms--1);
|
|
30
|
+
color: var(--blue-50);
|
|
31
|
+
white-space: nowrap;
|
|
32
|
+
transform: translateY(-50%);
|
|
33
|
+
}
|
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
import { ReactCake, ScaledSvg, Html } from "../../../lib";
|
|
2
|
+
import AxisX from "./AxisX/index";
|
|
3
|
+
import AxisY from "./AxisY";
|
|
2
4
|
import Columns from "./Columns";
|
|
3
|
-
import { scaleLinear, scaleBand } from "d3-scale"
|
|
5
|
+
import { scaleLinear, scaleBand } from "d3-scale";
|
|
6
|
+
import { max } from "d3-array";
|
|
4
7
|
|
|
5
8
|
const data = [
|
|
6
|
-
{year:
|
|
7
|
-
{year:
|
|
8
|
-
{year:
|
|
9
|
-
{year:
|
|
10
|
-
{year:
|
|
11
|
-
|
|
9
|
+
{ year: 2021, value: 18 },
|
|
10
|
+
{ year: 2022, value: 12 },
|
|
11
|
+
{ year: 2023, value: 22 },
|
|
12
|
+
{ year: 2024, value: 32 },
|
|
13
|
+
{ year: 2025, value: 15 },
|
|
14
|
+
{ year: 2026, value: 52 },
|
|
15
|
+
];
|
|
12
16
|
|
|
13
|
-
const xScale = scaleBand().paddingInner(.1)
|
|
17
|
+
const xScale = scaleBand().paddingInner(0.1).paddingOuter(0.2);
|
|
18
|
+
const yKey = "value";
|
|
14
19
|
|
|
15
20
|
export default function ColumnChart() {
|
|
16
21
|
return (
|
|
17
|
-
<ReactCake
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
<ReactCake
|
|
23
|
+
data={data}
|
|
24
|
+
x="year"
|
|
25
|
+
y={yKey}
|
|
26
|
+
yScale={scaleLinear()}
|
|
27
|
+
xScale={xScale}
|
|
28
|
+
percentRange={true}
|
|
29
|
+
yDomain={[0, max(data, (d) => d[yKey]) + 5]}
|
|
30
|
+
padding={{ top: 10, left: 35, right: 10, bottom: 30 }}
|
|
31
|
+
>
|
|
32
|
+
<Html>
|
|
33
|
+
<AxisX grid ticks />
|
|
34
|
+
<AxisY grid ticks={3} />
|
|
35
|
+
</Html>
|
|
36
|
+
<ScaledSvg overflow="hidden">
|
|
37
|
+
<Columns />
|
|
38
|
+
</ScaledSvg>
|
|
39
|
+
</ReactCake>
|
|
40
|
+
);
|
|
26
41
|
}
|
|
@@ -1,30 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useReactCake } from "../../../lib";
|
|
2
2
|
|
|
3
3
|
export default function Columns() {
|
|
4
4
|
const { data, x, xGet, yGet, xScale } = useReactCake();
|
|
5
5
|
|
|
6
|
-
console.log(data)
|
|
7
|
-
|
|
8
6
|
return (
|
|
9
7
|
<g className="column-group">
|
|
10
8
|
{data?.map((d) => {
|
|
9
|
+
const valueY = yGet(d);
|
|
10
|
+
const xGot = xGet(d);
|
|
11
|
+
const xPos = Array.isArray(xGot) ? xGot[0] : xGot;
|
|
12
|
+
const colWidth = xScale.bandwidth ? xScale.bandwidth() : 20;
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
stroke="#196c9e"
|
|
24
|
-
fill="none"
|
|
25
|
-
/>
|
|
14
|
+
return (
|
|
15
|
+
<rect
|
|
16
|
+
key={x(d)}
|
|
17
|
+
x={xPos}
|
|
18
|
+
y={100 - valueY}
|
|
19
|
+
width={colWidth}
|
|
20
|
+
height={valueY}
|
|
21
|
+
stroke="var(--blue-50)"
|
|
22
|
+
fill="none"
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
26
25
|
})}
|
|
27
26
|
</g>
|
|
28
|
-
|
|
29
|
-
)
|
|
27
|
+
);
|
|
30
28
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { Context } from "../ReactCake/";
|
|
3
|
+
import { type ContextValue } from "../ReactCake/types";
|
|
4
|
+
|
|
5
|
+
export default function GanttChart({ currentStep = null, highlight, maxDate, maxLegalDate }) {
|
|
6
|
+
const { x2, xGet, yGet, data, xScale, yScale, zGet } = useContext<ContextValue>(Context);
|
|
7
|
+
|
|
8
|
+
const scaledData = data.map((d, i) => {
|
|
9
|
+
const _maxDate =
|
|
10
|
+
d.kind === "construction" && maxLegalDate ? Math.min(maxLegalDate, maxDate) : maxDate;
|
|
11
|
+
|
|
12
|
+
const _x2 = x2(d) > _maxDate ? _maxDate : x2(d);
|
|
13
|
+
|
|
14
|
+
const fromStep = d.from_step || i;
|
|
15
|
+
const isActive = currentStep >= fromStep;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
...d,
|
|
19
|
+
width: isActive ? xScale(_x2) - xGet(d) : 0,
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return scaledData.map((d, i) => {
|
|
24
|
+
const x1 = xGet(d);
|
|
25
|
+
const y = yGet(d);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<rect
|
|
29
|
+
key={`gantt-${i}`}
|
|
30
|
+
x={x1}
|
|
31
|
+
y={y}
|
|
32
|
+
width={d.width}
|
|
33
|
+
height={yScale.bandwidth()}
|
|
34
|
+
fill={zGet(d) || "lightgray"}
|
|
35
|
+
className={`gantt-block ${currentStep > -1 && highlight[currentStep].includes(i) ? "current" : ""}`}
|
|
36
|
+
></rect>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { Context } from "../ReactCake/";
|
|
3
|
+
import { type ContextValue } from "../ReactCake/types";
|
|
4
|
+
|
|
5
|
+
interface OrdinalKeyProps {
|
|
6
|
+
shape?: "square" | "circle" | "line";
|
|
7
|
+
capitalise?: boolean;
|
|
8
|
+
format?: ((s: string | number) => string) | Record<string | number, string>;
|
|
9
|
+
align?: "start" | "center" | "end";
|
|
10
|
+
sort?: string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function cap(s: string) {
|
|
14
|
+
return String(s).replace(/^\w/, (d) => d.toUpperCase());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function OrdinalKey({
|
|
18
|
+
shape = "square",
|
|
19
|
+
align = "start",
|
|
20
|
+
sort = [],
|
|
21
|
+
format,
|
|
22
|
+
capitalise = true,
|
|
23
|
+
}: OrdinalKeyProps) {
|
|
24
|
+
const { zDomain, zScale } = useContext<ContextValue>(Context);
|
|
25
|
+
|
|
26
|
+
function displayName(val: string | number): string {
|
|
27
|
+
if (format) {
|
|
28
|
+
return typeof format === "function" ? format(val) : format[val] || val;
|
|
29
|
+
}
|
|
30
|
+
return capitalise === true ? cap(String(val)) : val;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className="ordinal-key" style={{ justifyContent: align === "end" ? "flex-end" : align }}>
|
|
35
|
+
{zDomain
|
|
36
|
+
.sort((a, b) => sort.indexOf(b.kind) - sort.indexOf(a.kind))
|
|
37
|
+
.map((d) => {
|
|
38
|
+
return (
|
|
39
|
+
<div className="key-item" key={d}>
|
|
40
|
+
<div
|
|
41
|
+
className={`chip chip__${shape}`}
|
|
42
|
+
style={{
|
|
43
|
+
background:
|
|
44
|
+
shape === `line`
|
|
45
|
+
? `linear-gradient(-45deg, var(--color-pageFill) 40%, ${zScale(d)} 41%, ${zScale(d)} 59%, var(--color-pageFill) 60%)`
|
|
46
|
+
: zScale(d),
|
|
47
|
+
}}
|
|
48
|
+
></div>
|
|
49
|
+
<p className="name">{displayName(d)}</p>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
})}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
.ordinal-key {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-flow: column;
|
|
4
|
+
color: var(--o3-color-palette-black-80);
|
|
5
|
+
font-family: var(--o3-font-family-metric);
|
|
6
|
+
gap: 0.5em;
|
|
7
|
+
background: var(--o3-color-palette-paper);
|
|
8
|
+
box-shadow: 0 0 10px 10px var(--o3-color-palette-paper);
|
|
9
|
+
|
|
10
|
+
* {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.key-item {
|
|
16
|
+
display: flex;
|
|
17
|
+
gap: 0.1em;
|
|
18
|
+
align-items: center;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.chip {
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
position: relative;
|
|
24
|
+
width: 12px;
|
|
25
|
+
height: 12px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.chip__circle {
|
|
29
|
+
border-radius: 50%;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.chip__line:after {
|
|
33
|
+
content: "";
|
|
34
|
+
position: absolute;
|
|
35
|
+
border-width: 3px;
|
|
36
|
+
width: 14px;
|
|
37
|
+
transform: rotate(-45deg);
|
|
38
|
+
transform-origin: 14px 5px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.name {
|
|
42
|
+
display: inline-block;
|
|
43
|
+
font-size: var(--o3-font-size-negative-2);
|
|
44
|
+
margin-left: 0.2em;
|
|
45
|
+
line-height: 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -26,6 +26,15 @@
|
|
|
26
26
|
width: 100%;
|
|
27
27
|
padding: 2rem 0;
|
|
28
28
|
font-family: sans-serif;
|
|
29
|
+
--blue-70: hsl(212, 70%, 26%);
|
|
30
|
+
--blue-50: hsl(212, 70%, 36%);
|
|
31
|
+
--blue-30: hsl(212, 50%, 76%);
|
|
32
|
+
--blue-10: hsl(212, 40%, 97%);
|
|
33
|
+
--ms--1: .8rem
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
a, a:visited {
|
|
37
|
+
color: var(--blue-70);
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
.content {
|
package/site/src/pages/index.mdx
CHANGED
package/site/tsconfig.json
CHANGED
package/site/.astro/content.d.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
declare module 'astro:content' {
|
|
2
|
-
interface Render {
|
|
3
|
-
'.mdx': Promise<{
|
|
4
|
-
Content: import('astro').MDXContent;
|
|
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
|
-
export 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
|
-
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
|
31
|
-
|
|
32
|
-
export type CollectionKey = keyof DataEntryMap;
|
|
33
|
-
export type CollectionEntry<C extends CollectionKey> = Flatten<DataEntryMap[C]>;
|
|
34
|
-
|
|
35
|
-
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
|
|
36
|
-
|
|
37
|
-
export type ReferenceDataEntry<
|
|
38
|
-
C extends CollectionKey,
|
|
39
|
-
E extends keyof DataEntryMap[C] = string,
|
|
40
|
-
> = {
|
|
41
|
-
collection: C;
|
|
42
|
-
id: E;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export type ReferenceLiveEntry<C extends keyof LiveContentConfig['collections']> = {
|
|
46
|
-
collection: C;
|
|
47
|
-
id: string;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export function getCollection<C extends keyof DataEntryMap, E extends CollectionEntry<C>>(
|
|
51
|
-
collection: C,
|
|
52
|
-
filter?: (entry: CollectionEntry<C>) => entry is E,
|
|
53
|
-
): Promise<E[]>;
|
|
54
|
-
export function getCollection<C extends keyof DataEntryMap>(
|
|
55
|
-
collection: C,
|
|
56
|
-
filter?: (entry: CollectionEntry<C>) => unknown,
|
|
57
|
-
): Promise<CollectionEntry<C>[]>;
|
|
58
|
-
|
|
59
|
-
export function getLiveCollection<C extends keyof LiveContentConfig['collections']>(
|
|
60
|
-
collection: C,
|
|
61
|
-
filter?: LiveLoaderCollectionFilterType<C>,
|
|
62
|
-
): Promise<
|
|
63
|
-
import('astro').LiveDataCollectionResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>
|
|
64
|
-
>;
|
|
65
|
-
|
|
66
|
-
export function getEntry<
|
|
67
|
-
C extends keyof DataEntryMap,
|
|
68
|
-
E extends keyof DataEntryMap[C] | (string & {}),
|
|
69
|
-
>(
|
|
70
|
-
entry: ReferenceDataEntry<C, E>,
|
|
71
|
-
): E extends keyof DataEntryMap[C]
|
|
72
|
-
? Promise<DataEntryMap[C][E]>
|
|
73
|
-
: Promise<CollectionEntry<C> | undefined>;
|
|
74
|
-
export function getEntry<
|
|
75
|
-
C extends keyof DataEntryMap,
|
|
76
|
-
E extends keyof DataEntryMap[C] | (string & {}),
|
|
77
|
-
>(
|
|
78
|
-
collection: C,
|
|
79
|
-
id: E,
|
|
80
|
-
): E extends keyof DataEntryMap[C]
|
|
81
|
-
? string extends keyof DataEntryMap[C]
|
|
82
|
-
? Promise<DataEntryMap[C][E]> | undefined
|
|
83
|
-
: Promise<DataEntryMap[C][E]>
|
|
84
|
-
: Promise<CollectionEntry<C> | undefined>;
|
|
85
|
-
export function getLiveEntry<C extends keyof LiveContentConfig['collections']>(
|
|
86
|
-
collection: C,
|
|
87
|
-
filter: string | LiveLoaderEntryFilterType<C>,
|
|
88
|
-
): Promise<import('astro').LiveDataEntryResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>>;
|
|
89
|
-
|
|
90
|
-
/** Resolve an array of entry references from the same collection */
|
|
91
|
-
export function getEntries<C extends keyof DataEntryMap>(
|
|
92
|
-
entries: ReferenceDataEntry<C, keyof DataEntryMap[C]>[],
|
|
93
|
-
): Promise<CollectionEntry<C>[]>;
|
|
94
|
-
|
|
95
|
-
export function render<C extends keyof DataEntryMap>(
|
|
96
|
-
entry: DataEntryMap[C][string],
|
|
97
|
-
): Promise<RenderResult>;
|
|
98
|
-
|
|
99
|
-
export function render<C extends keyof LiveContentConfig['collections']>(
|
|
100
|
-
entry: import('astro').LiveDataEntry<LiveLoaderDataType<C>>,
|
|
101
|
-
): Promise<RenderResult>;
|
|
102
|
-
|
|
103
|
-
export function reference<
|
|
104
|
-
C extends
|
|
105
|
-
| keyof DataEntryMap
|
|
106
|
-
// Allow generic `string` to avoid excessive type errors in the config
|
|
107
|
-
// if `dev` is not running to update as you edit.
|
|
108
|
-
// Invalid collection names will be caught at build time.
|
|
109
|
-
| (string & {}),
|
|
110
|
-
>(
|
|
111
|
-
collection: C,
|
|
112
|
-
): import('astro/zod').ZodPipe<
|
|
113
|
-
import('astro/zod').ZodString,
|
|
114
|
-
import('astro/zod').ZodTransform<
|
|
115
|
-
C extends keyof DataEntryMap
|
|
116
|
-
? {
|
|
117
|
-
collection: C;
|
|
118
|
-
id: string;
|
|
119
|
-
}
|
|
120
|
-
: never,
|
|
121
|
-
string
|
|
122
|
-
>
|
|
123
|
-
>;
|
|
124
|
-
|
|
125
|
-
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
|
|
126
|
-
type InferEntrySchema<C extends keyof DataEntryMap> = import('astro/zod').infer<
|
|
127
|
-
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
|
|
128
|
-
>;
|
|
129
|
-
type ExtractLoaderConfig<T> = T extends { loader: infer L } ? L : never;
|
|
130
|
-
type InferLoaderSchema<
|
|
131
|
-
C extends keyof DataEntryMap,
|
|
132
|
-
L = ExtractLoaderConfig<ContentConfig['collections'][C]>,
|
|
133
|
-
> = L extends { schema: import('astro/zod').ZodSchema }
|
|
134
|
-
? import('astro/zod').infer<L['schema']>
|
|
135
|
-
: any;
|
|
136
|
-
|
|
137
|
-
type DataEntryMap = {
|
|
138
|
-
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
type ExtractLoaderTypes<T> = T extends import('astro/loaders').LiveLoader<
|
|
142
|
-
infer TData,
|
|
143
|
-
infer TEntryFilter,
|
|
144
|
-
infer TCollectionFilter,
|
|
145
|
-
infer TError
|
|
146
|
-
>
|
|
147
|
-
? { data: TData; entryFilter: TEntryFilter; collectionFilter: TCollectionFilter; error: TError }
|
|
148
|
-
: { data: never; entryFilter: never; collectionFilter: never; error: never };
|
|
149
|
-
type ExtractEntryFilterType<T> = ExtractLoaderTypes<T>['entryFilter'];
|
|
150
|
-
type ExtractCollectionFilterType<T> = ExtractLoaderTypes<T>['collectionFilter'];
|
|
151
|
-
type ExtractErrorType<T> = ExtractLoaderTypes<T>['error'];
|
|
152
|
-
type ExtractDataType<T> = ExtractLoaderTypes<T>['data'];
|
|
153
|
-
|
|
154
|
-
type LiveLoaderDataType<C extends keyof LiveContentConfig['collections']> =
|
|
155
|
-
LiveContentConfig['collections'][C]['schema'] extends undefined
|
|
156
|
-
? ExtractDataType<LiveContentConfig['collections'][C]['loader']>
|
|
157
|
-
: import('astro/zod').infer<
|
|
158
|
-
Exclude<LiveContentConfig['collections'][C]['schema'], undefined>
|
|
159
|
-
>;
|
|
160
|
-
type LiveLoaderEntryFilterType<C extends keyof LiveContentConfig['collections']> =
|
|
161
|
-
ExtractEntryFilterType<LiveContentConfig['collections'][C]['loader']>;
|
|
162
|
-
type LiveLoaderCollectionFilterType<C extends keyof LiveContentConfig['collections']> =
|
|
163
|
-
ExtractCollectionFilterType<LiveContentConfig['collections'][C]['loader']>;
|
|
164
|
-
type LiveLoaderErrorType<C extends keyof LiveContentConfig['collections']> = ExtractErrorType<
|
|
165
|
-
LiveContentConfig['collections'][C]['loader']
|
|
166
|
-
>;
|
|
167
|
-
|
|
168
|
-
export type ContentConfig = never;
|
|
169
|
-
export type LiveContentConfig = never;
|
|
170
|
-
}
|
package/site/.astro/dev.json
DELETED
package/site/.astro/types.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// TKTK
|