* Add OG Image field to content editor
The `_emdash_seo` table and content API already support `seo_image`, but
the admin UI had no way to set it. This adds:
- `SeoImageField` component using the existing `MediaPickerModal`
- 2-column grid layout placing the OG Image next to the Featured Image
- `description` prop on `ImageFieldRenderer` for helper text below images
- Preserve `seo.image` in `SeoPanel.emitChange` so sidebar edits don't
clear the image
Closes#327
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: format
* Add changeset and fix stale seo.image in SeoPanel
- Add changeset for @emdash-cms/admin patch release
- Remove image from SeoPanel.emitChange to avoid overwriting
a freshly-selected OG image with a stale prop value
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review feedback on OG Image field
- Fix#1: Use @phosphor-icons/react instead of lucide-react
- Fix#2: Send minimal patch { image } instead of spreading stale seo props
- Fix#3: Only show OG Image next to the featured_image field, not all image fields
- Fix#4: Only add description text for the featured_image field
- Fix#5: Add responsive breakpoint (grid-cols-1 md:grid-cols-2)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: format
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
Override the fixed h-6.5 from Kumo's sm size with h-auto and py-1 so
the button sizes naturally around the avatar. The sm size is still used
for text size, gap, and border-radius — only the height is overridden,
since this is a usage-specific concern (tall content inside a small
button) rather than a design system issue.
Co-authored-by: Matt Kane <mkane@cloudflare.com>
* Hide preview button unless collection supports preview and content is published
* Remove isPublished check
---------
Co-authored-by: Matt Kane <mkane@cloudflare.com>
* fix(admin): avoid locally caught exception in PasskeyLogin
Why:
The passkey login flow threw an error when navigator.credentials.get()
returned no credential, but that exception was immediately caught by the
local catch block in the same function. This triggered a
"throw of exception caught locally" warning and made the failure path
less direct.
What:
- Handle the missing credential case inline instead of throwing locally
- Preserve the existing error message shown to the user
- Keep the onError callback behavior unchanged
* Add changeset
---------
Co-authored-by: Matt Kane <m@mk.gg>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
* Add Back navigation to Security and Domain settings pages
* changeset
---------
Co-authored-by: Matt Kane <mkane@cloudflare.com>
Co-authored-by: Matt Kane <m@mk.gg>
Wire up @dnd-kit sortable integration in ContentTypeEditor and connect the existing reorderFields API. The grab handle icon was visual-only with no drag functionality attached.
Closes#43
Co-authored-by: Matt Kane <mkane@cloudflare.com>
When theme is "system", ThemeProvider removed the data-mode attribute
from <html>, expecting color-scheme: light dark to handle dark mode.
However, Tailwind dark: utilities are mapped to [data-mode="dark"] via
@custom-variant and do not respond to color-scheme, so dark mode never
activated for system preference users.
Decouple DOM synchronization from the theme preference by syncing
data-mode with resolvedTheme instead. This ensures data-mode is always
set to "light" or "dark" regardless of whether the user chose explicitly
or follows system preference.
Fixes#96
Co-authored-by: Matt Kane <mkane@cloudflare.com>
* fix: passkeys behind TLS reverse proxy
Add passkeyPublicOrigin and wire it through passkey routes so origin/rpId match
the browser when dev runs behind nginx. Expose dev-only /_emdash/api/dev/passkey-url,
add admin messaging for insecure WebAuthn contexts, nginx repro under demos/simple,
and direct kysely dependency for the simple demo Node adapter bundle.
Made-with: Cursor
* docs: add passkeyPublicOrigin to configuration reference
Adds the new passkeyPublicOrigin option and reverse proxy guidance
to the public-facing configuration docs as requested in PR review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* update tests and more docs
* fix: add missing refresh-server-pat fixture and restore docs heading
---------
Co-authored-by: Joseph Eftekhari <jdeftekhari@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Base UI's PopoverTrigger injects invisible focus guard <span> elements
as siblings when the popover opens. The space-x-2 utility (which uses
> * + *) applied margin to these spans, causing the button to shift.
Replace space-x-2 with gap-2 which is unaffected by DOM changes.
Co-authored-by: Matt Kane <mkane@cloudflare.com>
* fix(admin): use collection urlPattern for preview button fallback URL
The preview button hardcoded fallback URLs as /${collection}/${slug},
ignoring the collection's urlPattern setting. Collections with custom
URL patterns (e.g. urlPattern: "/biljke/{slug}" on a "biljka" collection)
would open a 404 instead of the correct page.
Thread urlPattern through the manifest and use it in the ContentEditor
preview fallback.
Fixes#167
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
* chore: add changeset for preview URL pattern fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
---------
Signed-off-by: Filip Ilic <ilic.filip@gmail.com>
Co-authored-by: Matt Kane <mkane@cloudflare.com>
Replace placeholder text branding ("— EmDash") with actual logo SVGs
from the brand assets. Adds Logo.tsx with LogoIcon (icon mark) and
LogoLockup (icon + wordmark) components.
- Sidebar: gradient icon mark replaces em dash text character
- Login, Signup, Setup: full lockup SVG with currentColor wordmark
- Welcome modal: logo icon replaces Sparkle placeholder
- Favicon: real gradient icon SVG replaces emoji