@coywolf/emdash 0.0.0-stage → 0.35.14
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 +21 -0
- package/README.md +203 -2
- package/docs/README.md +45 -0
- package/docs/ai.md +39 -0
- package/docs/backups.md +88 -0
- package/docs/breadcrumbs.md +59 -0
- package/docs/code-blocks.md +21 -0
- package/docs/content-urls.md +41 -0
- package/docs/custom-blocks.md +27 -0
- package/docs/discovery.md +32 -0
- package/docs/files.md +44 -0
- package/docs/form-uploads.md +59 -0
- package/docs/headings.md +37 -0
- package/docs/images.md +141 -0
- package/docs/internals.md +13 -0
- package/docs/links.md +34 -0
- package/docs/performance.md +72 -0
- package/docs/redirects.md +84 -0
- package/docs/releasing.md +21 -0
- package/docs/reviews.md +89 -0
- package/docs/robots.md +81 -0
- package/docs/schema.md +79 -0
- package/docs/search.md +114 -0
- package/docs/videos.md +48 -0
- package/docs/wordpress-import.md +198 -0
- package/package.json +79 -5
- package/src/admin/admin-css.ts +57 -0
- package/src/admin/ai.tsx +915 -0
- package/src/admin/backups.tsx +613 -0
- package/src/admin/breadcrumbs.tsx +542 -0
- package/src/admin/codeBlocks.tsx +204 -0
- package/src/admin/customBlocks.tsx +321 -0
- package/src/admin/dirty.ts +20 -0
- package/src/admin/discovery.tsx +463 -0
- package/src/admin/download.ts +28 -0
- package/src/admin/feature-switches.tsx +124 -0
- package/src/admin/features.tsx +142 -0
- package/src/admin/files.tsx +791 -0
- package/src/admin/formUploads.tsx +445 -0
- package/src/admin/guides.tsx +18 -0
- package/src/admin/headings.tsx +262 -0
- package/src/admin/images.tsx +825 -0
- package/src/admin/index.tsx +62 -0
- package/src/admin/links.tsx +980 -0
- package/src/admin/performance.tsx +330 -0
- package/src/admin/preview.tsx +63 -0
- package/src/admin/redirects-removed.tsx +266 -0
- package/src/admin/redirects.tsx +470 -0
- package/src/admin/reviews.tsx +232 -0
- package/src/admin/robots-bots.tsx +647 -0
- package/src/admin/robots-shared.tsx +109 -0
- package/src/admin/robots-wizard.tsx +748 -0
- package/src/admin/robots.tsx +911 -0
- package/src/admin/save-bar.tsx +134 -0
- package/src/admin/schema.tsx +1187 -0
- package/src/admin/search.tsx +355 -0
- package/src/admin/settings-ui.tsx +87 -0
- package/src/admin/trash-prompt-core.ts +135 -0
- package/src/admin/trash-prompt.tsx +156 -0
- package/src/admin/usage.tsx +301 -0
- package/src/admin/videos-display.tsx +248 -0
- package/src/admin/videos.tsx +1202 -0
- package/src/admin/wpImport.tsx +1516 -0
- package/src/ai/entities.ts +59 -0
- package/src/ai/export.ts +61 -0
- package/src/ai/logic.ts +606 -0
- package/src/ai/pack.ts +121 -0
- package/src/ai/prompts.ts +87 -0
- package/src/ai/providers.ts +276 -0
- package/src/ai/routes.ts +359 -0
- package/src/ai/store.ts +301 -0
- package/src/ai/wikidata.ts +87 -0
- package/src/ai/worker.ts +530 -0
- package/src/astro/astro-modules.d.ts +6 -0
- package/src/astro/breadcrumbs/Breadcrumbs.astro +129 -0
- package/src/astro/breadcrumbs/BreadcrumbsBlock.astro +12 -0
- package/src/astro/codeBlocks/CodeBlock.astro +62 -0
- package/src/astro/codeBlocks/EmDashCode.astro +61 -0
- package/src/astro/customBlocks/CustomBlock.astro +64 -0
- package/src/astro/customBlocks/Details.astro +8 -0
- package/src/astro/customBlocks/Disclosure.astro +8 -0
- package/src/astro/customBlocks/Note.astro +8 -0
- package/src/astro/customBlocks/Podcast.astro +8 -0
- package/src/astro/customBlocks/Quote.astro +8 -0
- package/src/astro/customBlocks/Testimonial.astro +8 -0
- package/src/astro/files/FileCard.astro +103 -0
- package/src/astro/headings/HeadingBlock.astro +129 -0
- package/src/astro/headings/TableOfContents.astro +45 -0
- package/src/astro/headings/request.ts +19 -0
- package/src/astro/images/ResponsiveImage.astro +60 -0
- package/src/astro/index.ts +84 -0
- package/src/astro/reviews/CoywolfReview.astro +27 -0
- package/src/astro/reviews/Review.astro +49 -0
- package/src/astro/search/SearchBox.astro +61 -0
- package/src/astro/search/SearchBoxForm.astro +509 -0
- package/src/astro/tables/CaptionedTable.astro +72 -0
- package/src/astro/videos/CoywolfVideo.astro +448 -0
- package/src/backups/download.ts +112 -0
- package/src/backups/dump.ts +288 -0
- package/src/backups/module.ts +276 -0
- package/src/backups/pack.ts +33 -0
- package/src/backups/restore.ts +209 -0
- package/src/backups/store.ts +409 -0
- package/src/breadcrumbs/pack.ts +113 -0
- package/src/breadcrumbs/settings.ts +102 -0
- package/src/breadcrumbs/stamp.ts +40 -0
- package/src/breadcrumbs/trail.ts +123 -0
- package/src/codeBlocks/contrast.ts +179 -0
- package/src/codeBlocks/hljs.d.ts +5 -0
- package/src/codeBlocks/pack.ts +110 -0
- package/src/codeBlocks/render.ts +304 -0
- package/src/codeBlocks/settings.ts +18 -0
- package/src/codeBlocks/themes.generated.ts +304 -0
- package/src/codeBlocks/themes.ts +114 -0
- package/src/core/compose.ts +244 -0
- package/src/core/content-url.ts +888 -0
- package/src/core/csv.ts +119 -0
- package/src/core/d1-batch.ts +65 -0
- package/src/core/entry-docs.ts +175 -0
- package/src/core/features-module.ts +48 -0
- package/src/core/features.ts +392 -0
- package/src/core/generation.ts +88 -0
- package/src/core/guide-content.ts +166 -0
- package/src/core/module.ts +104 -0
- package/src/core/read-failures.ts +57 -0
- package/src/core/request-memo.ts +71 -0
- package/src/core/secrets.ts +83 -0
- package/src/core/settings-enhance.ts +74 -0
- package/src/core/site.ts +36 -0
- package/src/core/storage.ts +27 -0
- package/src/customBlocks/pack.ts +260 -0
- package/src/customBlocks/render.ts +424 -0
- package/src/customBlocks/rich.ts +313 -0
- package/src/customBlocks/settings.ts +46 -0
- package/src/discovery/build.ts +252 -0
- package/src/discovery/feed-build.ts +217 -0
- package/src/discovery/feed.ts +172 -0
- package/src/discovery/indexnow.ts +114 -0
- package/src/discovery/llms.ts +79 -0
- package/src/discovery/markdown.ts +294 -0
- package/src/discovery/memory-cache.ts +97 -0
- package/src/discovery/middleware.ts +186 -0
- package/src/discovery/module.ts +353 -0
- package/src/discovery/news.ts +99 -0
- package/src/discovery/pack.ts +58 -0
- package/src/discovery/settings.ts +91 -0
- package/src/discovery/urls.ts +35 -0
- package/src/env.d.ts +10 -0
- package/src/files/card.ts +231 -0
- package/src/files/counts.ts +60 -0
- package/src/files/export.ts +44 -0
- package/src/files/format.ts +163 -0
- package/src/files/module.ts +596 -0
- package/src/files/pack.ts +92 -0
- package/src/files/r2-rules.ts +41 -0
- package/src/files/range.ts +50 -0
- package/src/files/s3.ts +114 -0
- package/src/files/serve.ts +141 -0
- package/src/files/sigv4.ts +160 -0
- package/src/files/site.ts +137 -0
- package/src/files/walker.ts +58 -0
- package/src/formUploads/lib.ts +266 -0
- package/src/formUploads/pack.ts +55 -0
- package/src/formUploads/wrap.ts +592 -0
- package/src/forms.ts +16 -0
- package/src/headings/pack.ts +154 -0
- package/src/headings/render.ts +139 -0
- package/src/headings/settings.ts +117 -0
- package/src/headings/slug.ts +68 -0
- package/src/headings/stamp.ts +142 -0
- package/src/headings/test-hooks.mjs +14 -0
- package/src/headings/toc.ts +48 -0
- package/src/images/cloudflare.ts +329 -0
- package/src/images/lib.ts +221 -0
- package/src/images/module.ts +372 -0
- package/src/images/pack.ts +804 -0
- package/src/images/pending.ts +37 -0
- package/src/images/settings.ts +48 -0
- package/src/images/setup.ts +192 -0
- package/src/images/variants-estimate.ts +162 -0
- package/src/images/variants-store.ts +475 -0
- package/src/images/variants.ts +311 -0
- package/src/index.ts +143 -0
- package/src/links/check.ts +101 -0
- package/src/links/classify.ts +270 -0
- package/src/links/export.ts +59 -0
- package/src/links/module.ts +652 -0
- package/src/links/pack.ts +43 -0
- package/src/links/pt.ts +325 -0
- package/src/links/store.ts +704 -0
- package/src/middleware.ts +287 -0
- package/src/modules.ts +53 -0
- package/src/options.ts +66 -0
- package/src/pageCache/lib.ts +274 -0
- package/src/pageCache/pack.ts +240 -0
- package/src/pageCache/usage-core.ts +152 -0
- package/src/pageCache/usage.ts +262 -0
- package/src/pageCache/warm.ts +722 -0
- package/src/redirects/middleware.ts +169 -0
- package/src/redirects/module.ts +124 -0
- package/src/redirects/pack.ts +89 -0
- package/src/redirects/removed-core.ts +151 -0
- package/src/redirects/removed.ts +293 -0
- package/src/redirects/rules.ts +355 -0
- package/src/redirects/slug-changes.ts +207 -0
- package/src/redirects/slug-core.ts +49 -0
- package/src/redirects/transfer.ts +92 -0
- package/src/reviews/lib.ts +624 -0
- package/src/reviews/pack.ts +135 -0
- package/src/reviews/schema.ts +128 -0
- package/src/reviews/settings.ts +26 -0
- package/src/robots/bots.ts +321 -0
- package/src/robots/data/bots.json +696 -0
- package/src/robots/data/verified.json +582 -0
- package/src/robots/directory.ts +26 -0
- package/src/robots/explain.ts +191 -0
- package/src/robots/guided.ts +300 -0
- package/src/robots/importer.ts +263 -0
- package/src/robots/middleware.ts +151 -0
- package/src/robots/module.ts +446 -0
- package/src/robots/pack.ts +69 -0
- package/src/robots/radar.ts +129 -0
- package/src/robots/rep.ts +362 -0
- package/src/robots/rules.ts +883 -0
- package/src/robots/transfer.ts +45 -0
- package/src/robots/validate.ts +524 -0
- package/src/schema/catalog.ts +146 -0
- package/src/schema/graph.ts +791 -0
- package/src/schema/module.ts +1138 -0
- package/src/schema/og-image.ts +100 -0
- package/src/schema/pack.ts +58 -0
- package/src/search/engine.ts +578 -0
- package/src/search/fallback.ts +80 -0
- package/src/search/live-cache.ts +116 -0
- package/src/search/live-client.ts +770 -0
- package/src/search/live-serve.ts +282 -0
- package/src/search/module.ts +261 -0
- package/src/search/pack.ts +57 -0
- package/src/search/query.ts +132 -0
- package/src/search/ratelimit-core.ts +118 -0
- package/src/search/ratelimit.ts +79 -0
- package/src/search/snippet.ts +135 -0
- package/src/search/title-index.ts +139 -0
- package/src/search/title-match.ts +192 -0
- package/src/shared.ts +71 -0
- package/src/version.ts +2 -0
- package/src/videos/date.ts +40 -0
- package/src/videos/engagement.ts +75 -0
- package/src/videos/lib.ts +679 -0
- package/src/videos/module.ts +1160 -0
- package/src/videos/pack.ts +187 -0
- package/src/videos/pause.ts +42 -0
- package/src/videos/poster.ts +324 -0
- package/src/videos/render.ts +336 -0
- package/src/videos/store.ts +551 -0
- package/src/videos/stream.ts +134 -0
- package/src/wpImport/convert.ts +702 -0
- package/src/wpImport/guests.ts +329 -0
- package/src/wpImport/gutenberg.ts +157 -0
- package/src/wpImport/markers.ts +66 -0
- package/src/wpImport/pack.ts +451 -0
- package/src/wpImport/parents.ts +202 -0
- package/src/wpImport/prepare.ts +592 -0
- package/src/wpImport/redirects.ts +358 -0
- package/src/wpImport/sources.ts +67 -0
- package/src/wpImport/stream.ts +160 -0
- package/src/wpImport/urls.ts +354 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reviews page: the review box's accent color and custom CSS, with a live
|
|
3
|
+
* preview of a sample review (rendered by the same code as the site).
|
|
4
|
+
* Turning Reviews on or off happens on the Features page.
|
|
5
|
+
*/
|
|
6
|
+
import { Banner, Button, Input, InputArea, Loader } from "@cloudflare/kumo";
|
|
7
|
+
import { ArrowCounterClockwise, FloppyDisk } from "@phosphor-icons/react";
|
|
8
|
+
import { apiFetch, parseApiResponse } from "emdash/plugin-utils";
|
|
9
|
+
import * as React from "react";
|
|
10
|
+
|
|
11
|
+
import { SaveBar } from "./save-bar.js";
|
|
12
|
+
import { DEFAULT_ACCENT, MAX_CUSTOM_CSS, SAMPLE_REVIEW, isAccent, pageCss, renderReviewHtml, sanitizeCustomCss } from "../reviews/lib.js";
|
|
13
|
+
import { PartSwitches } from "./feature-switches.js";
|
|
14
|
+
|
|
15
|
+
const API = "/_emdash/api/plugins/coywolf-pack";
|
|
16
|
+
|
|
17
|
+
interface Style {
|
|
18
|
+
accent: string;
|
|
19
|
+
css: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const EXAMPLE_CSS = `/* Target .cw-review … so rules only reach review boxes. */
|
|
24
|
+
.cw-review {
|
|
25
|
+
--cw-review-accent: #b22d47;
|
|
26
|
+
--cw-review-column-min: 100%; /* one column */
|
|
27
|
+
}`;
|
|
28
|
+
|
|
29
|
+
const errorText = (cause: unknown, fallback: string) => (cause instanceof Error && cause.message ? cause.message : fallback);
|
|
30
|
+
|
|
31
|
+
async function post<T>(path: string, body: unknown, fallback: string): Promise<T> {
|
|
32
|
+
const response = await apiFetch(`${API}/${path}`, {
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: { "Content-Type": "application/json" },
|
|
35
|
+
body: JSON.stringify(body),
|
|
36
|
+
});
|
|
37
|
+
return parseApiResponse<T>(response, fallback);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The sample review in an isolated frame, so custom CSS can't restyle this admin page. */
|
|
41
|
+
function Preview({ style, width }: { style: Style; width: "wide" | "phone" }) {
|
|
42
|
+
const frame = React.useRef<HTMLIFrameElement>(null);
|
|
43
|
+
const [height, setHeight] = React.useState(320);
|
|
44
|
+
const doc = React.useMemo(() => {
|
|
45
|
+
const css = pageCss({ accent: isAccent(style.accent) ? style.accent : DEFAULT_ACCENT, css: sanitizeCustomCss(style.css) });
|
|
46
|
+
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>html{color-scheme:light dark}body{margin:0;padding:16px;font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;line-height:1.5;background:Canvas;color:CanvasText}</style><style>${css}</style></head><body>${renderReviewHtml(SAMPLE_REVIEW)}</body></html>`;
|
|
47
|
+
}, [style.accent, style.css]);
|
|
48
|
+
const measure = () => {
|
|
49
|
+
const body = frame.current?.contentDocument?.documentElement;
|
|
50
|
+
if (body) setHeight(Math.min(1200, Math.max(120, body.scrollHeight)));
|
|
51
|
+
};
|
|
52
|
+
return (
|
|
53
|
+
<iframe
|
|
54
|
+
ref={frame}
|
|
55
|
+
title="Review box preview"
|
|
56
|
+
// No scripts; same origin only so the frame's height can be measured.
|
|
57
|
+
sandbox="allow-same-origin"
|
|
58
|
+
srcDoc={doc}
|
|
59
|
+
onLoad={measure}
|
|
60
|
+
className="block rounded-lg border border-kumo-line bg-white"
|
|
61
|
+
style={{ width: width === "phone" ? 375 : "100%", maxWidth: "100%", height }}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function ReviewsPage() {
|
|
67
|
+
const [saved, setSaved] = React.useState<{ style: Style } | null>(null);
|
|
68
|
+
const [style, setStyle] = React.useState<Style>({ accent: DEFAULT_ACCENT, css: "" });
|
|
69
|
+
const [width, setWidth] = React.useState<"wide" | "phone">("wide");
|
|
70
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
71
|
+
const [status, setStatus] = React.useState("");
|
|
72
|
+
const [saving, setSaving] = React.useState(false);
|
|
73
|
+
|
|
74
|
+
React.useEffect(() => {
|
|
75
|
+
void (async () => {
|
|
76
|
+
try {
|
|
77
|
+
const settings = await apiFetch(`${API}/reviews/settings`).then((r) => parseApiResponse<Style>(r, "Couldn't load settings"));
|
|
78
|
+
const loaded = { accent: settings.accent, css: settings.css };
|
|
79
|
+
setStyle(loaded);
|
|
80
|
+
setSaved({ style: loaded });
|
|
81
|
+
} catch (cause) {
|
|
82
|
+
setError(errorText(cause, "Couldn't load settings"));
|
|
83
|
+
}
|
|
84
|
+
})();
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
const styleDirty = saved !== null && (style.accent !== saved.style.accent || style.css !== saved.style.css);
|
|
88
|
+
const dirty = styleDirty;
|
|
89
|
+
const accentValid = isAccent(style.accent);
|
|
90
|
+
const tooLong = style.css.length > MAX_CUSTOM_CSS;
|
|
91
|
+
|
|
92
|
+
async function save() {
|
|
93
|
+
if (!saved || !accentValid || tooLong) return;
|
|
94
|
+
setSaving(true);
|
|
95
|
+
setError(null);
|
|
96
|
+
setStatus("Saving…");
|
|
97
|
+
try {
|
|
98
|
+
let next = style;
|
|
99
|
+
if (styleDirty) next = await post<Style>("reviews/save", style, "Couldn't save the style");
|
|
100
|
+
setStyle(next);
|
|
101
|
+
setSaved({ style: next });
|
|
102
|
+
setStatus("Saved. The site picks up changes within a minute.");
|
|
103
|
+
} catch (cause) {
|
|
104
|
+
setStatus("");
|
|
105
|
+
setError(errorText(cause, "Couldn't save"));
|
|
106
|
+
} finally {
|
|
107
|
+
setSaving(false);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div className="space-y-6">
|
|
113
|
+
<header className="grid min-w-0 gap-4 border-b border-kumo-line pb-4">
|
|
114
|
+
<div className="grid grid-cols-[minmax(0,1fr)_auto] items-start gap-x-3 gap-y-1">
|
|
115
|
+
<h1 className="flex min-h-9 min-w-0 items-center text-2xl font-semibold leading-tight">Reviews</h1>
|
|
116
|
+
<div className="flex shrink-0 justify-end">
|
|
117
|
+
<Button variant="primary" icon={<FloppyDisk />} disabled={!dirty || saving || !accentValid || tooLong} onClick={() => void save()}>
|
|
118
|
+
Save
|
|
119
|
+
</Button>
|
|
120
|
+
</div>
|
|
121
|
+
<p className="col-span-2 text-sm leading-5 text-pretty text-kumo-subtle">
|
|
122
|
+
Add a review to an entry with the Coywolf Review block: a rating badge, what you liked most, and what could be better.
|
|
123
|
+
The box is styled with plain CSS sent only on pages with a review; no script.
|
|
124
|
+
</p>
|
|
125
|
+
</div>
|
|
126
|
+
</header>
|
|
127
|
+
|
|
128
|
+
<PartSwitches module="reviews" />
|
|
129
|
+
|
|
130
|
+
{error && <Banner variant="error" role="alert" description={error} />}
|
|
131
|
+
<p className="sr-only" role="status" aria-live="polite">
|
|
132
|
+
{status}
|
|
133
|
+
</p>
|
|
134
|
+
{status && !saving && <p className="text-sm text-kumo-subtle">{status}</p>}
|
|
135
|
+
|
|
136
|
+
{!saved && !error && (
|
|
137
|
+
<div className="flex justify-center py-12">
|
|
138
|
+
<Loader />
|
|
139
|
+
</div>
|
|
140
|
+
)}
|
|
141
|
+
|
|
142
|
+
{saved && (
|
|
143
|
+
<div className="grid gap-6 cw-lg-cols-24-fill">
|
|
144
|
+
<div className="space-y-6">
|
|
145
|
+
<div className="space-y-2">
|
|
146
|
+
<div className="flex items-end gap-2">
|
|
147
|
+
<input
|
|
148
|
+
type="color"
|
|
149
|
+
aria-label="Pick the accent color"
|
|
150
|
+
value={accentValid && style.accent.length === 7 ? style.accent : DEFAULT_ACCENT}
|
|
151
|
+
onChange={(e) => setStyle((cur) => ({ ...cur, accent: e.target.value }))}
|
|
152
|
+
className="h-9 w-12 shrink-0 cursor-pointer rounded border border-kumo-line bg-transparent p-0.5"
|
|
153
|
+
/>
|
|
154
|
+
<div className="min-w-0 flex-1">
|
|
155
|
+
<Input
|
|
156
|
+
label="Accent color (rating badge)"
|
|
157
|
+
value={style.accent}
|
|
158
|
+
aria-invalid={!accentValid}
|
|
159
|
+
aria-describedby={accentValid ? undefined : "cw-reviews-accent-error"}
|
|
160
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setStyle((cur) => ({ ...cur, accent: e.target.value.trim() }))}
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
<Button
|
|
164
|
+
variant="secondary"
|
|
165
|
+
icon={<ArrowCounterClockwise />}
|
|
166
|
+
disabled={style.accent === DEFAULT_ACCENT}
|
|
167
|
+
onClick={() => setStyle((cur) => ({ ...cur, accent: DEFAULT_ACCENT }))}
|
|
168
|
+
>
|
|
169
|
+
Default
|
|
170
|
+
</Button>
|
|
171
|
+
</div>
|
|
172
|
+
{!accentValid && (
|
|
173
|
+
<p id="cw-reviews-accent-error" className="text-sm text-kumo-danger" role="alert">
|
|
174
|
+
Use a hex color like {DEFAULT_ACCENT}.
|
|
175
|
+
</p>
|
|
176
|
+
)}
|
|
177
|
+
<p className="text-xs text-kumo-subtle">Badge text is white; pick a color dark enough to read it.</p>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<div className="space-y-2">
|
|
181
|
+
<InputArea
|
|
182
|
+
label="Custom CSS"
|
|
183
|
+
rows={10}
|
|
184
|
+
value={style.css}
|
|
185
|
+
placeholder={EXAMPLE_CSS}
|
|
186
|
+
spellCheck={false}
|
|
187
|
+
className="font-mono text-xs"
|
|
188
|
+
aria-invalid={tooLong || undefined}
|
|
189
|
+
aria-describedby="cw-reviews-css-limit"
|
|
190
|
+
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setStyle((cur) => ({ ...cur, css: e.target.value }))}
|
|
191
|
+
/>
|
|
192
|
+
<p id="cw-reviews-css-limit" className={`text-xs ${tooLong ? "text-kumo-danger" : "text-kumo-subtle"}`}>
|
|
193
|
+
{style.css.length.toLocaleString()} / {MAX_CUSTOM_CSS.toLocaleString()} characters. Added after the built-in styles on pages
|
|
194
|
+
with a review. Start rules with <code>.cw-review</code> and set the <code>--cw-review-*</code> properties (see docs/reviews.md in the Coywolf Pack repository) to
|
|
195
|
+
change colors and layout.
|
|
196
|
+
</p>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<section aria-labelledby="cw-review-preview-title" className="min-w-0">
|
|
201
|
+
<div className="mb-2 flex items-center justify-between gap-2">
|
|
202
|
+
<h2 id="cw-review-preview-title" className="text-sm font-medium">
|
|
203
|
+
Preview
|
|
204
|
+
</h2>
|
|
205
|
+
<div className="flex gap-1" role="group" aria-label="Preview width">
|
|
206
|
+
<Button size="sm" variant={width === "wide" ? "primary" : "secondary"} aria-pressed={width === "wide"} onClick={() => setWidth("wide")}>
|
|
207
|
+
Wide
|
|
208
|
+
</Button>
|
|
209
|
+
<Button size="sm" variant={width === "phone" ? "primary" : "secondary"} aria-pressed={width === "phone"} onClick={() => setWidth("phone")}>
|
|
210
|
+
Phone
|
|
211
|
+
</Button>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
<Preview style={style} width={width} />
|
|
215
|
+
<p className="mt-2 text-xs text-kumo-subtle">
|
|
216
|
+
The preview uses this page's fonts and your computer's light or dark setting. On the site the box uses your theme's fonts
|
|
217
|
+
and text color, and turns dark only if the theme supports dark mode (its color-scheme).
|
|
218
|
+
</p>
|
|
219
|
+
</section>
|
|
220
|
+
</div>
|
|
221
|
+
)}
|
|
222
|
+
|
|
223
|
+
<SaveBar
|
|
224
|
+
dirty={dirty}
|
|
225
|
+
saving={saving}
|
|
226
|
+
canSave={accentValid && !tooLong}
|
|
227
|
+
onSave={() => void save()}
|
|
228
|
+
onDiscard={() => saved && setStyle(saved.style)}
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|