thinkmill / keystatic Goto Github PK
View Code? Open in Web Editor NEWFirst class CMS experience, TypeScript API, Markdown & YAML/JSON based, no DB
Home Page: https://keystatic.com
License: MIT License
First class CMS experience, TypeScript API, Markdown & YAML/JSON based, no DB
Home Page: https://keystatic.com
License: MIT License
Not sure what the variation here is yet, but it's significant enough that it matters for #224
I think it revolves around React.forwardRef
Typescript wise, it'll mean something around using import_maps to shim react
into preact/compat
(not entirely sure yet)
I have an existing site with 300+ posts that I'm trying to migrate from Netlify CMS to Keystatic.
In the existing app all blog post images are stored like this public/assets/posts/[image name].ext
I have setup my image
field like this:
image: fields.image({
label: "Cover image",
directory: "public/assets/posts",
description: "The cover image for the blog post",
}),
However, when I add a new post the image is saved in public/assets/posts/[post-slug]/[image name].ext
Is there anyway to stop the folder matching the post slug from being created?
Just like DecapCMS, there should be an editorial workflow.
content should go through an approval process.
draft -> ready for review -> approved -> published
Typical way to visualise this would be a kanban board (this is how DecapCMS does it)
In strict mode, collection components don't behave as expected.
Move collection components to their own docs section and warn about the issue with strict mode.
On package @keystatic/[email protected]
I'm getting the following error from keystatic on dev or build
I'm was following Astro guide but got this error when trying to open Homepage singleton:
Hi. been trying to set up Keystatic and the new app directory in Next.js
It seems like importing createReader also imports some client components
Not sure I'm doing/setting everything up correctly to be honest, but created a small repro in case it helps.
https://github.com/kimf/keystatic-usereducer-bug-reproduction
Error:
You're importing a component that needs useReducer.
The error was caused by importing '@keystatic/core/reader/dist/keystatic-core-reader.esm.js'
Creating a collection entry with a non-unique slug will replace the existing entry.
Typically we should let the consumer decide how they want to handle their data. However, this is a destructive action so I think we should enforce uniqueness for each slug.
It'd be great if https://thinkmill.notion.site/Add-Keystatic-to-an-Astro-Project-312e59b9be1f43d480d3f77638da2910 could be updated to include the comments w/in the frontmatter, so that the snippets are valid Astro:
---
// src/pages/keystatic/[...params].astro
import { Keystatic } from '../../../keystatic.page'
---
<Keystatic client:only />
instead of
// src/pages/keystatic/[...params].astro
---
import { Keystatic } from '../../../keystatic.page'
---
<Keystatic client:only />
hi, i am seeing a "layoutInfo is undefined" error when clicking the "Paragraph" select in the richtext editor.
steps to reproduce:
it looks like the error is coming from the @react-aria/virtualizer
package
Saving every little change results in waiting insert build time here
before seeing changes live.
Until then technical users don't always know what's happening.
Those users which do not understand or know that git is underneath keystatic will be confused when they click "publish/save" and it doesn't show up on the site straight away. You can tell them many times: "yada yada yada, it takes 10 minutes to deploy", but they'll forget. (I know, I recently had to deal with this in a side project)
Ways to handle this:
DecapCMS does 2
but only cares about the deployment status for the purposes of displaying a "preview page" within PRs and not indicating that a PR has been merged and its deployment is in flight.
Finally there's probably something interesting that can be done by utilising merge queues?
In many config files (e.g. tailwind.config.ts
), it's hard to integrate async functions to read from keystatic entities. It would be helpful if there is a sync version of the reader API.
Hey, this library is a great idea, but I'm having trouble deploying to Cloudflare Pages, see the error log. I'm using Astro and GitHub as storage btw.
✘ [ERROR] Could not resolve "fs/promises"
../../node_modules/@keystatic/core/api/generic/dist/keystatic-core-api-generic.cjs.js:8:17:
8 │ var fs = require('fs/promises');
╵ ~~~~~~~~~~~~~
The package "fs/promises" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "node:crypto"
../../node_modules/@keystatic/core/api/generic/dist/keystatic-core-api-generic.cjs.js:9:26:
9 │ var node_crypto = require('node:crypto');
╵ ~~~~~~~~~~~~~
The package "node:crypto" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "path"
../../node_modules/@keystatic/core/api/generic/dist/keystatic-core-api-generic.cjs.js:13:19:
13 │ var path = require('path');
╵ ~~~~~~
The package "path" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "crypto"
../../node_modules/@keystatic/core/api/generic/dist/keystatic-core-api-generic.cjs.js:17:8:
17 │ require('crypto');
╵ ~~~~~~~~
The package "crypto" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "crypto"
../../node_modules/@hapi/iron/lib/index.js:3:23:
3 │ const Crypto = require('crypto');
╵ ~~~~~~~~
The package "crypto" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "fs/promises"
../../node_modules/@keystatic/core/dist/read-local-ecc50d5b.cjs.js:3:17:
3 │ var fs = require('fs/promises');
╵ ~~~~~~~~~~~~~
The package "fs/promises" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "crypto"
../../node_modules/@hapi/cryptiles/lib/index.js:3:23:
3 │ const Crypto = require('crypto');
╵ ~~~~~~~~
The package "crypto" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "path"
../../node_modules/@keystatic/core/dist/read-local-ecc50d5b.cjs.js:4:19:
4 │ var path = require('path');
╵ ~~~~~~
The package "path" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "stream"
../../node_modules/@hapi/b64/lib/encoder.js:9:23:
9 │ const Stream = require('stream');
╵ ~~~~~~~~
The package "stream" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "stream"
../../node_modules/@hapi/b64/lib/decoder.js:9:23:
9 │ const Stream = require('stream');
╵ ~~~~~~~~
The package "stream" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "fs/promises"
../../node_modules/@keystatic/core/reader/dist/keystatic-core-reader.cjs.js:24:17:
24 │ var fs = require('fs/promises');
╵ ~~~~~~~~~~~~~
The package "fs/promises" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "path"
../../node_modules/@keystatic/core/reader/dist/keystatic-core-reader.cjs.js:25:19:
25 │ var path = require('path');
╵ ~~~~~~
The package "path" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "crypto"
../../node_modules/@keystatic/core/dist/read-local-ecc50d5b.cjs.js:7:21:
7 │ var crypto = require('crypto');
╵ ~~~~~~~~
The package "crypto" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
error Could not resolve "stream"
File:
../../node_modules/@hapi/b64/lib/decoder.js:9:23
Code:
> 9 | const Stream = require('stream');
| ^
12 | const internals = {
Stacktrace:
Error: Build failed with 13 errors:
../../node_modules/@hapi/b64/lib/decoder.js:9:23: ERROR: Could not resolve "stream"
../../node_modules/@hapi/b64/lib/encoder.js:9:23: ERROR: Could not resolve "stream"
../../node_modules/@hapi/cryptiles/lib/index.js:3:23: ERROR: Could not resolve "crypto"
../../node_modules/@hapi/iron/lib/index.js:3:23: ERROR: Could not resolve "crypto"
../../node_modules/@keystatic/core/api/generic/dist/keystatic-core-api-generic.cjs.js:8:17: ERROR: Could not resolve "fs/promises"
...
at failureErrorWithLog (/opt/buildhome/repo/node_modules/esbuild/lib/main.js:1636:15)
at /opt/buildhome/repo/node_modules/esbuild/lib/main.js:1048:25
at /opt/buildhome/repo/node_modules/esbuild/lib/main.js:993:52
at buildResponseToResult (/opt/buildhome/repo/node_modules/esbuild/lib/main.js:1046:7)
at /opt/buildhome/repo/node_modules/esbuild/lib/main.js:1075:16
at responseCallbacks.<computed> (/opt/buildhome/repo/node_modules/esbuild/lib/main.js:697:9)
at handleIncomingPacket (/opt/buildhome/repo/node_modules/esbuild/lib/main.js:752:9)
at Socket.readFromStdout (/opt/buildhome/repo/node_modules/esbuild/lib/main.js:673:7)
at Socket.emit (node:events:513:28)
at addChunk (node:internal/streams/readable:324:12)
at readableAddChunk (node:internal/streams/readable:297:9)
at Readable.push (node:internal/streams/readable:234:10)
at Pipe.onStreamRead (node:internal/stream_base_commons:190:23)
When using the code block the list of available languages is not listed, to change a language you must manually write it in the combobox
EDIT: Found out why, when running <StrictMode>
triggers this error
More info: https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage
PD: this error is only triggered on development
Tried to install Keystatic according to the Quick Start guide under this link:
https://keystatic.com/docs/quick-start
Tried running npm create @keystatic@latest
and was greeted with this error:
➜ Code npm create @keystatic@latest
npm ERR! code EINVALIDPACKAGENAME
npm ERR! Invalid package name "@keystatic" of package "@keystatic@latest/create": name can only contain URL-friendly characters.
One of the really nice things that DecapCMS does is a media library, this is facilitated through two main aspects
essential:
nice to have:
stormwarning/netlify-cms-widget-image-extra
not-dalia/netlify-cms-widget-image-dimensions
mvolfik/netlify-cms-widget-external-image
Image Compression in browser:
BosNaufal/react-image-compressor
medium.com/front-end-weekly/image-compression-in-reactjs-a07ec0066b24
fengyuanchen/compressorjs
Making color-schema
dark
on dark mode would be awesome so that we don't get white flashy scrollbars on windows
Hello !
I found a bug with NumberField.
The label and the description should appear but nothing is displayed for NumberFields.
Here is my schema
export default config({
storage: {
kind: "local",
},
collections: {
hotels: collection({
schema: {
slug: fields.slug({
name: {
label: "Name",
},
}),
distance: fields.integer({
label: "Distance",
description: "Distance from the place in meters",
validation: {
min: 0,
max: 10000,
},
}),
...
I wanted to do a simple key value to handle common error strings inside my forms:
keystatic.config.js
formCommon: collection({
label: 'Form Common Texts',
path: 'src/modules/keystatic/content/form-common/*/',
slugField: 'key',
schema: {
key: fields.text({
label: 'Key',
validation: { length: { min: 1 } },
}),
value: fields.text({
label: 'Value',
validation: { length: { min: 1 } },
}),
},
}),
When log the content of my data, I have :
I updated my package.json
to:
"@keystatic/core": "^0.0.98",
"@keystatic/next": "^0.0.7",
Now, I have to do this:
const col = await reader.collections[resource].read(slug)
if (col && 'key' in col && col?.key === null) {
col.key = slug
}
return col
It's easy to remap it because I just asked .read(slug)
.
I want to have the slug by default when I ask for a key
+ value
object so I don't have to set the key (slug) by myself.
Slug is null
.
Creating an issue from this to track the issue, cc/ @simonswiss @emmatown
Originally posted by eyrewiut June 24, 2023
I have set up my site with keystatic and everything works fine, however there seems to be a glitch when logging into the cms.
When I click the "log in with github" button, it shows an unstyled 404 page as shown below, but if I reload the page it logs in and works fine thereafter.. I am trying to use the new "hybrid" rendering mode, but have also tried it with the standard SSR mode as well with the same result.
Does anyone have any idea what is causing this?
Per #401
We need to be able to set the Locale in config
and it should default to en-US
.
The current implementation is cosmetic. We'll need proper semantic breadcrumbs; ideally they'd respond to the viewport and collapse into an overflow menu.
Currently, we can add relationship between 2 collections, for any entry.
It would be great to allow applying filters, for instance:
fields.relationship({ label: "Category", collection: "categories", filter: (entry, collectionEntry) => entry.locale === collectionEntry.locale })
To achieve this, I think types from collections must be properly passed to each other in order to type properly collectionEntry
(as well as collection
)
When I access my project in dev mode at http://localhost:3000/keystatic, I always get redirected to http://127.0.0.1:3000/keystatic and receive an ERR_CONNECTION_REFUSED error from my browser. I think this is because I'm using Windows WSL2, and the IP address 127.0.0.1 doesn't work by default.
I tested this by adding it to an existing Next.js 13 project and a new template project from Keystatic CLI, and both encountered this error.
Why is Keystatic redirecting to this IP? Did I miss some configuration?
Config File (Same as in the docs):
// keystatic.config.ts
import { config, fields, singleton } from '@keystatic/core'
export default config({
storage: {
kind: 'local'
},
singletons: {
homepage: singleton({
label: 'Homepage',
path: 'src/content/_homepage',
schema: {
headline: fields.text({ label: 'Headline' })
}
})
}
})
I wanted to try this repository:
When I clone the Starter called "Start from a blank Canva", I can run the project locally but can't go to /keystatic
.
When I click on the button Go to Keystatic, I have the following error:
Unhandled Runtime Error
Error: Expected never to be called, but received: 320
Call Stack
assertNever
node_modules/emery/assertions/dist/emery-assertions.esm.js (25:0)
sizeResolver
node_modules/@voussoir/style/dist/voussoir-style.esm.js (689:15)
mapResponsiveValue
node_modules/@voussoir/style/dist/voussoir-style.esm.js (517:0)
convertStyleProps
node_modules/@voussoir/style/dist/voussoir-style.esm.js (912:0)
useStyleProps
node_modules/@voussoir/style/dist/voussoir-style.esm.js (941:0)
useFlexStyleProps
node_modules/@voussoir/layout/dist/voussoir-layout.esm.js (129:22)
eval
node_modules/@voussoir/layout/dist/voussoir-layout.esm.js (253:0)
renderWithHooks
node_modules/react-dom/cjs/react-dom.development.js (16305:0)
updateForwardRef
node_modules/react-dom/cjs/react-dom.development.js (19226:0)
beginWork
node_modules/react-dom/cjs/react-dom.development.js (21636:0)
HTMLUnknownElement.callCallback
node_modules/react-dom/cjs/react-dom.development.js (4164:0)
Object.invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js (4213:0)
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js (4277:0)
beginWork$1
node_modules/react-dom/cjs/react-dom.development.js (27451:0)
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js (26557:0)
workLoopSync
node_modules/react-dom/cjs/react-dom.development.js (26466:0)
renderRootSync
node_modules/react-dom/cjs/react-dom.development.js (26434:0)
performConcurrentWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js (25738:0)
workLoop
node_modules/scheduler/cjs/scheduler.development.js (266:0)
flushWork
node_modules/scheduler/cjs/scheduler.development.js (239:0)
MessagePort.performWorkUntilDeadline
node_modules/scheduler/cjs/scheduler.development.js (533:0)
I set in package.json set NextJS to exact versions:
It's also the case in my personnal NextJS application (I tried the starter to see if it was relative to one of my middleware but It's not : the bug is present in the starter repo).
I want to be able to go to /keystatic
and have the dashboard / editor UI.
I have an error on the editor page.
npm i
and npm run dev
Error: Expected never to be called, but received: 320
error.I have set up my application with the production callback URL but is always redirecting me to localhost
http://127.0.0.1:3000/api/keystatic/github/oauth/callback?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdocs.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch
My app is on https://danestves.fly.dev/
Refactor hard-coded text to support localized strings.
Probably one massive JSON file somewhere near the root, containing common words like "add, remove" etc. then by page for more complex phrases.
Targets:
Once the relevant packages, related to strict-mode issues are published, upgrade all the things.
website_url/keystatic should not be listed in search engine.
website_url/keystaic now can be crawled and indexed by search engine.
We need toasts
Hi, I got the error SyntaxError: Failed to execute 'querySelector' on 'Element': '#react-aria9261322746-:r5:' is not a valid selector.
I'm following the steps on Next.JS Integration with new NextJS Project
This happens after clicking on singleton content type, ex: http://127.0.0.1:2700/keystatic/singleton/blog
I don't know is this is a bug or a feature, but given the example from the docs, keystatic doesn't prevent creating duplicated values.
tags: fields.array(
fields.text({ label: 'Tag' }),
// Labelling options
{
label: 'Tag',
itemLabel: props => props.value
}
)
Could be an option like { unique: true }
We've added initial support for interface localisation but it's incomplete / broken for non-English users, specifically:
To make this less broken we should do a few things:
Later when we have more confidence in our translation support, we could (re)introduce the option to use the browser's locale so that implementations of Keystatic with users who have different locales see their own, but right now that would lead to a broken experience on a per-end-user basis so let's leave it with the config to set globally for each project.
Currently, the path is always static except for the slug, specified by slugField
.
Projects often require more custom paths, e.g.: locales, publish date
Make the collection config an intersection like so (pseudocode):
type Collection = { /* base props */}
& (
{
path: string // with * validation
slugField: keyof fields
}
| {
path: (fields: Record<string, any>) => string // with * validation
slugField: keyof fields // might not be required, we could manually specify the field by interpolation instead
}
)
export default defineConfig({
// ...
collections: {
blog: collection({
label: "Blog",
path: ({ locale }) => `src/content/blog/${locale}/*`
schema: {
// ...
locale: fields.text({ label: "Locale" }) // could be a relationship, whatever
}
})
}
})
export default defineConfig({
// ...
collections: {
blog: collection({
label: "Blog",
path: ({ publishDate }) => `src/content/blog/${publishDate}.*`
schema: {
// ...
publishDate: fields.date({ label: "Published date" })
}
})
}
})
In the main view of the editor, the array view of an element is incomplete.
This screenshot shows an empty list of images and a list of "Programming Languages" relationships, with one astro
entry in that array.
images: fields.array({
...fields.object({
image: fields.image({ label: "Image", directory: "public" }),
alt: fields.text({ label: "Alt text" }),
}),
}),
programmingLanguages: fields.array({
...fields.relationship({
label: "Programming Languages",
collection: "programmingLanguages",
description: "Link the languages this tool supports",
}),
}),
Not sure if I and the keystatic-astro-docs
starter are configuring things wrong, or not?
I'd love to make a PR to fix -- just point me in the right direction 😁
When I'm trying to choose an option from the select field in the Admin UI, I get this error message:
This is the part of the schema in my config:
caffeineSource: fields.select({
label: "Brühmaterial",
options: [
{ label: "Espresso", value: "espresso" },
{ label: "Kaffeepulver", value: "coffee" },
{ label: "Tee", value: "tea" },
],
defaultValue: "espresso",
})
I'm adding Keystatic to an existing Astro app. I've followed the guide, except for SSR:
hybrid
export const prerender = false
to both src/pages/keystatic/[...params].astro
and src/pages/api/keystatic/[...params].ts
(Btw I think this option should be added to guide as well)
When going to http://127.0.0.1:3000/keystatic
, I get the following warning:
Warning: Can't perform a React state update on a component that hasn't mounted yet. This indicates that you have a side-effect in your render function that asynchronously later calls tries to update the component. Move this work to useEffect instead.
Nothing's broken, but I thought I'd mention it anyway
Allow project develoeprs to describe their own storage backend, allowing them to wire up other gitlike apis (or what ever other storage api they like):
I don't think it matters what the storage services might be (gitlab, azure, https://min.io/) but more that the interface that keystatic expects should be defined and pluggable.
end result should be that I can write an npm package that can be inserted into the keystatic config that changes how content is read and written.
Dogfood your own project for documentation.
Show us how much confidence you have in the project!
A bunch of icons have been added since last upgrade: See: https://github.com/lucide-icons/lucide/releases
As mentioned in https://youtu.be/6l2YWCyPsWk, it would be great to have a keystaticToAstroCollection
utility exported by @keystatic/astro
to translate the Keystatic config to the Astro collections config.
Example usage:
// src/content/config.ts
import keystaticConfig from "../../keystatic.config"
import { keystaticToAstroCollection } from "@keystatic/astro"
const keystaticCollections = keystaticToAstroCollection(keystaticConfig)
export const collections = {
...keystaticCollections
}
I made some experiments at the type level but collections and singletons specific types are lost once past to the config
Keystatic should aim to support at its core the ability to add our own field (and collection types if that can be done)
Coming from TheOtherPopularPlatform™️ , people would probably expect it to be able to:
additionally, (and seperately)
Something that didn't make sense to me from TheOtherPopularPlatform™️ was
This largely means that all the packages should be esm
and usable via cdns like https://esm.sh.
We shouldn't rely on transforms that involve babel or custom typescript loaders.
finally, since we're writing esm
deployment shouldn't require any use of webpack/vite/parcel. The deno ecosystem already has tools that handle this unlikely scenario.
same as what https://www.npmjs.com/package/netlify-cms-proxy-server does.
this is a DX thing.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.