b60ae0f067
Better filtering in the examples app, see gif below. Drive-by fixes: - removed a duplicate shape meta example - Speech bubble text was overflowing and needed the width to be set - Sticker (bindings) no longer snaps - typos ![2024-06-12 at 17 06 17 - Jade Woodpecker](https://github.com/tldraw/tldraw/assets/98838967/80a2ca95-582e-4f7e-b50f-5560211ef081) ### Change Type <!-- ❗ Please select a 'Scope' label ❗️ --> - [ ] `sdk` — Changes the tldraw SDK - [ ] `dotcom` — Changes the tldraw.com web app - [x] `docs` — Changes to the documentation, examples, or templates. - [ ] `vs code` — Changes to the vscode plugin - [ ] `internal` — Does not affect user-facing stuff <!-- ❗ Please select a 'Type' label ❗️ --> - [ ] `bugfix` — Bug fix - [ ] `feature` — New feature - [x] `improvement` — Improving existing features - [ ] `chore` — Updating dependencies, other boring stuff - [ ] `galaxy brain` — Architectural changes - [ ] `tests` — Changes to any test code - [ ] `tools` — Changes to infrastructure, CI, internal scripts, debugging tools, etc. - [ ] `dunno` — I don't know ### Test Plan 1. Type a lot of text in a speech bubble shape and move the tail 2. Text should stay static ### Release Notes - Improve filtering of examples
122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
import react from '@vitejs/plugin-react-swc'
|
|
import path from 'path'
|
|
import { PluginOption, defineConfig } from 'vite'
|
|
|
|
export default defineConfig({
|
|
plugins: [react({ tsDecorators: true }), exampleReadmePlugin()],
|
|
root: path.join(__dirname, 'src'),
|
|
publicDir: path.join(__dirname, 'public'),
|
|
build: {
|
|
outDir: path.join(__dirname, 'dist'),
|
|
assetsInlineLimit: 0,
|
|
target: 'es2022',
|
|
},
|
|
esbuild: {
|
|
target: 'es2022',
|
|
},
|
|
server: {
|
|
port: 5420,
|
|
},
|
|
clearScreen: false,
|
|
optimizeDeps: {
|
|
exclude: ['@tldraw/assets'],
|
|
esbuildOptions: {
|
|
target: 'es2022',
|
|
},
|
|
},
|
|
define: {
|
|
'process.env.TLDRAW_ENV': JSON.stringify(process.env.VERCEL_ENV ?? 'development'),
|
|
},
|
|
})
|
|
|
|
function exampleReadmePlugin(): PluginOption {
|
|
return {
|
|
name: 'example-readme',
|
|
async transform(src, id) {
|
|
const match = id.match(/examples\/src\/examples\/(.*)\/README.md$/)
|
|
if (!match) return
|
|
|
|
const remark = (await import('remark')).remark
|
|
const remarkFrontmatter = (await import('remark-frontmatter')).default
|
|
const remarkHtml = (await import('remark-html')).default
|
|
const matter = (await import('vfile-matter')).matter
|
|
|
|
const file = await remark()
|
|
.use(remarkFrontmatter)
|
|
.use(remarkHtml)
|
|
.use(() => (_, file) => matter(file))
|
|
.process(src)
|
|
|
|
const frontmatter = parseFrontMatter(file.data.matter, id)
|
|
|
|
const separator = '\n<hr>\n'
|
|
const parts = String(file).split(separator)
|
|
const description = parts[0]
|
|
const details = parts.slice(1).join(separator)
|
|
const path = `/${match[1]}`
|
|
const codeUrl = `https://github.com/tldraw/tldraw/tree/main/apps/examples/src/examples${path}`
|
|
|
|
const result = [
|
|
`export const title = ${JSON.stringify(frontmatter.title)};`,
|
|
`export const priority = ${JSON.stringify(frontmatter.priority ?? '100000')};`,
|
|
`export const category = ${JSON.stringify(frontmatter.category)};`,
|
|
`export const hide = ${JSON.stringify(frontmatter.hide)};`,
|
|
`export const description = ${JSON.stringify(description)};`,
|
|
`export const details = ${JSON.stringify(details)};`,
|
|
`export const codeUrl = ${JSON.stringify(codeUrl)};`,
|
|
`export const path = ${JSON.stringify(path)};`,
|
|
`export const componentFile = ${JSON.stringify(frontmatter.component)};`,
|
|
`import {lazy} from 'react';`,
|
|
`export const loadComponent = async () => {`,
|
|
` return (await import(${JSON.stringify(frontmatter.component)})).default;`,
|
|
`};`,
|
|
`export const keywords = ${JSON.stringify(frontmatter.keywords)};`,
|
|
]
|
|
|
|
return result.join('\n')
|
|
},
|
|
}
|
|
}
|
|
|
|
function parseFrontMatter(data: unknown, fileName: string) {
|
|
if (!data || typeof data !== 'object') {
|
|
throw new Error(`Frontmatter missing in ${fileName}`)
|
|
}
|
|
|
|
if (!('title' in data && typeof data.title === 'string')) {
|
|
throw new Error(`Frontmatter key 'title' must be string in ${fileName}`)
|
|
}
|
|
|
|
if (!('component' in data && typeof data.component === 'string')) {
|
|
throw new Error(`Frontmatter key 'component' must be string in ${fileName}`)
|
|
}
|
|
|
|
const priority = 'priority' in data ? data.priority : 999999
|
|
if (typeof priority !== 'number') {
|
|
throw new Error(`Frontmatter key 'priority' must be number in ${fileName}`)
|
|
}
|
|
|
|
const category = 'category' in data ? data.category : null
|
|
if (typeof category !== 'string') {
|
|
throw new Error(`Frontmatter key 'category' must be string in ${fileName}`)
|
|
}
|
|
|
|
const hide = 'hide' in data ? data.hide : false
|
|
if (hide !== false && hide !== true) {
|
|
throw new Error(`Frontmatter key 'hide' must be boolean in ${fileName}`)
|
|
}
|
|
|
|
const keywords = 'keywords' in data ? data.keywords : []
|
|
if (!Array.isArray(keywords)) {
|
|
throw new Error(`Frontmatter key 'keywords' must be array in ${fileName}`)
|
|
}
|
|
|
|
return {
|
|
title: data.title,
|
|
component: data.component,
|
|
priority,
|
|
category,
|
|
hide,
|
|
keywords,
|
|
}
|
|
}
|