From 5164e5929c4b47e509aeab687c7c24a9c10737bb Mon Sep 17 00:00:00 2001 From: Travis Kuhl Date: Tue, 14 May 2024 09:49:08 -0700 Subject: [PATCH 1/3] first docs setup --- apps/docs/package.json | 1 + apps/docs/src/app/docs/contributing/page.md | 0 .../docs/src/app/docs/getting-started/page.md | 141 ++++++++++++++++++ apps/docs/src/app/docs/page.md | 115 ++++---------- apps/docs/src/app/docs/support/page.md | 17 +++ apps/docs/src/app/layout.tsx | 13 +- apps/docs/src/app/page.tsx | 2 +- apps/docs/src/app/providers.tsx | 8 +- apps/docs/src/components/Layout.tsx | 21 ++- apps/docs/src/lib/navigation.ts | 16 +- apps/docs/src/styles/tailwind.css | 5 + apps/docs/tailwind.config.ts | 10 +- pnpm-lock.yaml | 3 + 13 files changed, 241 insertions(+), 111 deletions(-) create mode 100644 apps/docs/src/app/docs/contributing/page.md create mode 100644 apps/docs/src/app/docs/getting-started/page.md create mode 100644 apps/docs/src/app/docs/support/page.md diff --git a/apps/docs/package.json b/apps/docs/package.json index ff449f0..97732be 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -42,6 +42,7 @@ "@next/eslint-plugin-next": "^14.2.3", "eslint-config-next": "latest", "eslint-plugin-next": "^0.0.0", + "postcss": "^8.4.38", "prettier": "^3.2.5", "sharp": "0.33.3" } diff --git a/apps/docs/src/app/docs/contributing/page.md b/apps/docs/src/app/docs/contributing/page.md new file mode 100644 index 0000000..e69de29 diff --git a/apps/docs/src/app/docs/getting-started/page.md b/apps/docs/src/app/docs/getting-started/page.md new file mode 100644 index 0000000..f15f130 --- /dev/null +++ b/apps/docs/src/app/docs/getting-started/page.md @@ -0,0 +1,141 @@ +--- +title: Getting started +--- + +Elwood has two integration modes. Pick which one is right for you! {% .lead %} + +{% quick-links %} + +{% quick-link title="Standalone" icon="installation" href="#standalone" description="Setup Elwood as a standalone Next.js application." /%} + +{% quick-link title="Embedded" icon="lightbulb" href="#embedded" description="Integrate Elwood into your existing React application." /%} + +{% /quick-links %} + +## Standalone + +In standalone mode, Elwood runs as standalone Next.js application & Supabase project. This is the easiest way to get started with Elwood. + +### Prerequisites + +You'll need the following installed on your machine: + +- Git +- Supabase CLI +- Node.js (>=v20) +- PNPM +- Deno (optional) + +### Clone the repository + +```bash +git clone https://github.com/elwood-software/elwood +``` + +### Install dependencies + +```bash +pnpm install +``` + +npm + +### Start Supabase + +```bash +supabase start +``` + +### Start Elwood + +```bash +pnpm dev +``` + +## Embedded + +You can integrate Elwood into your existing Next.js application. This is useful if you want to add Elwood to an existing project. + +### Install Elwood packages + +```bash +pnpm install @elwood/react @elwood/ui @elwood/js +``` + +### Add Elwood pages + +Elwood has a few pages you'll need to get your application up and running. + +#### Layout + +`app/elwood/(dashboard)/layout.tsx` + +```typescript +import {type PropsWithChildren} from 'react'; +import AuthPage from '@/app/(unauthenticated)/auth/page'; +import {RedirectType, redirect} from 'next/navigation'; +import {ElwoodThemeProvider} from '@elwood/ui'; + +export default async function Layout( + props: PropsWithChildren, +): Promise { + // + // !! CHANGE !! + // add your custom check for a user here + // Elwood does not provide authentication flow + // in Embedded mode + // + if (!user) { + redirect('/login', RedirectType.replace); + } + + return ( + +
{props.children}
+
+ ); +} + +``` + +#### Dashboard page + +`app/elwood/(dashboard)/[[...slug]]/page.tsx` + +```typescript +'use client'; + +import React, {useEffect, useState} from 'react'; +import { + Router, + createBrowserRouter, + dashboardRoutes, + type RouterProps, +} from '@elwood/react'; +import {type ElwoodClient, createClient} from '@elwood/js'; +import {Spinner} from '@elwood/ui'; + +export default function Page(): JSX.Element { + const [client, setClient] = useState(null); + const [router, setRouter] = useState(null); + + useEffect(() => { + setClient(createClient()); + setRouter( + createBrowserRouter(dashboardRoutes, { + basename: `/`, + }), + ); + }, []); + + if (!router || !client) { + return ; + } + + return ( + + + + ); +} +``` diff --git a/apps/docs/src/app/docs/page.md b/apps/docs/src/app/docs/page.md index 43cb1d2..b7983b3 100644 --- a/apps/docs/src/app/docs/page.md +++ b/apps/docs/src/app/docs/page.md @@ -1,112 +1,47 @@ --- -title: Getting started +title: Elwood Documentation --- -Learn how to get CacheAdvance set up in your project in under thirty minutes or it's free. {% .lead %} +The open source Dropbox alternative with Lighting fast, resumable uploads. Real-time, multi-user collaboration. Powerful role-based sharing. AI powered assistant (to the) file manager. {% .lead %} {% quick-links %} -{% quick-link title="Installation" icon="installation" href="/" description="Step-by-step guides to setting up your system and installing the library." /%} +{% quick-link title="Getting Started" icon="installation" href="/docs/getting-started" description="Step-by-step guides to setting up Elwood." /%} -{% quick-link title="Architecture guide" icon="presets" href="/" description="Learn how the internals work and contribute." /%} - -{% quick-link title="Plugins" icon="plugins" href="/" description="Extend the library with third-party plugins or write your own." /%} - -{% quick-link title="API reference" icon="theming" href="/" description="Learn to easily customize and modify your app's visual design to fit your brand." /%} +{% quick-link title="Support" icon="lightbulb" href="/docs/support" description="You've got Questions, we've got answers." /%} {% /quick-links %} -Possimus saepe veritatis sint nobis et quam eos. Architecto consequatur odit perferendis fuga eveniet possimus rerum cumque. Ea deleniti voluptatum deserunt voluptatibus ut non iste. - ---- - -## Quick start - -Sit commodi iste iure molestias qui amet voluptatem sed quaerat. Nostrum aut pariatur. Sint ipsa praesentium dolor error cumque velit tenetur. - -### Installing dependencies - -Sit commodi iste iure molestias qui amet voluptatem sed quaerat. Nostrum aut pariatur. Sint ipsa praesentium dolor error cumque velit tenetur quaerat exercitationem. Consequatur et cum atque mollitia qui quia necessitatibus. - -```shell -npm install @tailwindlabs/cache-advance -``` - -Possimus saepe veritatis sint nobis et quam eos. Architecto consequatur odit perferendis fuga eveniet possimus rerum cumque. Ea deleniti voluptatum deserunt voluptatibus ut non iste. Provident nam asperiores vel laboriosam omnis ducimus enim nesciunt quaerat. Minus tempora cupiditate est quod. - -{% callout type="warning" title="Oh no! Something bad happened!" %} -This is what a disclaimer message looks like. You might want to include inline `code` in it. Or maybe you’ll want to include a [link](/) in it. I don’t think we should get too carried away with other scenarios like lists or tables — that would be silly. -{% /callout %} - -### Configuring the library - -Sit commodi iste iure molestias qui amet voluptatem sed quaerat. Nostrum aut pariatur. Sint ipsa praesentium dolor error cumque velit tenetur quaerat exercitationem. Consequatur et cum atque mollitia qui quia necessitatibus. - -```js -// cache-advance.config.js -export default { - strategy: 'predictive', - engine: { - cpus: 12, - backups: ['./storage/cache.wtf'], - }, -} -``` - -Possimus saepe veritatis sint nobis et quam eos. Architecto consequatur odit perferendis fuga eveniet possimus rerum cumque. Ea deleniti voluptatum deserunt voluptatibus ut non iste. Provident nam asperiores vel laboriosam omnis ducimus enim nesciunt quaerat. Minus tempora cupiditate est quod. - {% callout title="You should know!" %} -This is what a disclaimer message looks like. You might want to include inline `code` in it. Or maybe you’ll want to include a [link](/) in it. I don’t think we should get too carried away with other scenarios like lists or tables — that would be silly. +Elwood is currently in public BETA. We are actively developing and improving the code & documentation. If you have any questions, please reach out to us at [hello@elwood.software](mailto:hello@elwood.software). {% /callout %} --- -## Basic usage - -Praesentium laudantium magni. Consequatur reiciendis aliquid nihil iusto ut in et. Quisquam ut et aliquid occaecati. Culpa veniam aut et voluptates amet perspiciatis. Qui exercitationem in qui. Vel qui dignissimos sit quae distinctio. - -### Your first cache - -Minima vel non iste debitis. Consequatur repudiandae et quod accusamus sit molestias consequatur aperiam. Et sequi ipsa eum voluptatibus ipsam. Et quisquam ut. - -Qui quae esse aspernatur fugit possimus. Quam sed molestiae temporibus. Eum perferendis dignissimos provident ea et. Et repudiandae quasi accusamus consequatur dolore nobis. Quia reiciendis necessitatibus a blanditiis iste quia. Ut quis et amet praesentium sapiente. - -Atque eos laudantium. Optio odit aspernatur consequuntur corporis soluta quidem sunt aut doloribus. Laudantium assumenda commodi. - -### Clearing the cache - -Vel aut velit sit dolor aut suscipit at veritatis voluptas. Laudantium tempore praesentium. Qui ut voluptatem. - -Ea est autem fugiat velit esse a alias earum. Dolore non amet soluta eos libero est. Consequatur qui aliquam qui odit eligendi ut impedit illo dignissimos. - -Ut dolore qui aut nam. Natus temporibus nisi voluptatum labore est ex error vel officia. Vero repellendus ut. Suscipit voluptate et placeat. Eius quo corporis ab et consequatur quisquam. Nihil officia facere dolorem occaecati alias deleniti deleniti in. - -### Adding middleware - -Officia nobis tempora maiores id iusto magni reprehenderit velit. Quae dolores inventore molestiae perspiciatis aut. Quis sequi officia quasi rem officiis officiis. Nesciunt ut cupiditate. Sunt aliquid explicabo enim ipsa eum recusandae. Vitae sunt eligendi et non beatae minima aut. - -Harum perferendis aut qui quibusdam tempore laboriosam voluptatum qui sed. Amet error amet totam exercitationem aut corporis accusantium dolorum. Perspiciatis aut animi et. Sed unde error ut aut rerum. - -Ut quo libero aperiam mollitia est repudiandae quaerat corrupti explicabo. Voluptas accusantium sed et doloribus voluptatem fugiat a mollitia. Numquam est magnam dolorem asperiores fugiat. Soluta et fuga amet alias temporibus quasi velit. Laudantium voluptatum perspiciatis doloribus quasi facere. Eveniet deleniti veniam et quia veritatis minus veniam perspiciatis. - ---- - -## Getting help - -Consequuntur et aut quisquam et qui consequatur eligendi. Necessitatibus dolorem sit. Excepturi cumque quibusdam soluta ullam rerum voluptatibus. Porro illo sequi consequatur nisi numquam nisi autem. Ut necessitatibus aut. Veniam ipsa voluptatem sed. - -### Submit an issue +## What is Elwood? -Inventore et aut minus ut voluptatem nihil commodi doloribus consequatur. Facilis perferendis nihil sit aut aspernatur iure ut dolores et. Aspernatur odit dignissimos. Aut qui est sint sint. +Elwood is an open source Dropbox alternative. -Facere aliquam qui. Dolorem officia ipsam adipisci qui molestiae. Error voluptatem reprehenderit ex. +- ✔️ Lighting fast, resumable uploads +- ✔️ Real-time, multi-user collaboration +- ✔️ Simple user management +- ✔️ File previews for images, videos, and documents (text, pdf, markdown) +- Public link sharing +- Role-based access control (RBAC) +- Unified search with external providers (S3, Dropbox, Box, Google Drive, etc) +- AI chat based file manager assistant +- Zero knowledge, end-to-end encrypted file storage +- Desktop app +- Mobile app -Consequatur enim quia maiores aperiam et ipsum dicta. Quam ut sit facere sit quae. Eligendi veritatis aut ut veritatis iste ut adipisci illo. +## Contribute -### Join the community +Want to contribute to Elwood? We'd love your help! Check out our [Contributing Guide](/docs/contributing) to get started. -Praesentium facilis iste aliquid quo quia a excepturi. Fuga reprehenderit illo sequi voluptatem voluptatem omnis. Id quia consequatur rerum consectetur eligendi et omnis. Voluptates iusto labore possimus provident praesentium id vel harum quisquam. Voluptatem provident corrupti. +## Follow Us -Eum et ut. Qui facilis est ipsa. Non facere quia sequi commodi autem. Dicta autem sit sequi omnis impedit. Eligendi amet dolorum magnam repudiandae in a. +Want to stay up to date on all the latest Elwood news and updates? -Molestiae iusto ut exercitationem dolorem unde iusto tempora atque nihil. Voluptatem velit facere laboriosam nobis ea. Consequatur rerum velit ipsum ipsam. Et qui saepe consequatur minima laborum tempore voluptatum et. Quia eveniet eaque sequi consequatur nihil eos. +- Watch us on [Github](https://github.com/elwood-software/elwood) +- Follow us on [Twitter](https://twitter.com/hello_elwood) +- Join us on [Discord](https://discord.gg/mkhKk5db) diff --git a/apps/docs/src/app/docs/support/page.md b/apps/docs/src/app/docs/support/page.md new file mode 100644 index 0000000..91402ac --- /dev/null +++ b/apps/docs/src/app/docs/support/page.md @@ -0,0 +1,17 @@ +--- +title: Support +--- + +We are here to help! Reach out with any questions, concerns, favorite "The Office" quotes, or just say "Hello!" {% .lead %} + +{% quick-links %} + +{% quick-link title="Forums" icon="lightbulb" href="https://github.com/orgs/elwood-software/discussions" description="The best place to get answers to all your questions" /%} + +{% quick-link title="Discord" icon="lightbulb" href="https://discord.gg/mkhKk5db" description="Join the community" /%} + +{% quick-link title="Bug Report" icon="lightbulb" href="https://github.com/elwood-software/elwood/issues" description="Found a bug... Open an Issue" /%} + +{% quick-link title="Email" icon="lightbulb" href="mailto:support@elwood.software" description="Old school is the best school" /%} + +{% /quick-links %} diff --git a/apps/docs/src/app/layout.tsx b/apps/docs/src/app/layout.tsx index 0739f1c..4fdd4db 100644 --- a/apps/docs/src/app/layout.tsx +++ b/apps/docs/src/app/layout.tsx @@ -1,6 +1,7 @@ import { type Metadata } from 'next' import { Inter } from 'next/font/google' import localFont from 'next/font/local' +import { cookies } from 'next/headers' import clsx from 'clsx' import { Providers } from '@/app/providers' @@ -24,7 +25,7 @@ const lexend = localFont({ export const metadata: Metadata = { title: { template: '%s - Docs', - default: 'Elwood | Open Source Dropbox Alternative', + default: 'Elwood Documentation | Open Source Dropbox Alternative', }, description: 'Lighting fast, resumable uploads. Real-time, multi-user collaboration. Powerful role-based sharing (coming soon).', @@ -35,13 +36,21 @@ export default function RootLayout({ }: { children: React.ReactNode }) { + const theme = cookies().get('system-theme')?.value ?? '' + const validThemes = ['light', 'dark'] + const themeClassName = validThemes.includes(theme) ? theme : '' + return ( - + {children} diff --git a/apps/docs/src/app/page.tsx b/apps/docs/src/app/page.tsx index 23aaa7a..6515062 100644 --- a/apps/docs/src/app/page.tsx +++ b/apps/docs/src/app/page.tsx @@ -1,5 +1,5 @@ import { RedirectType, redirect } from 'next/navigation' export default function Page(): void { - redirect('https://github.com/elwood-software/elwood', RedirectType.replace) + redirect('/docs', RedirectType.replace) } diff --git a/apps/docs/src/app/providers.tsx b/apps/docs/src/app/providers.tsx index d16b648..4b42ea6 100644 --- a/apps/docs/src/app/providers.tsx +++ b/apps/docs/src/app/providers.tsx @@ -2,10 +2,8 @@ import { ThemeProvider } from 'next-themes' +import { ElwoodThemeProvider } from '@elwood/ui' + export function Providers({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ) + return {children} } diff --git a/apps/docs/src/components/Layout.tsx b/apps/docs/src/components/Layout.tsx index c7deb74..b9b20bf 100644 --- a/apps/docs/src/components/Layout.tsx +++ b/apps/docs/src/components/Layout.tsx @@ -35,9 +35,9 @@ function Header(): JSX.Element { return (
@@ -49,17 +49,22 @@ function Header(): JSX.Element { -
- -
+
{/* */}
- + {/* */} + + hello@elwood.software + - +
@@ -79,7 +84,7 @@ export function Layout({ } return ( -
+
diff --git a/apps/docs/src/lib/navigation.ts b/apps/docs/src/lib/navigation.ts index 80b01b6..645fa87 100644 --- a/apps/docs/src/lib/navigation.ts +++ b/apps/docs/src/lib/navigation.ts @@ -1,9 +1,19 @@ export const navigation = [ { - title: 'Introduction', + title: 'Docs', links: [ - { title: 'Getting started', href: '/' }, - { title: 'Installation', href: '/docs/installation' }, + { title: 'Introduction', href: '/docs/' }, + { title: 'Getting started', href: '/docs/getting-started' }, + { title: 'Support', href: '/docs/support' }, + { title: 'Contributing', href: '/docs/contributing' }, + ], + }, + { + title: 'Follow us', + links: [ + { title: 'Github', href: 'https://github.com/elwood-software/elwood' }, + { title: 'Twitter', href: 'https://twitter.com/hello_elwood' }, + { title: 'Discord', href: 'https://discord.gg/mkhKk5db' }, ], }, ] diff --git a/apps/docs/src/styles/tailwind.css b/apps/docs/src/styles/tailwind.css index e423890..b6a6242 100644 --- a/apps/docs/src/styles/tailwind.css +++ b/apps/docs/src/styles/tailwind.css @@ -2,9 +2,14 @@ @import './prism.css'; @import 'tailwindcss/components'; @import 'tailwindcss/utilities'; +@import '@elwood/ui/style.css'; @layer base { [inert] ::-webkit-scrollbar { display: none; } + + body { + overflow: hidden; + } } diff --git a/apps/docs/tailwind.config.ts b/apps/docs/tailwind.config.ts index a46c213..d8a61ad 100644 --- a/apps/docs/tailwind.config.ts +++ b/apps/docs/tailwind.config.ts @@ -1,10 +1,15 @@ import typographyPlugin from '@tailwindcss/typography' +import type { PluginCreator } from 'postcss' import { type Config } from 'tailwindcss' +import { darkMode, theme, plugins } from '@elwood/ui/tailwind.config.js' + +const themeExtend = theme?.extend || {} export default { content: ['./src/**/*.{js,jsx,ts,tsx,md}'], - darkMode: 'selector', + darkMode: darkMode ?? 'selector', theme: { + ...theme, fontSize: { xs: ['0.75rem', { lineHeight: '1rem' }], sm: ['0.875rem', { lineHeight: '1.5rem' }], @@ -21,6 +26,7 @@ export default { '9xl': ['8rem', { lineHeight: '1' }], }, extend: { + ...themeExtend, fontFamily: { sans: 'var(--font-inter)', display: ['var(--font-lexend)', { fontFeatureSettings: '"ss01"' }], @@ -30,5 +36,5 @@ export default { }, }, }, - plugins: [typographyPlugin], + plugins: [...Array.from(plugins as PluginCreator[]), typographyPlugin], } satisfies Config diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 792d621..a02744a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,6 +117,9 @@ importers: eslint-plugin-next: specifier: ^0.0.0 version: 0.0.0 + postcss: + specifier: ^8.4.38 + version: 8.4.38 prettier: specifier: ^3.2.5 version: 3.2.5 From 30c2d6bbe4987acc1627454b382626ffa7174ce0 Mon Sep 17 00:00:00 2001 From: Travis Kuhl Date: Tue, 14 May 2024 10:06:20 -0700 Subject: [PATCH 2/3] fix docs prettier --- .prettierrc | 20 -- apps/docs/package.json | 4 +- apps/docs/prettier.config.js | 5 +- apps/docs/src/app/layout.tsx | 42 ++- apps/docs/src/app/not-found.tsx | 7 +- apps/docs/src/app/page.tsx | 4 +- apps/docs/src/app/providers.tsx | 10 +- apps/docs/src/components/Button.tsx | 16 +- apps/docs/src/components/Callout.tsx | 22 +- apps/docs/src/components/DocsHeader.tsx | 20 +- apps/docs/src/components/DocsLayout.tsx | 24 +- apps/docs/src/components/Fence.tsx | 21 +- apps/docs/src/components/Hero.tsx | 53 ++-- apps/docs/src/components/HeroBackground.tsx | 9 +- apps/docs/src/components/Home.tsx | 4 +- apps/docs/src/components/Icon.tsx | 56 ++-- apps/docs/src/components/Layout.tsx | 71 +++-- apps/docs/src/components/Logo.tsx | 2 +- apps/docs/src/components/MobileNavigation.tsx | 57 ++-- apps/docs/src/components/Navigation.tsx | 26 +- apps/docs/src/components/PrevNextLinks.tsx | 37 ++- apps/docs/src/components/Prose.tsx | 8 +- apps/docs/src/components/QuickLinks.tsx | 18 +- apps/docs/src/components/Search.tsx | 243 +++++++++--------- apps/docs/src/components/TableOfContents.tsx | 82 +++--- apps/docs/src/components/ThemeSelector.tsx | 46 ++-- .../src/components/icons/InstallationIcon.tsx | 8 +- .../src/components/icons/LightbulbIcon.tsx | 8 +- .../docs/src/components/icons/PluginsIcon.tsx | 14 +- .../docs/src/components/icons/PresetsIcon.tsx | 11 +- .../docs/src/components/icons/ThemingIcon.tsx | 8 +- .../docs/src/components/icons/WarningIcon.tsx | 8 +- apps/docs/src/lib/navigation.ts | 16 +- apps/docs/src/lib/sections.ts | 72 +++--- apps/docs/tailwind.config.ts | 2 +- apps/docs/types.d.ts | 12 +- prettier.config.js | 20 ++ 37 files changed, 520 insertions(+), 566 deletions(-) delete mode 100644 .prettierrc create mode 100644 prettier.config.js diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index e2a83e3..0000000 --- a/.prettierrc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "tabWidth": 2, - "arrowParens": "avoid", - "bracketSameLine": true, - "bracketSpacing": false, - "singleQuote": true, - "trailingComma": "all", - "sqlKeywordCase": "lower", - "plugins": ["prettier-plugin-sql-cst"], - "overrides": [ - { - "files": "**/*.json", - "options": {"parser": "json"} - }, - { - "files": ["*.sql"], - "options": {"parser": "postgresql"} - } - ] -} diff --git a/apps/docs/package.json b/apps/docs/package.json index 97732be..3907a24 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -6,7 +6,9 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "format-check": "prettier --check \"**/*.{ts,tsx,md}\"", + "format-fix": "prettier --write \"**/*.{ts,tsx,md}\"" }, "browserslist": "defaults, not ie <= 11", "dependencies": { diff --git a/apps/docs/prettier.config.js b/apps/docs/prettier.config.js index 6b16840..ff29114 100644 --- a/apps/docs/prettier.config.js +++ b/apps/docs/prettier.config.js @@ -1,6 +1,7 @@ +const root = require('../../prettier.config') + /** @type {import('prettier').Options} */ module.exports = { - singleQuote: true, - semi: false, + ...root, plugins: ['prettier-plugin-tailwindcss'], } diff --git a/apps/docs/src/app/layout.tsx b/apps/docs/src/app/layout.tsx index 4fdd4db..6b5f570 100644 --- a/apps/docs/src/app/layout.tsx +++ b/apps/docs/src/app/layout.tsx @@ -1,26 +1,26 @@ -import { type Metadata } from 'next' -import { Inter } from 'next/font/google' -import localFont from 'next/font/local' -import { cookies } from 'next/headers' -import clsx from 'clsx' +import {type Metadata} from 'next'; +import {Inter} from 'next/font/google'; +import localFont from 'next/font/local'; +import {cookies} from 'next/headers'; +import clsx from 'clsx'; -import { Providers } from '@/app/providers' -import { Layout } from '@/components/Layout' +import {Providers} from '@/app/providers'; +import {Layout} from '@/components/Layout'; -import '@/styles/tailwind.css' +import '@/styles/tailwind.css'; const inter = Inter({ subsets: ['latin'], display: 'swap', variable: '--font-inter', -}) +}); // Use local version of Lexend so that we can use OpenType features const lexend = localFont({ src: '../fonts/lexend.woff2', display: 'swap', variable: '--font-lexend', -}) +}); export const metadata: Metadata = { title: { @@ -29,32 +29,26 @@ export const metadata: Metadata = { }, description: 'Lighting fast, resumable uploads. Real-time, multi-user collaboration. Powerful role-based sharing (coming soon).', -} +}; -export default function RootLayout({ - children, -}: { - children: React.ReactNode -}) { - const theme = cookies().get('system-theme')?.value ?? '' - const validThemes = ['light', 'dark'] - const themeClassName = validThemes.includes(theme) ? theme : '' +export default function RootLayout({children}: {children: React.ReactNode}) { + const theme = cookies().get('system-theme')?.value ?? ''; + const validThemes = ['light', 'dark']; + const themeClassName = validThemes.includes(theme) ? theme : ''; return ( + suppressHydrationWarning> + data-color-server-theme={theme}> {children} - ) + ); } diff --git a/apps/docs/src/app/not-found.tsx b/apps/docs/src/app/not-found.tsx index a41451d..f37628e 100644 --- a/apps/docs/src/app/not-found.tsx +++ b/apps/docs/src/app/not-found.tsx @@ -1,4 +1,4 @@ -import Link from 'next/link' +import Link from 'next/link'; export default function NotFound() { return ( @@ -15,11 +15,10 @@ export default function NotFound() {

+ className="mt-8 text-sm font-medium text-slate-900 dark:text-white"> Go back home
- ) + ); } diff --git a/apps/docs/src/app/page.tsx b/apps/docs/src/app/page.tsx index 6515062..565bad6 100644 --- a/apps/docs/src/app/page.tsx +++ b/apps/docs/src/app/page.tsx @@ -1,5 +1,5 @@ -import { RedirectType, redirect } from 'next/navigation' +import {RedirectType, redirect} from 'next/navigation'; export default function Page(): void { - redirect('/docs', RedirectType.replace) + redirect('/docs', RedirectType.replace); } diff --git a/apps/docs/src/app/providers.tsx b/apps/docs/src/app/providers.tsx index 4b42ea6..749fc3f 100644 --- a/apps/docs/src/app/providers.tsx +++ b/apps/docs/src/app/providers.tsx @@ -1,9 +1,9 @@ -'use client' +'use client'; -import { ThemeProvider } from 'next-themes' +import {ThemeProvider} from 'next-themes'; -import { ElwoodThemeProvider } from '@elwood/ui' +import {ElwoodThemeProvider} from '@elwood/ui'; -export function Providers({ children }: { children: React.ReactNode }) { - return {children} +export function Providers({children}: {children: React.ReactNode}) { + return {children}; } diff --git a/apps/docs/src/components/Button.tsx b/apps/docs/src/components/Button.tsx index 068c104..eec8126 100644 --- a/apps/docs/src/components/Button.tsx +++ b/apps/docs/src/components/Button.tsx @@ -1,30 +1,30 @@ -import Link from 'next/link' -import clsx from 'clsx' +import Link from 'next/link'; +import clsx from 'clsx'; const variantStyles = { primary: 'rounded-full bg-sky-300 py-2 px-4 text-sm font-semibold text-slate-900 hover:bg-sky-200 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-300/50 active:bg-sky-500', secondary: 'rounded-full bg-slate-800 py-2 px-4 text-sm font-medium text-white hover:bg-slate-700 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/50 active:text-slate-400', -} +}; type ButtonProps = { - variant?: keyof typeof variantStyles + variant?: keyof typeof variantStyles; } & ( | React.ComponentPropsWithoutRef - | (React.ComponentPropsWithoutRef<'button'> & { href?: undefined }) -) + | (React.ComponentPropsWithoutRef<'button'> & {href?: undefined}) +); export function Button({ variant = 'primary', className, ...props }: ButtonProps) { - className = clsx(variantStyles[variant], className) + className = clsx(variantStyles[variant], className); return typeof props.href === 'undefined' ? (
- ) + ); } diff --git a/apps/docs/src/components/DocsHeader.tsx b/apps/docs/src/components/DocsHeader.tsx index 964822e..e69bbc1 100644 --- a/apps/docs/src/components/DocsHeader.tsx +++ b/apps/docs/src/components/DocsHeader.tsx @@ -1,17 +1,17 @@ -'use client' +'use client'; -import { usePathname } from 'next/navigation' +import {usePathname} from 'next/navigation'; -import { navigation } from '@/lib/navigation' +import {navigation} from '@/lib/navigation'; -export function DocsHeader({ title }: { title?: string }) { - let pathname = usePathname() - let section = navigation.find((section) => - section.links.find((link) => link.href === pathname), - ) +export function DocsHeader({title}: {title?: string}) { + let pathname = usePathname(); + let section = navigation.find(section => + section.links.find(link => link.href === pathname), + ); if (!title && !section) { - return null + return null; } return ( @@ -27,5 +27,5 @@ export function DocsHeader({ title }: { title?: string }) { )} - ) + ); } diff --git a/apps/docs/src/components/DocsLayout.tsx b/apps/docs/src/components/DocsLayout.tsx index 5921566..5a137ba 100644 --- a/apps/docs/src/components/DocsLayout.tsx +++ b/apps/docs/src/components/DocsLayout.tsx @@ -1,21 +1,21 @@ -import { type Node } from '@markdoc/markdoc' +import {type Node} from '@markdoc/markdoc'; -import { DocsHeader } from '@/components/DocsHeader' -import { PrevNextLinks } from '@/components/PrevNextLinks' -import { Prose } from '@/components/Prose' -import { TableOfContents } from '@/components/TableOfContents' -import { collectSections } from '@/lib/sections' +import {DocsHeader} from '@/components/DocsHeader'; +import {PrevNextLinks} from '@/components/PrevNextLinks'; +import {Prose} from '@/components/Prose'; +import {TableOfContents} from '@/components/TableOfContents'; +import {collectSections} from '@/lib/sections'; export function DocsLayout({ children, - frontmatter: { title }, + frontmatter: {title}, nodes, }: { - children: React.ReactNode - frontmatter: { title?: string } - nodes: Array + children: React.ReactNode; + frontmatter: {title?: string}; + nodes: Array; }) { - let tableOfContents = collectSections(nodes) + let tableOfContents = collectSections(nodes); return ( <> @@ -28,5 +28,5 @@ export function DocsLayout({ - ) + ); } diff --git a/apps/docs/src/components/Fence.tsx b/apps/docs/src/components/Fence.tsx index d9643aa..0aa4d75 100644 --- a/apps/docs/src/components/Fence.tsx +++ b/apps/docs/src/components/Fence.tsx @@ -1,30 +1,29 @@ -'use client' +'use client'; -import { Fragment } from 'react' -import { Highlight } from 'prism-react-renderer' +import {Fragment} from 'react'; +import {Highlight} from 'prism-react-renderer'; export function Fence({ children, language, }: { - children: string - language: string + children: string; + language: string; }) { return ( - {({ className, style, tokens, getTokenProps }) => ( + theme={{plain: {}, styles: []}}> + {({className, style, tokens, getTokenProps}) => (
           
             {tokens.map((line, lineIndex) => (
               
                 {line
-                  .filter((token) => !token.empty)
+                  .filter(token => !token.empty)
                   .map((token, tokenIndex) => (
-                    
+                    
                   ))}
                 {'\n'}
               
@@ -33,5 +32,5 @@ export function Fence({
         
)}
- ) + ); } diff --git a/apps/docs/src/components/Hero.tsx b/apps/docs/src/components/Hero.tsx index ddddad1..81b8b9e 100644 --- a/apps/docs/src/components/Hero.tsx +++ b/apps/docs/src/components/Hero.tsx @@ -1,26 +1,26 @@ -import { Fragment } from 'react' -import Image from 'next/image' -import clsx from 'clsx' -import { Highlight } from 'prism-react-renderer' +import {Fragment} from 'react'; +import Image from 'next/image'; +import clsx from 'clsx'; +import {Highlight} from 'prism-react-renderer'; -import { Button } from '@/components/Button' -import { HeroBackground } from '@/components/HeroBackground' -import blurCyanImage from '@/images/blur-cyan.png' -import blurIndigoImage from '@/images/blur-indigo.png' +import {Button} from '@/components/Button'; +import {HeroBackground} from '@/components/HeroBackground'; +import blurCyanImage from '@/images/blur-cyan.png'; +import blurIndigoImage from '@/images/blur-indigo.png'; -const codeLanguage = 'javascript' +const codeLanguage = 'javascript'; const code = `export default { strategy: 'predictive', engine: { cpus: 12, backups: ['./storage/cache.wtf'], }, -}` +}`; const tabs = [ - { name: 'cache-advance.config.js', isActive: true }, - { name: 'package.json', isActive: false }, -] + {name: 'cache-advance.config.js', isActive: true}, + {name: 'package.json', isActive: false}, +]; function TrafficLightsIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( @@ -29,7 +29,7 @@ function TrafficLightsIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - ) + ); } export function Hero() { @@ -64,7 +64,7 @@ export function Hero() {
-
+
@@ -94,7 +94,7 @@ export function Hero() {
- {tabs.map((tab) => ( + {tabs.map(tab => (
+ )}>
+ )}> {tab.name}
@@ -118,8 +116,7 @@ export function Hero() {
- ) + ); } diff --git a/apps/docs/src/components/HeroBackground.tsx b/apps/docs/src/components/HeroBackground.tsx index 5f0adb4..8c54ab9 100644 --- a/apps/docs/src/components/HeroBackground.tsx +++ b/apps/docs/src/components/HeroBackground.tsx @@ -1,7 +1,7 @@ -import { useId } from 'react' +import {useId} from 'react'; export function HeroBackground(props: React.ComponentPropsWithoutRef<'svg'>) { - let id = useId() + let id = useId(); return ( ) { width={668} height={1069} fill="none" - {...props} - > + {...props}> ) { /> - ) + ); } diff --git a/apps/docs/src/components/Home.tsx b/apps/docs/src/components/Home.tsx index 7839dd3..2b1412d 100644 --- a/apps/docs/src/components/Home.tsx +++ b/apps/docs/src/components/Home.tsx @@ -1,9 +1,9 @@ -import { Logo } from '@elwood/ui' +import {Logo} from '@elwood/ui'; export function Home(): JSX.Element { return (
- ) + ); } diff --git a/apps/docs/src/components/Icon.tsx b/apps/docs/src/components/Icon.tsx index d440504..782d96d 100644 --- a/apps/docs/src/components/Icon.tsx +++ b/apps/docs/src/components/Icon.tsx @@ -1,12 +1,12 @@ -import { useId } from 'react' -import clsx from 'clsx' +import {useId} from 'react'; +import clsx from 'clsx'; -import { InstallationIcon } from '@/components/icons/InstallationIcon' -import { LightbulbIcon } from '@/components/icons/LightbulbIcon' -import { PluginsIcon } from '@/components/icons/PluginsIcon' -import { PresetsIcon } from '@/components/icons/PresetsIcon' -import { ThemingIcon } from '@/components/icons/ThemingIcon' -import { WarningIcon } from '@/components/icons/WarningIcon' +import {InstallationIcon} from '@/components/icons/InstallationIcon'; +import {LightbulbIcon} from '@/components/icons/LightbulbIcon'; +import {PluginsIcon} from '@/components/icons/PluginsIcon'; +import {PresetsIcon} from '@/components/icons/PresetsIcon'; +import {ThemingIcon} from '@/components/icons/ThemingIcon'; +import {WarningIcon} from '@/components/icons/WarningIcon'; const icons = { installation: InstallationIcon, @@ -15,13 +15,13 @@ const icons = { theming: ThemingIcon, lightbulb: LightbulbIcon, warning: WarningIcon, -} +}; const iconStyles = { blue: '[--icon-foreground:theme(colors.slate.900)] [--icon-background:theme(colors.white)]', amber: '[--icon-foreground:theme(colors.amber.900)] [--icon-background:theme(colors.amber.100)]', -} +}; export function Icon({ icon, @@ -29,11 +29,11 @@ export function Icon({ className, ...props }: { - color?: keyof typeof iconStyles - icon: keyof typeof icons + color?: keyof typeof iconStyles; + icon: keyof typeof icons; } & Omit, 'color'>) { - let id = useId() - let IconComponent = icons[icon] + let id = useId(); + let IconComponent = icons[icon]; return ( + {...props}> - ) + ); } const gradients = { blue: [ - { stopColor: '#0EA5E9' }, - { stopColor: '#22D3EE', offset: '.527' }, - { stopColor: '#818CF8', offset: 1 }, + {stopColor: '#0EA5E9'}, + {stopColor: '#22D3EE', offset: '.527'}, + {stopColor: '#818CF8', offset: 1}, ], amber: [ - { stopColor: '#FDE68A', offset: '.08' }, - { stopColor: '#F59E0B', offset: '.837' }, + {stopColor: '#FDE68A', offset: '.08'}, + {stopColor: '#F59E0B', offset: '.837'}, ], -} +}; export function Gradient({ color = 'blue', ...props }: { - color?: keyof typeof gradients + color?: keyof typeof gradients; } & Omit, 'color'>) { return ( + {...props}> {gradients[color].map((stop, stopIndex) => ( ))} - ) + ); } export function LightMode({ className, ...props }: React.ComponentPropsWithoutRef<'g'>) { - return + return ; } export function DarkMode({ className, ...props }: React.ComponentPropsWithoutRef<'g'>) { - return + return ; } diff --git a/apps/docs/src/components/Layout.tsx b/apps/docs/src/components/Layout.tsx index b9b20bf..c252aa8 100644 --- a/apps/docs/src/components/Layout.tsx +++ b/apps/docs/src/components/Layout.tsx @@ -1,52 +1,51 @@ -'use client' +'use client'; -import { useEffect, useState } from 'react' -import Link from 'next/link' -import { usePathname } from 'next/navigation' -import { clsx } from 'clsx' -import { Logo } from '@/components/Logo' -import { MobileNavigation } from '@/components/MobileNavigation' -import { Navigation } from '@/components/Navigation' -import { Search } from '@/components/Search' -import { ThemeSelector } from '@/components/ThemeSelector' +import {useEffect, useState} from 'react'; +import Link from 'next/link'; +import {usePathname} from 'next/navigation'; +import {clsx} from 'clsx'; +import {Logo} from '@/components/Logo'; +import {MobileNavigation} from '@/components/MobileNavigation'; +import {Navigation} from '@/components/Navigation'; +import {Search} from '@/components/Search'; +import {ThemeSelector} from '@/components/ThemeSelector'; function GitHubIcon(props: React.ComponentPropsWithoutRef<'svg'>): JSX.Element { return ( - ) + ); } function Header(): JSX.Element { - const [isScrolled, setIsScrolled] = useState(false) + const [isScrolled, setIsScrolled] = useState(false); useEffect(() => { function onScroll(): void { - setIsScrolled(window.scrollY > 0) + setIsScrolled(window.scrollY > 0); } - onScroll() - window.addEventListener('scroll', onScroll, { passive: true }) + onScroll(); + window.addEventListener('scroll', onScroll, {passive: true}); return () => { - window.removeEventListener('scroll', onScroll) - } - }, []) + window.removeEventListener('scroll', onScroll); + }; + }, []); return (
+ )}>
- +
{/* */}
@@ -54,33 +53,27 @@ function Header(): JSX.Element { {/* */} + className="group text-sm text-muted-foreground hover:text-foreground" + aria-label="Email us"> hello@elwood.software - + aria-label="GitHub"> +
- ) + ); } -export function Layout({ - children, -}: { - children: React.ReactNode -}): JSX.Element { - const pathname = usePathname() - const isHomePage = pathname === '/' +export function Layout({children}: {children: React.ReactNode}): JSX.Element { + const pathname = usePathname(); + const isHomePage = pathname === '/'; if (isHomePage) { - return <>{children} + return <>{children}; } return ( @@ -99,5 +92,5 @@ export function Layout({ {children}
- ) + ); } diff --git a/apps/docs/src/components/Logo.tsx b/apps/docs/src/components/Logo.tsx index 4d25485..baf5f84 100644 --- a/apps/docs/src/components/Logo.tsx +++ b/apps/docs/src/components/Logo.tsx @@ -1 +1 @@ -export { Logo } from '@elwood/ui' +export {Logo} from '@elwood/ui'; diff --git a/apps/docs/src/components/MobileNavigation.tsx b/apps/docs/src/components/MobileNavigation.tsx index 804a851..019335c 100644 --- a/apps/docs/src/components/MobileNavigation.tsx +++ b/apps/docs/src/components/MobileNavigation.tsx @@ -1,12 +1,12 @@ -'use client' +'use client'; -import { Suspense, useCallback, useEffect, useState } from 'react' -import Link from 'next/link' -import { usePathname, useSearchParams } from 'next/navigation' -import { Dialog } from '@headlessui/react' +import {Suspense, useCallback, useEffect, useState} from 'react'; +import Link from 'next/link'; +import {usePathname, useSearchParams} from 'next/navigation'; +import {Dialog} from '@headlessui/react'; -import { Logo } from '@/components/Logo' -import { Navigation } from '@/components/Navigation' +import {Logo} from '@/components/Logo'; +import {Navigation} from '@/components/Navigation'; function MenuIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( @@ -16,11 +16,10 @@ function MenuIcon(props: React.ComponentPropsWithoutRef<'svg'>) { fill="none" strokeWidth="2" strokeLinecap="round" - {...props} - > + {...props}> - ) + ); } function CloseIcon(props: React.ComponentPropsWithoutRef<'svg'>) { @@ -31,35 +30,34 @@ function CloseIcon(props: React.ComponentPropsWithoutRef<'svg'>) { fill="none" strokeWidth="2" strokeLinecap="round" - {...props} - > + {...props}> - ) + ); } -function CloseOnNavigation({ close }: { close: () => void }) { - let pathname = usePathname() - let searchParams = useSearchParams() +function CloseOnNavigation({close}: {close: () => void}) { + let pathname = usePathname(); + let searchParams = useSearchParams(); useEffect(() => { - close() - }, [pathname, searchParams, close]) + close(); + }, [pathname, searchParams, close]); - return null + return null; } export function MobileNavigation() { - let [isOpen, setIsOpen] = useState(false) - let close = useCallback(() => setIsOpen(false), [setIsOpen]) + let [isOpen, setIsOpen] = useState(false); + let close = useCallback(() => setIsOpen(false), [setIsOpen]); function onLinkClick(event: React.MouseEvent) { - let link = event.currentTarget + let link = event.currentTarget; if ( link.pathname + link.search + link.hash === window.location.pathname + window.location.search + window.location.hash ) { - close() + close(); } } @@ -69,8 +67,7 @@ export function MobileNavigation() { type="button" onClick={() => setIsOpen(true)} className="relative" - aria-label="Open navigation" - > + aria-label="Open navigation"> @@ -80,15 +77,13 @@ export function MobileNavigation() { open={isOpen} onClose={() => close()} className="fixed inset-0 z-50 flex items-start overflow-y-auto bg-slate-900/50 pr-10 backdrop-blur lg:hidden" - aria-label="Navigation" - > - + aria-label="Navigation"> +
@@ -99,5 +94,5 @@ export function MobileNavigation() { - ) + ); } diff --git a/apps/docs/src/components/Navigation.tsx b/apps/docs/src/components/Navigation.tsx index be35de0..dcaef84 100644 --- a/apps/docs/src/components/Navigation.tsx +++ b/apps/docs/src/components/Navigation.tsx @@ -1,31 +1,30 @@ -import Link from 'next/link' -import { usePathname } from 'next/navigation' -import clsx from 'clsx' +import Link from 'next/link'; +import {usePathname} from 'next/navigation'; +import clsx from 'clsx'; -import { navigation } from '@/lib/navigation' +import {navigation} from '@/lib/navigation'; export function Navigation({ className, onLinkClick, }: { - className?: string - onLinkClick?: React.MouseEventHandler + className?: string; + onLinkClick?: React.MouseEventHandler; }) { - let pathname = usePathname() + let pathname = usePathname(); return ( - ) + ); } diff --git a/apps/docs/src/components/PrevNextLinks.tsx b/apps/docs/src/components/PrevNextLinks.tsx index 75d779d..0264ea1 100644 --- a/apps/docs/src/components/PrevNextLinks.tsx +++ b/apps/docs/src/components/PrevNextLinks.tsx @@ -1,17 +1,17 @@ -'use client' +'use client'; -import Link from 'next/link' -import { usePathname } from 'next/navigation' -import clsx from 'clsx' +import Link from 'next/link'; +import {usePathname} from 'next/navigation'; +import clsx from 'clsx'; -import { navigation } from '@/lib/navigation' +import {navigation} from '@/lib/navigation'; function ArrowIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( - ) + ); } function PageLink({ @@ -20,9 +20,9 @@ function PageLink({ dir = 'next', ...props }: Omit, 'dir' | 'title'> & { - title: string - href: string - dir?: 'previous' | 'next' + title: string; + href: string; + dir?: 'previous' | 'next'; }) { return (
@@ -35,8 +35,7 @@ function PageLink({ className={clsx( 'flex items-center gap-x-1 text-base font-semibold text-slate-500 hover:text-slate-600 dark:text-slate-400 dark:hover:text-slate-300', dir === 'previous' && 'flex-row-reverse', - )} - > + )}> {title}
- ) + ); } export function PrevNextLinks() { - let pathname = usePathname() - let allLinks = navigation.flatMap((section) => section.links) - let linkIndex = allLinks.findIndex((link) => link.href === pathname) - let previousPage = linkIndex > -1 ? allLinks[linkIndex - 1] : null - let nextPage = linkIndex > -1 ? allLinks[linkIndex + 1] : null + let pathname = usePathname(); + let allLinks = navigation.flatMap(section => section.links); + let linkIndex = allLinks.findIndex(link => link.href === pathname); + let previousPage = linkIndex > -1 ? allLinks[linkIndex - 1] : null; + let nextPage = linkIndex > -1 ? allLinks[linkIndex + 1] : null; if (!nextPage && !previousPage) { - return null + return null; } return ( @@ -66,5 +65,5 @@ export function PrevNextLinks() { {previousPage && } {nextPage && } - ) + ); } diff --git a/apps/docs/src/components/Prose.tsx b/apps/docs/src/components/Prose.tsx index 678dcd7..229b9c4 100644 --- a/apps/docs/src/components/Prose.tsx +++ b/apps/docs/src/components/Prose.tsx @@ -1,13 +1,13 @@ -import clsx from 'clsx' +import clsx from 'clsx'; export function Prose({ as, className, ...props }: React.ComponentPropsWithoutRef & { - as?: T + as?: T; }) { - let Component = as ?? 'div' + let Component = as ?? 'div'; return ( ({ )} {...props} /> - ) + ); } diff --git a/apps/docs/src/components/QuickLinks.tsx b/apps/docs/src/components/QuickLinks.tsx index 0970cae..e7d1f2b 100644 --- a/apps/docs/src/components/QuickLinks.tsx +++ b/apps/docs/src/components/QuickLinks.tsx @@ -1,13 +1,13 @@ -import Link from 'next/link' +import Link from 'next/link'; -import { Icon } from '@/components/Icon' +import {Icon} from '@/components/Icon'; -export function QuickLinks({ children }: { children: React.ReactNode }) { +export function QuickLinks({children}: {children: React.ReactNode}) { return (
{children}
- ) + ); } export function QuickLink({ @@ -16,10 +16,10 @@ export function QuickLink({ href, icon, }: { - title: string - description: string - href: string - icon: React.ComponentProps['icon'] + title: string; + description: string; + href: string; + icon: React.ComponentProps['icon']; }) { return (
@@ -37,5 +37,5 @@ export function QuickLink({

- ) + ); } diff --git a/apps/docs/src/components/Search.tsx b/apps/docs/src/components/Search.tsx index 141779d..220a950 100644 --- a/apps/docs/src/components/Search.tsx +++ b/apps/docs/src/components/Search.tsx @@ -1,4 +1,4 @@ -'use client' +'use client'; import { forwardRef, @@ -9,61 +9,61 @@ import { useId, useRef, useState, -} from 'react' -import Highlighter from 'react-highlight-words' -import { usePathname, useRouter, useSearchParams } from 'next/navigation' +} from 'react'; +import Highlighter from 'react-highlight-words'; +import {usePathname, useRouter, useSearchParams} from 'next/navigation'; import { type AutocompleteApi, type AutocompleteCollection, type AutocompleteState, createAutocomplete, -} from '@algolia/autocomplete-core' -import { Dialog } from '@headlessui/react' -import clsx from 'clsx' -import { type Result } from '@/markdoc/search.mjs' +} from '@algolia/autocomplete-core'; +import {Dialog} from '@headlessui/react'; +import clsx from 'clsx'; +import {type Result} from '@/markdoc/search.mjs'; -import { navigation } from '@/lib/navigation' +import {navigation} from '@/lib/navigation'; -type EmptyObject = Record +type EmptyObject = Record; type Autocomplete = AutocompleteApi< Result, React.SyntheticEvent, React.MouseEvent, React.KeyboardEvent -> +>; function SearchIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( - ) + ); } function useAutocomplete({ close, }: { - close: (autocomplete: Autocomplete) => void + close: (autocomplete: Autocomplete) => void; }) { - let id = useId() - let router = useRouter() + let id = useId(); + let router = useRouter(); let [autocompleteState, setAutocompleteState] = useState< AutocompleteState | EmptyObject - >({}) + >({}); - function navigate({ itemUrl }: { itemUrl?: string }) { + function navigate({itemUrl}: {itemUrl?: string}) { if (!itemUrl) { - return + return; } - router.push(itemUrl) + router.push(itemUrl); if ( itemUrl === window.location.pathname + window.location.search + window.location.hash ) { - close(autocomplete) + close(autocomplete); } } @@ -77,39 +77,39 @@ function useAutocomplete({ id, placeholder: 'Find something...', defaultActiveItemId: 0, - onStateChange({ state }) { - setAutocompleteState(state) + onStateChange({state}) { + setAutocompleteState(state); }, - shouldPanelOpen({ state }) { - return state.query !== '' + shouldPanelOpen({state}) { + return state.query !== ''; }, navigator: { navigate, }, - getSources({ query }) { - return import('@/markdoc/search.mjs').then(({ search }) => { + getSources({query}) { + return import('@/markdoc/search.mjs').then(({search}) => { return [ { sourceId: 'documentation', getItems() { - return search(query, { limit: 5 }) + return search(query, {limit: 5}); }, - getItemUrl({ item }) { - return item.url + getItemUrl({item}) { + return item.url; }, onSelect: navigate, }, - ] - }) + ]; + }); }, }), - ) + ); - return { autocomplete, autocompleteState } + return {autocomplete, autocompleteState}; } function LoadingIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - let id = useId() + let id = useId(); return ( - ) + ); } -function HighlightQuery({ text, query }: { text: string; query: string }) { +function HighlightQuery({text, query}: {text: string; query: string}) { return ( - ) + ); } function SearchResult({ @@ -154,19 +153,19 @@ function SearchResult({ collection, query, }: { - result: Result - autocomplete: Autocomplete - collection: AutocompleteCollection - query: string + result: Result; + autocomplete: Autocomplete; + collection: AutocompleteCollection; + query: string; }) { - let id = useId() + let id = useId(); - let sectionTitle = navigation.find((section) => - section.links.find((link) => link.href === result.url.split('#')[0]), - )?.title + let sectionTitle = navigation.find(section => + section.links.find(link => link.href === result.url.split('#')[0]), + )?.title; let hierarchy = [sectionTitle, result.pageTitle].filter( (x): x is string => typeof x === 'string', - ) + ); return (
  • + })}> {hierarchy.length > 0 && ( )}
  • - ) + ); } function SearchResults({ @@ -215,9 +210,9 @@ function SearchResults({ query, collection, }: { - autocomplete: Autocomplete - query: string - collection: AutocompleteCollection + autocomplete: Autocomplete; + query: string; + collection: AutocompleteCollection; }) { if (collection.items.length === 0) { return ( @@ -228,12 +223,12 @@ function SearchResults({ ”

    - ) + ); } return (
      - {collection.items.map((result) => ( + {collection.items.map(result => ( ))}
    - ) + ); } const SearchInput = forwardRef< React.ElementRef<'input'>, { - autocomplete: Autocomplete - autocompleteState: AutocompleteState | EmptyObject - onClose: () => void + autocomplete: Autocomplete; + autocompleteState: AutocompleteState | EmptyObject; + onClose: () => void; } ->(function SearchInput({ autocomplete, autocompleteState, onClose }, inputRef) { - let inputProps = autocomplete.getInputProps({ inputElement: null }) +>(function SearchInput({autocomplete, autocompleteState, onClose}, inputRef) { + let inputProps = autocomplete.getInputProps({inputElement: null}); return (
    @@ -262,11 +257,11 @@ const SearchInput = forwardRef< { + onKeyDown={event => { if ( event.key === 'Escape' && !autocompleteState.isOpen && @@ -275,12 +270,12 @@ const SearchInput = forwardRef< // In Safari, closing the dialog with the escape key can sometimes cause the scroll position to jump to the // bottom of the page. This is a workaround for that until we can figure out a proper fix in Headless UI. if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur() + document.activeElement.blur(); } - onClose() + onClose(); } else { - inputProps.onKeyDown(event) + inputProps.onKeyDown(event); } }} /> @@ -290,24 +285,24 @@ const SearchInput = forwardRef<
    )}
    - ) -}) + ); +}); function CloseOnNavigation({ close, autocomplete, }: { - close: (autocomplete: Autocomplete) => void - autocomplete: Autocomplete + close: (autocomplete: Autocomplete) => void; + autocomplete: Autocomplete; }) { - let pathname = usePathname() - let searchParams = useSearchParams() + let pathname = usePathname(); + let searchParams = useSearchParams(); useEffect(() => { - close(autocomplete) - }, [pathname, searchParams, close, autocomplete]) + close(autocomplete); + }, [pathname, searchParams, close, autocomplete]); - return null + return null; } function SearchDialog({ @@ -315,46 +310,46 @@ function SearchDialog({ setOpen, className, }: { - open: boolean - setOpen: (open: boolean) => void - className?: string + open: boolean; + setOpen: (open: boolean) => void; + className?: string; }) { - let formRef = useRef>(null) - let panelRef = useRef>(null) - let inputRef = useRef>(null) + let formRef = useRef>(null); + let panelRef = useRef>(null); + let inputRef = useRef>(null); let close = useCallback( (autocomplete: Autocomplete) => { - setOpen(false) - autocomplete.setQuery('') + setOpen(false); + autocomplete.setQuery(''); }, [setOpen], - ) + ); - let { autocomplete, autocompleteState } = useAutocomplete({ + let {autocomplete, autocompleteState} = useAutocomplete({ close() { - close(autocomplete) + close(autocomplete); }, - }) + }); useEffect(() => { if (open) { - return + return; } function onKeyDown(event: KeyboardEvent) { if (event.key === 'k' && (event.metaKey || event.ctrlKey)) { - event.preventDefault() - setOpen(true) + event.preventDefault(); + setOpen(true); } } - window.addEventListener('keydown', onKeyDown) + window.addEventListener('keydown', onKeyDown); return () => { - window.removeEventListener('keydown', onKeyDown) - } - }, [open, setOpen]) + window.removeEventListener('keydown', onKeyDown); + }; + }, [open, setOpen]); return ( <> @@ -364,19 +359,17 @@ function SearchDialog({ close(autocomplete)} - className={clsx('fixed inset-0 z-50', className)} - > + className={clsx('fixed inset-0 z-50', className)}>
    - +
    + })}> + {...autocomplete.getPanelProps({})}> {autocompleteState.isOpen && (
    - ) + ); } function useSearchProps() { - let buttonRef = useRef>(null) - let [open, setOpen] = useState(false) + let buttonRef = useRef>(null); + let [open, setOpen] = useState(false); return { buttonProps: { ref: buttonRef, onClick() { - setOpen(true) + setOpen(true); }, }, dialogProps: { open, setOpen: useCallback((open: boolean) => { - let { width = 0, height = 0 } = - buttonRef.current?.getBoundingClientRect() ?? {} + let {width = 0, height = 0} = + buttonRef.current?.getBoundingClientRect() ?? {}; if (!open || (width !== 0 && height !== 0)) { - setOpen(open) + setOpen(open); } }, []), }, - } + }; } export function Search() { - let [modifierKey, setModifierKey] = useState() - let { buttonProps, dialogProps } = useSearchProps() + let [modifierKey, setModifierKey] = useState(); + let {buttonProps, dialogProps} = useSearchProps(); useEffect(() => { setModifierKey( /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘' : 'Ctrl ', - ) - }, []) + ); + }, []); return ( <> - ) + ); } diff --git a/apps/docs/src/components/TableOfContents.tsx b/apps/docs/src/components/TableOfContents.tsx index 2a8ce2e..06f0903 100644 --- a/apps/docs/src/components/TableOfContents.tsx +++ b/apps/docs/src/components/TableOfContents.tsx @@ -1,64 +1,64 @@ -'use client' +'use client'; -import { useCallback, useEffect, useState } from 'react' -import Link from 'next/link' -import clsx from 'clsx' +import {useCallback, useEffect, useState} from 'react'; +import Link from 'next/link'; +import clsx from 'clsx'; -import { type Section, type Subsection } from '@/lib/sections' +import {type Section, type Subsection} from '@/lib/sections'; export function TableOfContents({ tableOfContents, }: { - tableOfContents: Array
    + tableOfContents: Array
    ; }) { - let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id) + let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id); let getHeadings = useCallback((tableOfContents: Array
    ) => { return tableOfContents - .flatMap((node) => [node.id, ...node.children.map((child) => child.id)]) - .map((id) => { - let el = document.getElementById(id) - if (!el) return null + .flatMap(node => [node.id, ...node.children.map(child => child.id)]) + .map(id => { + let el = document.getElementById(id); + if (!el) return null; - let style = window.getComputedStyle(el) - let scrollMt = parseFloat(style.scrollMarginTop) + let style = window.getComputedStyle(el); + let scrollMt = parseFloat(style.scrollMarginTop); - let top = window.scrollY + el.getBoundingClientRect().top - scrollMt - return { id, top } + let top = window.scrollY + el.getBoundingClientRect().top - scrollMt; + return {id, top}; }) - .filter((x): x is { id: string; top: number } => x !== null) - }, []) + .filter((x): x is {id: string; top: number} => x !== null); + }, []); useEffect(() => { - if (tableOfContents.length === 0) return - let headings = getHeadings(tableOfContents) + if (tableOfContents.length === 0) return; + let headings = getHeadings(tableOfContents); function onScroll() { - let top = window.scrollY - let current = headings[0].id + let top = window.scrollY; + let current = headings[0].id; for (let heading of headings) { if (top >= heading.top - 10) { - current = heading.id + current = heading.id; } else { - break + break; } } - setCurrentSection(current) + setCurrentSection(current); } - window.addEventListener('scroll', onScroll, { passive: true }) - onScroll() + window.addEventListener('scroll', onScroll, {passive: true}); + onScroll(); return () => { - window.removeEventListener('scroll', onScroll) - } - }, [getHeadings, tableOfContents]) + window.removeEventListener('scroll', onScroll); + }; + }, [getHeadings, tableOfContents]); function isActive(section: Section | Subsection) { if (section.id === currentSection) { - return true + return true; } if (!section.children) { - return false + return false; } - return section.children.findIndex(isActive) > -1 + return section.children.findIndex(isActive) > -1; } return ( @@ -68,12 +68,11 @@ export function TableOfContents({ <>

    + className="font-display text-sm font-medium text-slate-900 dark:text-white"> On this page

      - {tableOfContents.map((section) => ( + {tableOfContents.map(section => (
    1. + )}> {section.title}

      {section.children.length > 0 && (
        - {section.children.map((subSection) => ( + className="mt-2 space-y-3 pl-5 text-slate-500 dark:text-slate-400"> + {section.children.map(subSection => (
      1. + }> {subSection.title}
      2. @@ -115,5 +111,5 @@ export function TableOfContents({ )}
    - ) + ); } diff --git a/apps/docs/src/components/ThemeSelector.tsx b/apps/docs/src/components/ThemeSelector.tsx index 1a09c6e..1e043b6 100644 --- a/apps/docs/src/components/ThemeSelector.tsx +++ b/apps/docs/src/components/ThemeSelector.tsx @@ -1,13 +1,13 @@ -import { useEffect, useState } from 'react' -import { useTheme } from 'next-themes' -import { Listbox } from '@headlessui/react' -import clsx from 'clsx' +import {useEffect, useState} from 'react'; +import {useTheme} from 'next-themes'; +import {Listbox} from '@headlessui/react'; +import clsx from 'clsx'; const themes = [ - { name: 'Light', value: 'light', icon: LightIcon }, - { name: 'Dark', value: 'dark', icon: DarkIcon }, - { name: 'System', value: 'system', icon: SystemIcon }, -] + {name: 'Light', value: 'light', icon: LightIcon}, + {name: 'Dark', value: 'dark', icon: DarkIcon}, + {name: 'System', value: 'system', icon: SystemIcon}, +]; function LightIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( @@ -18,7 +18,7 @@ function LightIcon(props: React.ComponentPropsWithoutRef<'svg'>) { d="M7 1a1 1 0 0 1 2 0v1a1 1 0 1 1-2 0V1Zm4 7a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm2.657-5.657a1 1 0 0 0-1.414 0l-.707.707a1 1 0 0 0 1.414 1.414l.707-.707a1 1 0 0 0 0-1.414Zm-1.415 11.313-.707-.707a1 1 0 0 1 1.415-1.415l.707.708a1 1 0 0 1-1.415 1.414ZM16 7.999a1 1 0 0 0-1-1h-1a1 1 0 1 0 0 2h1a1 1 0 0 0 1-1ZM7 14a1 1 0 1 1 2 0v1a1 1 0 1 1-2 0v-1Zm-2.536-2.464a1 1 0 0 0-1.414 0l-.707.707a1 1 0 0 0 1.414 1.414l.707-.707a1 1 0 0 0 0-1.414Zm0-8.486A1 1 0 0 1 3.05 4.464l-.707-.707a1 1 0 0 1 1.414-1.414l.707.707ZM3 8a1 1 0 0 0-1-1H1a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Z" /> - ) + ); } function DarkIcon(props: React.ComponentPropsWithoutRef<'svg'>) { @@ -30,7 +30,7 @@ function DarkIcon(props: React.ComponentPropsWithoutRef<'svg'>) { d="M7.23 3.333C7.757 2.905 7.68 2 7 2a6 6 0 1 0 0 12c.68 0 .758-.905.23-1.332A5.989 5.989 0 0 1 5 8c0-1.885.87-3.568 2.23-4.668ZM12 5a1 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 0 2 1 1 0 0 0-1 1 1 1 0 1 1-2 0 1 1 0 0 0-1-1 1 1 0 1 1 0-2 1 1 0 0 0 1-1 1 1 0 0 1 1-1Z" /> - ) + ); } function SystemIcon(props: React.ComponentPropsWithoutRef<'svg'>) { @@ -42,21 +42,21 @@ function SystemIcon(props: React.ComponentPropsWithoutRef<'svg'>) { d="M1 4a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v4a3 3 0 0 1-3 3h-1.5l.31 1.242c.084.333.36.573.63.808.091.08.182.158.264.24A1 1 0 0 1 11 15H5a1 1 0 0 1-.704-1.71c.082-.082.173-.16.264-.24.27-.235.546-.475.63-.808L5.5 11H4a3 3 0 0 1-3-3V4Zm3-1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4Z" /> - ) + ); } export function ThemeSelector( props: React.ComponentPropsWithoutRef>, ) { - let { theme, setTheme } = useTheme() - let [mounted, setMounted] = useState(false) + let {theme, setTheme} = useTheme(); + let [mounted, setMounted] = useState(false); useEffect(() => { - setMounted(true) - }, []) + setMounted(true); + }, []); if (!mounted) { - return
    + return
    ; } return ( @@ -64,8 +64,7 @@ export function ThemeSelector( Theme + aria-label="Theme"> - {themes.map((theme) => ( + {themes.map(theme => ( + className={({active, selected}) => clsx( 'flex cursor-pointer select-none items-center rounded-[0.625rem] p-1', { @@ -94,9 +93,8 @@ export function ThemeSelector( 'bg-slate-100 dark:bg-slate-900/40': active, }, ) - } - > - {({ selected }) => ( + }> + {({selected}) => ( <>
    - ) + ); } diff --git a/apps/docs/src/components/icons/InstallationIcon.tsx b/apps/docs/src/components/icons/InstallationIcon.tsx index c81a5e3..947230b 100644 --- a/apps/docs/src/components/icons/InstallationIcon.tsx +++ b/apps/docs/src/components/icons/InstallationIcon.tsx @@ -1,11 +1,11 @@ -import { DarkMode, Gradient, LightMode } from '@/components/Icon' +import {DarkMode, Gradient, LightMode} from '@/components/Icon'; export function InstallationIcon({ id, color, }: { - id: string - color?: React.ComponentProps['color'] + id: string; + color?: React.ComponentProps['color']; }) { return ( <> @@ -43,5 +43,5 @@ export function InstallationIcon({ /> - ) + ); } diff --git a/apps/docs/src/components/icons/LightbulbIcon.tsx b/apps/docs/src/components/icons/LightbulbIcon.tsx index 7367f51..5de9007 100644 --- a/apps/docs/src/components/icons/LightbulbIcon.tsx +++ b/apps/docs/src/components/icons/LightbulbIcon.tsx @@ -1,11 +1,11 @@ -import { DarkMode, Gradient, LightMode } from '@/components/Icon' +import {DarkMode, Gradient, LightMode} from '@/components/Icon'; export function LightbulbIcon({ id, color, }: { - id: string - color?: React.ComponentProps['color'] + id: string; + color?: React.ComponentProps['color']; }) { return ( <> @@ -48,5 +48,5 @@ export function LightbulbIcon({ /> - ) + ); } diff --git a/apps/docs/src/components/icons/PluginsIcon.tsx b/apps/docs/src/components/icons/PluginsIcon.tsx index 2caf217..2f1714e 100644 --- a/apps/docs/src/components/icons/PluginsIcon.tsx +++ b/apps/docs/src/components/icons/PluginsIcon.tsx @@ -1,11 +1,11 @@ -import { DarkMode, Gradient, LightMode } from '@/components/Icon' +import {DarkMode, Gradient, LightMode} from '@/components/Icon'; export function PluginsIcon({ id, color, }: { - id: string - color?: React.ComponentProps['color'] + id: string; + color?: React.ComponentProps['color']; }) { return ( <> @@ -33,8 +33,7 @@ export function PluginsIcon({ className="fill-[var(--icon-background)] stroke-[color:var(--icon-foreground)]" strokeWidth={2} strokeLinecap="round" - strokeLinejoin="round" - > + strokeLinejoin="round"> @@ -47,8 +46,7 @@ export function PluginsIcon({ className="stroke-[color:var(--icon-foreground)]" strokeWidth={2} strokeLinecap="round" - strokeLinejoin="round" - > + strokeLinejoin="round"> @@ -65,5 +63,5 @@ export function PluginsIcon({ /> - ) + ); } diff --git a/apps/docs/src/components/icons/PresetsIcon.tsx b/apps/docs/src/components/icons/PresetsIcon.tsx index e01b953..0dc7e5d 100644 --- a/apps/docs/src/components/icons/PresetsIcon.tsx +++ b/apps/docs/src/components/icons/PresetsIcon.tsx @@ -1,11 +1,11 @@ -import { DarkMode, Gradient, LightMode } from '@/components/Icon' +import {DarkMode, Gradient, LightMode} from '@/components/Icon'; export function PresetsIcon({ id, color, }: { - id: string - color?: React.ComponentProps['color'] + id: string; + color?: React.ComponentProps['color']; }) { return ( <> @@ -28,8 +28,7 @@ export function PresetsIcon({ fillOpacity={0.5} strokeWidth={2} strokeLinecap="round" - strokeLinejoin="round" - > + strokeLinejoin="round"> @@ -45,5 +44,5 @@ export function PresetsIcon({ - ) + ); } diff --git a/apps/docs/src/components/icons/ThemingIcon.tsx b/apps/docs/src/components/icons/ThemingIcon.tsx index 02876f7..252de0d 100644 --- a/apps/docs/src/components/icons/ThemingIcon.tsx +++ b/apps/docs/src/components/icons/ThemingIcon.tsx @@ -1,11 +1,11 @@ -import { DarkMode, Gradient, LightMode } from '@/components/Icon' +import {DarkMode, Gradient, LightMode} from '@/components/Icon'; export function ThemingIcon({ id, color, }: { - id: string - color?: React.ComponentProps['color'] + id: string; + color?: React.ComponentProps['color']; }) { return ( <> @@ -61,5 +61,5 @@ export function ThemingIcon({ /> - ) + ); } diff --git a/apps/docs/src/components/icons/WarningIcon.tsx b/apps/docs/src/components/icons/WarningIcon.tsx index abed5e3..f43d352 100644 --- a/apps/docs/src/components/icons/WarningIcon.tsx +++ b/apps/docs/src/components/icons/WarningIcon.tsx @@ -1,11 +1,11 @@ -import { DarkMode, Gradient, LightMode } from '@/components/Icon' +import {DarkMode, Gradient, LightMode} from '@/components/Icon'; export function WarningIcon({ id, color, }: { - id: string - color?: React.ComponentProps['color'] + id: string; + color?: React.ComponentProps['color']; }) { return ( <> @@ -57,5 +57,5 @@ export function WarningIcon({ /> - ) + ); } diff --git a/apps/docs/src/lib/navigation.ts b/apps/docs/src/lib/navigation.ts index 645fa87..de038a5 100644 --- a/apps/docs/src/lib/navigation.ts +++ b/apps/docs/src/lib/navigation.ts @@ -2,18 +2,18 @@ export const navigation = [ { title: 'Docs', links: [ - { title: 'Introduction', href: '/docs/' }, - { title: 'Getting started', href: '/docs/getting-started' }, - { title: 'Support', href: '/docs/support' }, - { title: 'Contributing', href: '/docs/contributing' }, + {title: 'Introduction', href: '/docs/'}, + {title: 'Getting started', href: '/docs/getting-started'}, + {title: 'Support', href: '/docs/support'}, + {title: 'Contributing', href: '/docs/contributing'}, ], }, { title: 'Follow us', links: [ - { title: 'Github', href: 'https://github.com/elwood-software/elwood' }, - { title: 'Twitter', href: 'https://twitter.com/hello_elwood' }, - { title: 'Discord', href: 'https://discord.gg/mkhKk5db' }, + {title: 'Github', href: 'https://github.com/elwood-software/elwood'}, + {title: 'Twitter', href: 'https://twitter.com/hello_elwood'}, + {title: 'Discord', href: 'https://discord.gg/mkhKk5db'}, ], }, -] +]; diff --git a/apps/docs/src/lib/sections.ts b/apps/docs/src/lib/sections.ts index afb1bfe..d9d31db 100644 --- a/apps/docs/src/lib/sections.ts +++ b/apps/docs/src/lib/sections.ts @@ -1,26 +1,26 @@ -import { type Node } from '@markdoc/markdoc' -import { slugifyWithCounter } from '@sindresorhus/slugify' +import {type Node} from '@markdoc/markdoc'; +import {slugifyWithCounter} from '@sindresorhus/slugify'; interface HeadingNode extends Node { - type: 'heading' + type: 'heading'; attributes: { - level: 1 | 2 | 3 | 4 | 5 | 6 - id?: string - [key: string]: unknown - } + level: 1 | 2 | 3 | 4 | 5 | 6; + id?: string; + [key: string]: unknown; + }; } type H2Node = HeadingNode & { attributes: { - level: 2 - } -} + level: 2; + }; +}; type H3Node = HeadingNode & { attributes: { - level: 3 - } -} + level: 3; + }; +}; function isHeadingNode(node: Node): node is HeadingNode { return ( @@ -28,70 +28,70 @@ function isHeadingNode(node: Node): node is HeadingNode { [1, 2, 3, 4, 5, 6].includes(node.attributes.level) && (typeof node.attributes.id === 'string' || typeof node.attributes.id === 'undefined') - ) + ); } function isH2Node(node: Node): node is H2Node { - return isHeadingNode(node) && node.attributes.level === 2 + return isHeadingNode(node) && node.attributes.level === 2; } function isH3Node(node: Node): node is H3Node { - return isHeadingNode(node) && node.attributes.level === 3 + return isHeadingNode(node) && node.attributes.level === 3; } function getNodeText(node: Node) { - let text = '' + let text = ''; for (let child of node.children ?? []) { if (child.type === 'text') { - text += child.attributes.content + text += child.attributes.content; } - text += getNodeText(child) + text += getNodeText(child); } - return text + return text; } export type Subsection = H3Node['attributes'] & { - id: string - title: string - children?: undefined -} + id: string; + title: string; + children?: undefined; +}; export type Section = H2Node['attributes'] & { - id: string - title: string - children: Array -} + id: string; + title: string; + children: Array; +}; export function collectSections( nodes: Array, slugify = slugifyWithCounter(), ) { - let sections: Array
    = [] + let sections: Array
    = []; for (let node of nodes) { if (isH2Node(node) || isH3Node(node)) { - let title = getNodeText(node) + let title = getNodeText(node); if (title) { - let id = slugify(title) + let id = slugify(title); if (isH3Node(node)) { if (!sections[sections.length - 1]) { throw new Error( 'Cannot add `h3` to table of contents without a preceding `h2`', - ) + ); } sections[sections.length - 1].children.push({ ...node.attributes, id, title, - }) + }); } else { - sections.push({ ...node.attributes, id, title, children: [] }) + sections.push({...node.attributes, id, title, children: []}); } } } - sections.push(...collectSections(node.children ?? [], slugify)) + sections.push(...collectSections(node.children ?? [], slugify)); } - return sections + return sections; } diff --git a/apps/docs/tailwind.config.ts b/apps/docs/tailwind.config.ts index d8a61ad..b0c98e2 100644 --- a/apps/docs/tailwind.config.ts +++ b/apps/docs/tailwind.config.ts @@ -36,5 +36,5 @@ export default { }, }, }, - plugins: [...Array.from(plugins as PluginCreator[]), typographyPlugin], + plugins: [...Array.from(plugins as PluginCreator[]), typographyPlugin], } satisfies Config diff --git a/apps/docs/types.d.ts b/apps/docs/types.d.ts index 349d908..9d58ccb 100644 --- a/apps/docs/types.d.ts +++ b/apps/docs/types.d.ts @@ -1,11 +1,11 @@ -import { type SearchOptions } from 'flexsearch' +import {type SearchOptions} from 'flexsearch'; declare module '@/markdoc/search.mjs' { export type Result = { - url: string - title: string - pageTitle?: string - } + url: string; + title: string; + pageTitle?: string; + }; - export function search(query: string, options?: SearchOptions): Array + export function search(query: string, options?: SearchOptions): Array; } diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..9ed8605 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,20 @@ +/** @type {import('prettier').Options} */ +module.exports = { + tabWidth: 2, + arrowParens: "avoid", + bracketSameLine: true, + bracketSpacing: false, + singleQuote: true, + trailingComma: "all", + plugins: ["prettier-plugin-sql-cst"], + overrides: [ + { + files: "**/*.json", + options: {parser: "json"} + }, + { + files: ["*.sql"], + options: {parser: "postgresql"} + } + ] +} From bdd6606600a7ec09833da78dafce0cf96f8d48f8 Mon Sep 17 00:00:00 2001 From: Travis Kuhl Date: Tue, 14 May 2024 10:08:38 -0700 Subject: [PATCH 3/3] fix format --- apps/docs/tailwind.config.ts | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/docs/tailwind.config.ts b/apps/docs/tailwind.config.ts index b0c98e2..2cfcab3 100644 --- a/apps/docs/tailwind.config.ts +++ b/apps/docs/tailwind.config.ts @@ -1,9 +1,9 @@ -import typographyPlugin from '@tailwindcss/typography' -import type { PluginCreator } from 'postcss' -import { type Config } from 'tailwindcss' -import { darkMode, theme, plugins } from '@elwood/ui/tailwind.config.js' +import typographyPlugin from '@tailwindcss/typography'; +import type {PluginCreator} from 'postcss'; +import {type Config} from 'tailwindcss'; +import {darkMode, theme, plugins} from '@elwood/ui/tailwind.config.js'; -const themeExtend = theme?.extend || {} +const themeExtend = theme?.extend || {}; export default { content: ['./src/**/*.{js,jsx,ts,tsx,md}'], @@ -11,25 +11,25 @@ export default { theme: { ...theme, fontSize: { - xs: ['0.75rem', { lineHeight: '1rem' }], - sm: ['0.875rem', { lineHeight: '1.5rem' }], - base: ['1rem', { lineHeight: '2rem' }], - lg: ['1.125rem', { lineHeight: '1.75rem' }], - xl: ['1.25rem', { lineHeight: '2rem' }], - '2xl': ['1.5rem', { lineHeight: '2.5rem' }], - '3xl': ['2rem', { lineHeight: '2.5rem' }], - '4xl': ['2.5rem', { lineHeight: '3rem' }], - '5xl': ['3rem', { lineHeight: '3.5rem' }], - '6xl': ['3.75rem', { lineHeight: '1' }], - '7xl': ['4.5rem', { lineHeight: '1' }], - '8xl': ['6rem', { lineHeight: '1' }], - '9xl': ['8rem', { lineHeight: '1' }], + xs: ['0.75rem', {lineHeight: '1rem'}], + sm: ['0.875rem', {lineHeight: '1.5rem'}], + base: ['1rem', {lineHeight: '2rem'}], + lg: ['1.125rem', {lineHeight: '1.75rem'}], + xl: ['1.25rem', {lineHeight: '2rem'}], + '2xl': ['1.5rem', {lineHeight: '2.5rem'}], + '3xl': ['2rem', {lineHeight: '2.5rem'}], + '4xl': ['2.5rem', {lineHeight: '3rem'}], + '5xl': ['3rem', {lineHeight: '3.5rem'}], + '6xl': ['3.75rem', {lineHeight: '1'}], + '7xl': ['4.5rem', {lineHeight: '1'}], + '8xl': ['6rem', {lineHeight: '1'}], + '9xl': ['8rem', {lineHeight: '1'}], }, extend: { ...themeExtend, fontFamily: { sans: 'var(--font-inter)', - display: ['var(--font-lexend)', { fontFeatureSettings: '"ss01"' }], + display: ['var(--font-lexend)', {fontFeatureSettings: '"ss01"'}], }, maxWidth: { '8xl': '88rem', @@ -37,4 +37,4 @@ export default { }, }, plugins: [...Array.from(plugins as PluginCreator[]), typographyPlugin], -} satisfies Config +} satisfies Config;