@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,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared "unsaved changes" bar for settings pages: pinned to the bottom of
|
|
3
|
+
* the page's content column (position: sticky inside EmDash's scrolling
|
|
4
|
+
* <main>, so it never covers the sidebar) and shown only while the draft
|
|
5
|
+
* differs from what's saved. Ctrl/⌘+S saves, and leaving the page while
|
|
6
|
+
* dirty asks first.
|
|
7
|
+
*
|
|
8
|
+
* Place it as the LAST child of the page's root container. For a <form>,
|
|
9
|
+
* give the form an id and pass it as `form`: Save becomes that form's submit
|
|
10
|
+
* button (so Enter in a field still submits and native validation runs).
|
|
11
|
+
* Because it's sticky rather than fixed, it takes its own space at the end of
|
|
12
|
+
* the page and never hides the last field.
|
|
13
|
+
*/
|
|
14
|
+
import { Button } from "@cloudflare/kumo";
|
|
15
|
+
import { FloppyDisk } from "@phosphor-icons/react";
|
|
16
|
+
import * as React from "react";
|
|
17
|
+
|
|
18
|
+
import { SAVE_BAR_CSS } from "./admin-css.js";
|
|
19
|
+
|
|
20
|
+
export { isDirty } from "./dirty.js";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* While `dirty`: warn before leaving the page, and Ctrl/⌘+S calls `onSave`
|
|
24
|
+
* (when `canSave`). The browser's own Save dialog is suppressed whenever the
|
|
25
|
+
* page is mounted, dirty or not.
|
|
26
|
+
*/
|
|
27
|
+
export function useUnsavedChanges(dirty: boolean, onSave: () => void, canSave = true) {
|
|
28
|
+
const latest = React.useRef({ dirty, onSave, canSave });
|
|
29
|
+
latest.current = { dirty, onSave, canSave };
|
|
30
|
+
|
|
31
|
+
React.useEffect(() => {
|
|
32
|
+
if (!dirty) return;
|
|
33
|
+
const warn = (event: BeforeUnloadEvent) => event.preventDefault();
|
|
34
|
+
window.addEventListener("beforeunload", warn);
|
|
35
|
+
return () => window.removeEventListener("beforeunload", warn);
|
|
36
|
+
}, [dirty]);
|
|
37
|
+
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
const onKey = (event: KeyboardEvent) => {
|
|
40
|
+
if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey || event.key.toLowerCase() !== "s") return;
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
const { dirty: isDirtyNow, onSave: save, canSave: ok } = latest.current;
|
|
43
|
+
if (isDirtyNow && ok && !event.repeat) save();
|
|
44
|
+
};
|
|
45
|
+
window.addEventListener("keydown", onKey);
|
|
46
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
47
|
+
}, []);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function SaveBar(props: {
|
|
51
|
+
dirty: boolean;
|
|
52
|
+
saving: boolean;
|
|
53
|
+
/** False when the draft is invalid (the page's own validity rules). */
|
|
54
|
+
canSave?: boolean;
|
|
55
|
+
/** Called by Save and Ctrl/⌘+S. With `form`, that form is submitted instead (its onSubmit saves). */
|
|
56
|
+
onSave?: () => void;
|
|
57
|
+
onDiscard: () => void;
|
|
58
|
+
/** Extra context after "Unsaved changes", e.g. what saving also does. */
|
|
59
|
+
detail?: React.ReactNode;
|
|
60
|
+
/** Label for the Save button (default "Save"). */
|
|
61
|
+
label?: string;
|
|
62
|
+
/** Id of the <form> whose submit button Save is. */
|
|
63
|
+
form?: string;
|
|
64
|
+
}) {
|
|
65
|
+
const canSave = props.canSave ?? true;
|
|
66
|
+
const { onSave, form, saving } = props;
|
|
67
|
+
const save = React.useCallback(() => {
|
|
68
|
+
if (saving) return;
|
|
69
|
+
if (form) (document.getElementById(form) as HTMLFormElement | null)?.requestSubmit();
|
|
70
|
+
else onSave?.();
|
|
71
|
+
}, [onSave, form, saving]);
|
|
72
|
+
useUnsavedChanges(props.dirty, save, canSave);
|
|
73
|
+
|
|
74
|
+
// Sticky bottom: 0 stops at the top of the scroll container's bottom padding
|
|
75
|
+
// (EmDash's <main> has p-6), leaving a strip of page showing under the bar.
|
|
76
|
+
// Offset by that padding so the bar sits flush with the bottom edge.
|
|
77
|
+
const bar = React.useRef<HTMLDivElement>(null);
|
|
78
|
+
const [offset, setOffset] = React.useState(0);
|
|
79
|
+
React.useLayoutEffect(() => {
|
|
80
|
+
if (!props.dirty || !bar.current) return;
|
|
81
|
+
let node: HTMLElement | null = bar.current.parentElement;
|
|
82
|
+
while (node && !/(auto|scroll)/.test(getComputedStyle(node).overflowY)) node = node.parentElement;
|
|
83
|
+
setOffset(node ? Number.parseFloat(getComputedStyle(node).paddingBottom) || 0 : 0);
|
|
84
|
+
}, [props.dirty]);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<>
|
|
88
|
+
{/* Always rendered so the change is announced when the bar appears. */}
|
|
89
|
+
<p className="sr-only" role="status" aria-live="polite">
|
|
90
|
+
{props.dirty ? "Unsaved changes" : ""}
|
|
91
|
+
</p>
|
|
92
|
+
{props.dirty && (
|
|
93
|
+
<div
|
|
94
|
+
ref={bar}
|
|
95
|
+
className="cw-save-bar flex flex-wrap items-center justify-between gap-3 border border-kumo-line bg-kumo-base"
|
|
96
|
+
role="region"
|
|
97
|
+
aria-label="Unsaved changes"
|
|
98
|
+
style={{
|
|
99
|
+
position: "sticky",
|
|
100
|
+
bottom: -offset,
|
|
101
|
+
zIndex: 20,
|
|
102
|
+
borderBottom: "none",
|
|
103
|
+
borderTopLeftRadius: 8,
|
|
104
|
+
borderTopRightRadius: 8,
|
|
105
|
+
padding: "12px 16px",
|
|
106
|
+
paddingBottom: "calc(12px + env(safe-area-inset-bottom, 0px))",
|
|
107
|
+
boxShadow: "0 -4px 12px -6px rgba(0, 0, 0, 0.18)",
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
<style>{SAVE_BAR_CSS}</style>
|
|
111
|
+
<div className="min-w-0 text-sm">
|
|
112
|
+
<span className="font-medium">Unsaved changes</span>
|
|
113
|
+
{props.detail && <span className="text-kumo-subtle"> · {props.detail}</span>}
|
|
114
|
+
</div>
|
|
115
|
+
<div className="flex shrink-0 gap-2">
|
|
116
|
+
<Button type="button" variant="secondary" disabled={props.saving} onClick={props.onDiscard}>
|
|
117
|
+
Discard
|
|
118
|
+
</Button>
|
|
119
|
+
<Button
|
|
120
|
+
type={form ? "submit" : "button"}
|
|
121
|
+
form={form}
|
|
122
|
+
variant="primary"
|
|
123
|
+
icon={<FloppyDisk />}
|
|
124
|
+
disabled={props.saving || !canSave}
|
|
125
|
+
onClick={form ? undefined : save}
|
|
126
|
+
>
|
|
127
|
+
{props.saving ? "Saving…" : (props.label ?? "Save")}
|
|
128
|
+
</Button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
)}
|
|
132
|
+
</>
|
|
133
|
+
);
|
|
134
|
+
}
|