Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tailwind styles aren't loaded for Keystatic UI custom components in Astro #1189

Open
orlovol opened this issue Jun 20, 2024 · 2 comments
Open

Comments

@orlovol
Copy link
Contributor

orlovol commented Jun 20, 2024

Hi!

I've been trying to setup a Footnote custom mark component, as written here. There's a sample repo using Next, but I had an issue getting the same result for Astro.

Basic idea is adding a custom component with tailwind classes:

// keystatic.config.tsx

// config.collections.<name>.schema
content: fields.markdoc({
  label: "Text",
  components: {
    Footnote: mark({
      label: "Footnote",
      icon: <SuperscriptIcon />,
      className: "align-super text-xs",
      schema: {},
    }),
  },
}),

But when the text is marked in UI, styles aren't applied, because Keystatic Astro component has no idea about the styles file.

How I think this can be fixed

(some steps can be automated by keystatic integration, others might need user input)

  1. Add "keystatic.config.tsx" to tailwind content config, so the custom component styles are picked up into global css
  2. Add a custom Astro component, like so:
---
// src/components/MyKeystatic.astro

import Keystatic from '@keystatic/astro/internal/keystatic-astro-page.astro';
import "styles/globals.css";

export const prerender = false;
---

<div class="bg-blue-500 text-black">Custom Keystatic component with Tailwind</div>
<Keystatic />
  1. Expand integration with option to provide custom Astro component, like so:
// /node_modules/@keystatic/astro/dist/keystatic-astro.js

function keystatic(options) {
  return {
    name: 'keystatic',
    hooks: {
      'astro:config:setup': ({
        ...
        const astroPage = options.astroPage ?? '@keystatic/astro/internal/keystatic-astro-page.astro'
        logger.info(`Using ${astroPage} as Keystatic component`)
...
  1. Configure Astro integration:
// astro.config.mjs

integrations: [
    markdoc(),
    keystatic({ astroPage: "src/components/MyKeystatic.astro" }),
    tailwind(),
]

As a result, tailwind CSS styles are loaded and applied to custom components in the editor UI.

If this approach makes sense — I'll gladly open a PR. Thanks!

@orlovol
Copy link
Contributor Author

orlovol commented Jun 22, 2024

Thought about this a bit more, found a workaround that could work without changes to Keystatic:
By adding Astro middleware for keystatics routes, we can prepend the styles to the Astro island with Keystatic UI, by importing tailwind css content and injecting it into Astro styles. There might be a better way, but this works!

It's especially helpful for custom content components:

// keystatic.config.tsx
...
content: fields.markdoc({
  label: "Body",
  components: {
    Badge: inline({
      label: "Footnote",
      schema: {
        foo: fields.number({ label: "My Foo" }),
      },
      NodeView: ({ value }) => (
        <Badge variant="secondary"> Foo: #{value.foo} </Badge>
      ),
  })

Attaching the middleware code:

?url in style path is needed for vite to build for production, otherwise it produces
src/middleware.ts (2:7): "default" is not exported by "src/styles/globals.css", imported by "src/middleware.ts".

// /src/middleware.ts
import { defineMiddleware } from "astro:middleware";
import css from "./styles/globals.css?url";

export const onRequest = defineMiddleware(async (context, next) => {
  const response = await next();

  if (!context.url.pathname.startsWith("/keystatic")) {
    return response;
  }

  const html = await response.text();
  const redactedHtml = html.replace("<!DOCTYPE html>", `<!DOCTYPE html><meta charset="utf-8"/><link rel="stylesheet" href="${css}" />`);

  return new Response(redactedHtml, {
    status: 200,
    headers: response.headers,
  });
});

@stefanprobst
Copy link
Contributor

i think setting up the keystatic page and api route manually should also work, like here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants