diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index 9c4e09ba8..398328ef5 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -23,9 +23,6 @@ jobs: - name: Install tools & dependencies uses: ./.github/actions/install - - name: Generate virtual modules - run: pnpm sync - - name: TypeScript check run: pnpm check:types diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..474a57d70 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +ignore-workspace-root-check=true +auto-install-peers=false diff --git a/README.md b/README.md index 035aea0fd..3a195a435 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Welcome to Solid's documentation! -This is the repo for [docs.solidjs.com](https://docs.solidjs.com/). This repo +This is the repo for [docs.solidjs.com](https://docs.solidjs.com/). This repo contains all the source code that we use to build our docs. [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/solidjs/solid-docs-next) @@ -37,9 +37,9 @@ Have you noticed something is missing, confusing, or is wrong in our documentation? Check to see if it has -[already been mentioned ](https://github.com/solidjs/solid-docs-next/issues) +[already been mentioned ](https://github.com/solidjs/solid-docs/issues) and, if not, -[create an issue](https://github.com/solidjs/solid-docs-next/issues/new/choose) +[create an issue](https://github.com/solidjs/solid-docs/issues/new/choose) to bring it to our attention! ## Share an idea @@ -51,7 +51,7 @@ Discussion threads are where you can offer feedback on things that might not be problems that need addressing, but are ideas to be explored. Join us in the -[Discussions section](https://github.com/solidjs/solid-docs-next/discussions/280) +[Discussions section](https://github.com/solidjs/solid-docs/discussions/280) where we can brainstorm these ideas, ask questions, and share goals! ## Suggest a fix or contribute @@ -62,19 +62,19 @@ If you can see what the problem is, and you know how to fix it, you can make a PR (pull request) with the change and contribute to the docs repo yourself. If you're looking to make a larger contribution, please see our -[CONTRIBUTING.md](https://github.com/solidjs/solid-docs-next/blob/main/CONTRIBUTING.md) +[CONTRIBUTING.md](https://github.com/solidjs/solid-docs/blob/main/CONTRIBUTING.md) first! ## Running the Site Locally At the moment, we recommend running the site locally through either -[CodeSandbox](https://codesandbox.io/p/github/solidjs/solid-docs-next/), -[Gitpod](https://gitpod.io/#https://github.com/solidjs/solid-docs-next), or -[StackBlitz](https://stackblitz.com/github/solidjs/solid-docs-next). These are +[CodeSandbox](https://codesandbox.io/p/github/solidjs/solid-docs/), +[Gitpod](https://gitpod.io/#https://github.com/solidjs/solid-docs), or +[StackBlitz](https://stackblitz.com/github/solidjs/solid-docs). These are the quickest and easiest way to browse and edit the project files and run the site locally. -The app uses [pnpm](https://pnpm.io) as the package manager and it runs on Node.js `v18+`. +The app uses [pnpm](https://pnpm.io) as the package manager and it runs on Node.js `v22+`. Install dependencies: @@ -90,9 +90,8 @@ pnpm dev This will start your the app at [localhost:3000](http://localhost:3000) or the next available port. -### Collections and virtual modules +### Framework and Theme -The builds an [Astro](https://docs.astro.build/en/guides/content-collections/) inspired collection navigation, it will bring all routes and generate a couple of files at `/.solid`. -These files are exposed to your app via [Vite virtual modules](https://vitejs.dev/guide/api-plugin#virtual-modules-convention). This task is perform via our `sync` script (`pnpm sync`), ran before every build. +The docs are built on [SolidBase](https://solidbase.dev) and uses the [Osmium Theme](./osmium). -If changes are made to the navigation (new entry, or repositioning entry), it is necessary to restart the server for changes to take effect. +This repo should only contain content as mdx files, features should be implemented upstream and UI changes in the theme. diff --git a/app.config.ts b/app.config.ts deleted file mode 100644 index 3313de230..000000000 --- a/app.config.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { defineConfig } from "@solidjs/start/config"; - -import { createWithSolidBase, defineTheme } from "@kobalte/solidbase/config"; - -import tree from "./.solid/tree"; -import entries from "./.solid/flat-entries"; -import solidstartEntries from "./.solid/solid-start-flat-entries"; -import solidrouterEntries from "./.solid/solid-router-flat-entries"; -import solidMetaEntries from "./.solid/solid-meta-flat-entries"; -import solidrouterTree from "./.solid/solid-router-tree"; -import solidStartTree from "./.solid/solid-start-tree"; -import solidMetaTree from "./.solid/solid-meta-tree"; - -function docsData() { - const virtualModuleId = "solid:collection"; - const resolveVirtualModuleId = "\0" + virtualModuleId; - - return { - name: virtualModuleId, - resolveId(id: string) { - if (id === virtualModuleId) { - return resolveVirtualModuleId; - } - }, - async load(id: string) { - if (id === resolveVirtualModuleId) { - return ` - export const coreEntries = ${JSON.stringify(entries, null, 2)} - export const routerEntries = ${JSON.stringify(solidrouterEntries, null, 2)} - export const startEntries = ${JSON.stringify(solidstartEntries, null, 2)} - export const metaEntries = ${JSON.stringify(solidMetaEntries, null, 2)} - export const coreTree = ${JSON.stringify(tree, null, 2)} - export const routerTree = ${JSON.stringify(solidrouterTree, null, 2)} - export const startTree = ${JSON.stringify(solidStartTree, null, 2)} - export const metaTree = ${JSON.stringify(solidMetaTree, null, 2)} - `; - } - }, - }; -} - -const theme = defineTheme({ - componentsPath: import.meta.resolve("./src/solidbase-theme"), -}); -export default defineConfig( - createWithSolidBase(theme)( - { - ssr: true, - middleware: "src/middleware/index.ts", - server: { - preset: "netlify", - prerender: { - crawlLinks: true, - autoSubfolderIndex: false, - failOnError: true, - // eslint-disable-next-line no-useless-escape - ignore: [/\{\getPath}/, /.*?emojiSvg\(.*/], - }, - }, - vite: { - plugins: [docsData(), heroCodeSnippet()], - }, - }, - { - title: "Solid Docs", - description: - "Documentation for SolidJS, the signals-powered UI framework", - editPath: "https://github.com/solidjs/solid-docs/edit/main/:path", - markdown: { - expressiveCode: { - themes: ["min-light", "material-theme-ocean"], - themeCssSelector: (theme) => `[data-theme="${theme.type}"]`, - frames: false, - styleOverrides: { - twoSlash: { - cursorColor: "var(--twoslash-cursor)", - }, - }, - }, - toc: { - minDepth: 2, - }, - packageManagers: { - presets: { - npm: { - install: "npm i :content", - "install-dev": "npm i :content -D", - "install-global": "npm i :content -g", - "install-local": "npm i", - remove: "npm remove :content", - update: "npm update :content", - run: "npm run :content", - exec: "npx :content", - create: "npm init :content", - }, - pnpm: { - install: "pnpm i :content", - "install-dev": "pnpm i :content -D", - "install-global": "pnpm i :content -g", - "install-local": "pnpm i", - remove: "pnpm remove :content", - update: "pnpm update :content", - run: "pnpm :content", - exec: "pnpx :content", - create: "pnpm create :content", - }, - yarn: { - install: "yarn add :content", - "install-dev": "yarn add :content -D", - "install-global": "yarn add :content -g", - "install-local": "yarn i", - remove: "yarn remove :content", - update: "yarn upgrade :content", - run: "yarn :content", - exec: "yarn dlx :content", - create: "yarn create :content", - }, - bun: { - install: "bun i :content", - "install-dev": "bun i :content -d", - "install-global": "bun i :content -g", - "install-local": "bun i", - remove: "bun remove :content", - update: "bun update :content", - run: "bun run :content", - exec: "bunx :content", - create: "bun create :content", - }, - deno: { - install: "deno add npm::content", - "install-dev": "deno add npm::content -D", - "install-global": "deno add npm::content -g", - "install-local": "deno i", - remove: "deno remove npm::content", - update: "deno update npm::content", - run: "deno run :content", - exec: "dpx :content", - create: "deno init --npm :content", - }, - }, - }, - }, - } - ) -); - -import { readFile } from "node:fs/promises"; -import { codeToHtml } from "shiki"; - -function heroCodeSnippet() { - const virtualModuleId = "solid:hero-code-snippet"; - const resolveVirtualModuleId = "\0" + virtualModuleId; - - return { - name: virtualModuleId, - resolveId(id: string) { - if (id === virtualModuleId) { - return resolveVirtualModuleId; - } - }, - async load(id: string) { - if (id === resolveVirtualModuleId) { - const snippet = await readFile( - "./src/ui/layout/hero-code-snippet.code", - "utf-8" - ); - - const highlightedCode = await codeToHtml(snippet.trim(), { - lang: "tsx", - theme: "material-theme-ocean", - }); - - return `export const highlightedCode = \`${highlightedCode}\``; - } - }, - }; -} diff --git a/env.d.ts b/env.d.ts index eaa53030d..d92c7e41c 100644 --- a/env.d.ts +++ b/env.d.ts @@ -16,13 +16,3 @@ declare namespace NodeJS { readonly ORAMA_PRIVATE_API_KEY: string; } } - -declare module "solid:collection" { - // eslint-disable-next-line - const component: any; - export default component; -} - -declare module "solid:hero-code-snippet" { - export const highlightedCode: string; -} diff --git a/global.d.ts b/global.d.ts deleted file mode 100644 index fd182f46a..000000000 --- a/global.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -declare module "solid:collection" { - import coreTree from ".solid/tree"; - import startTree from ".solid/solid-router-tree"; - import routerTree from ".solid/solid-start-tree"; - import metaTree from ".solid/solid-meta-tree"; - import coreEntries from ".solid/flat-entries"; - import routerEntries from ".solid/solid-start-flat-entries"; - import startEntries from ".solid/solid-router-flat-entries"; - import metaEntries from ".solid/solid-meta-flat-entries"; - - export { - coreEntries, - routerEntries, - startEntries, - metaEntries, - coreTree, - routerTree, - startTree, - metaTree, - }; -} diff --git a/osmium/README.md b/osmium/README.md new file mode 100644 index 000000000..ba4eb1e23 --- /dev/null +++ b/osmium/README.md @@ -0,0 +1,26 @@ +# Osmium + +Official SolidJS docs theme for SolidBase. + +## Installation + +```sh +npm i solidbase-osmium +``` + +In your `vite.config.ts`: + +```ts +import { osmium } from "solidbase-osmium"; + +const solidBase = createSolidBase(osmium); + +export default defineConfig({ + ...solidBase.startConfig({ + ... + }), + plugins: [solidBase.plugin({ ... })], +}) +```` + +More information in the [SolidBase docs for consuming a theme.](https://solidbase.dev/guide/customization/custom-themes#consuming-a-theme) diff --git a/osmium/package.json b/osmium/package.json new file mode 100644 index 000000000..f80ab8f97 --- /dev/null +++ b/osmium/package.json @@ -0,0 +1,50 @@ +{ + "name": "solidbase-osmium", + "version": "0.0.0-dev", + "description": "Official SolidJS docs theme for SolidBase.", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "url": "https://github.com/solidjs/solid-docs" + }, + "keywords": [ + "solid", + "solidjs", + "solidbase", + "theme" + ], + "files": [ + "src" + ], + "exports": { + ".": { + "solid": "./src/index.ts", + "import": "./src/index.ts", + "types": "./src/index.ts" + }, + "./style": "./src/index.css" + }, + "license": "MIT", + "dependencies": { + "@fontsource-variable/geist": "^5.2.8", + "@fontsource-variable/geist-mono": "^5.2.7", + "@kobalte/core": "^0.13.11", + "@kobalte/solidbase": "^0.4.2", + "@orama/core": "^1.2.19", + "@solid-primitives/context": "^0.3.2", + "@solid-primitives/event-listener": "^2.4.5", + "@solid-primitives/marker": "^0.2.2", + "@solid-primitives/platform": "^0.2.1", + "@solidjs/router": "0.15.3", + "solid-heroicons": "^3.2.4", + "solid-js": "^1.9.11", + "tailwindcss": "^4.2.2", + "@kobalte/tailwindcss": "^0.9.0", + "@tailwindcss/typography": "^0.5.19" + }, + "peerDependencies": { + "tailwindcss": "^4.2.2" + } +} diff --git a/osmium/src/Layout.tsx b/osmium/src/Layout.tsx new file mode 100644 index 000000000..15046315a --- /dev/null +++ b/osmium/src/Layout.tsx @@ -0,0 +1,25 @@ +import { ErrorBoundary } from "solid-js"; + +import { Layout } from "./ui/layout"; +import { NotFound } from "./ui/not-found"; +import { SidebarProvider, useThemeListener } from "@kobalte/solidbase/client"; +import { usePace } from "@kobalte/solidbase/default-theme/pace.js"; +import { useRouteConfig } from "./utils"; +import { OsmiumThemeStateProvider } from "./context"; +import { ParentProps } from "solid-js"; + +export default function (props: ParentProps) { + const config = useRouteConfig(); + useThemeListener(); + usePace(); + + return ( + + + }> + {props.children} + + + + ); +} diff --git a/osmium/src/context.ts b/osmium/src/context.ts new file mode 100644 index 000000000..b92ee6ec6 --- /dev/null +++ b/osmium/src/context.ts @@ -0,0 +1,34 @@ +import { createSignal } from "solid-js"; +import { createContextProvider } from "@solid-primitives/context"; +import { useOsmiumThemeFrontmatter } from "./frontmatter"; + +const [OsmiumThemeStateProvider, useOsmiumThemeStateContext] = + createContextProvider(() => { + const [sidebarOpen, setSidebarOpen] = createSignal(false); + const [tocOpen, setTocOpen] = createSignal(false); + const [navOpen, setNavOpen] = createSignal(false); + const frontmatter = useOsmiumThemeFrontmatter(); + + return { + sidebarOpen, + setSidebarOpen, + tocOpen, + setTocOpen, + navOpen, + setNavOpen, + frontmatter, + }; + }); + +export function useOsmiumThemeState() { + return ( + useOsmiumThemeStateContext() ?? + (() => { + throw new Error( + "useOsmiumThemeState must be used within a OsmiumThemeStateProvider" + ); + })() + ); +} + +export { OsmiumThemeStateProvider }; diff --git a/osmium/src/env.d.ts b/osmium/src/env.d.ts new file mode 100644 index 000000000..c3c9c552c --- /dev/null +++ b/osmium/src/env.d.ts @@ -0,0 +1,8 @@ +interface ImportMetaEnv { + readonly VITE_ORAMA_PROJECT_ID?: string; + readonly VITE_ORAMA_PUBLIC_API_KEY?: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/osmium/src/frontmatter.ts b/osmium/src/frontmatter.ts new file mode 100644 index 000000000..6f4b0aef0 --- /dev/null +++ b/osmium/src/frontmatter.ts @@ -0,0 +1,78 @@ +import { BaseFrontmatter, useFrontmatter } from "@kobalte/solidbase/client"; +import { createMemo } from "solid-js"; + +export function useOsmiumThemeFrontmatter() { + const frontmatter = useFrontmatter(); + + return createMemo(() => { + const data = frontmatter(); + if (!data) return data; + + data.editLink ??= true; + data.lastUpdated ??= true; + + if (data?.layout === "home") { + data.sidebar = false; + data.footer = false; + data.toc = false; + data.prev = false; + data.next = false; + data.editLink = false; + data.lastUpdated = false; + } + + return data; + }); +} + +export type RelativePageConfig = + | string + | false + | { + text?: string; + link?: string; + }; + +interface OsmiumThemeBaseFrontmatter { + category?: string; + sidebar?: boolean; + footer?: boolean; + toc?: boolean; + prev?: RelativePageConfig; + next?: RelativePageConfig; + editLink?: boolean; + lastUpdated?: boolean; +} + +interface HeroActionConfig { + theme?: string; + text?: string; + link?: string; +} + +export interface HeroConfig { + name?: string; + text?: string; + tagline?: string; + image?: { + src: string; + alt?: string; + }; + actions?: Array; +} + +export interface FeaturesConfig { + icon?: string; + title?: string; + details?: string; +} + +interface HomeLayoutFrontmatter { + layout?: "home"; + hero?: HeroConfig; + features?: Array; +} + +export type OsmiumThemeFrontmatter = (BaseFrontmatter & + OsmiumThemeBaseFrontmatter) & + HomeLayoutFrontmatter; diff --git a/src/i18n/dictionaries/en/ui.ts b/osmium/src/i18n/dictionaries/en/ui.ts similarity index 100% rename from src/i18n/dictionaries/en/ui.ts rename to osmium/src/i18n/dictionaries/en/ui.ts diff --git a/src/styles.css b/osmium/src/index.css similarity index 91% rename from src/styles.css rename to osmium/src/index.css index 282bd6dae..b9744cada 100644 --- a/src/styles.css +++ b/osmium/src/index.css @@ -1,9 +1,7 @@ -@import "tailwindcss/base"; +@import "./tailwind.css"; + @import "./styles/prism.css"; @import "./styles/expressive-code.css"; -@import "tailwindcss/components"; -@import "tailwindcss/utilities"; -@import "./styles/fonts.css"; @layer base { html { @@ -90,7 +88,7 @@ @layer utilities { a[data-auto-heading] { - @apply text-slate-900 shadow-none dark:text-white !important; + @apply text-slate-900! shadow-none! dark:text-white!; } a[data-auto-heading]:hover::after { @@ -125,7 +123,10 @@ /* pace from solidbase */ :root { - --bprogress-color: theme("colors.blue.500") !important; + --bprogress-color: var(--color-blue-500) !important; + + --font-geist: "Geist Variable", sans-serif; + --font-geist-mono: "Geist Mono Variable", monospace; } /* twoslash from solidbase */ diff --git a/osmium/src/index.ts b/osmium/src/index.ts new file mode 100644 index 000000000..52b7d9ad6 --- /dev/null +++ b/osmium/src/index.ts @@ -0,0 +1,88 @@ +import { defineTheme } from "@kobalte/solidbase/config"; +import type { SidebarConfig } from "@kobalte/solidbase/config/sidebar"; +import { fileURLToPath } from "node:url"; + +export interface OsmiumThemeConfig { + projects?: ProjectConfig[]; + sidebar?: SidebarConfig; + reportPagePath?: string; + fonts?: { [K in keyof typeof allFonts]?: false } | false; +} + +export interface ProjectConfig { + path: string; + name: string; +} + +type Font = { cssPath: string; preloadFontPath: string; fontType: string }; + +const allFonts = { + geist: { + cssPath: import.meta.resolve("@fontsource-variable/geist"), + preloadFontPath: import.meta + .resolve("@fontsource-variable/geist/files/geist-latin-wght-normal.woff2"), + fontType: "woff2", + }, + geistMono: { + cssPath: import.meta.resolve("@fontsource-variable/geist-mono"), + preloadFontPath: import.meta + .resolve("@fontsource-variable/geist-mono/files/geist-mono-latin-wght-normal.woff2"), + fontType: "woff2", + }, +} satisfies Record; + +export const osmium = defineTheme({ + componentsPath: import.meta.resolve("."), + vite(config) { + const filteredFonts: Array = []; + + if (config?.themeConfig?.fonts !== false) { + const fonts = config?.themeConfig?.fonts; + for (const [font, paths] of Object.entries(allFonts)) { + if (fonts?.[font as keyof typeof fonts] !== false) + filteredFonts.push(paths); + } + } + + return [ + { + name: "solidbase-osmium-fonts", + resolveId(id) { + if (id.startsWith("virtual:solidbase-osmium/fonts.css")) + return "\0virtual:solidbase-osmium/fonts.css"; + if (id.startsWith("virtual:solidbase-osmium/fonts")) + return "\0virtual:solidbase-osmium/fonts"; + }, + load(id) { + if (id.startsWith("\0virtual:solidbase-osmium/fonts.css")) + return filteredFonts + .map( + (font) => + `@import url(${fileURLToPath(font.cssPath, { windows: false })});` + ) + .join("\n"); + if (id.startsWith("\0virtual:solidbase-osmium/fonts")) { + const preloadFonts = filteredFonts.map((font, i) => { + const pathIdent = `font_${i}`; + return { + pathIdent, + import: `import ${pathIdent} from "${fileURLToPath(font.preloadFontPath, { windows: false })}?url";`, + type: font.fontType, + }; + }); + + return ` + ${preloadFonts.map((f) => f.import).join("\n")} + + export const preloadFonts = [ + ${preloadFonts + .map((f) => `{ path: ${f.pathIdent}, type: "${f.type}" }`) + .join(",")} + ]; + `; + } + }, + }, + ]; + }, +}); diff --git a/src/solidbase-theme/mdx-components.tsx b/osmium/src/mdx-components.tsx similarity index 76% rename from src/solidbase-theme/mdx-components.tsx rename to osmium/src/mdx-components.tsx index b00b7f05b..bee8c1775 100644 --- a/src/solidbase-theme/mdx-components.tsx +++ b/osmium/src/mdx-components.tsx @@ -9,18 +9,14 @@ import { } from "solid-js"; import { isServer } from "solid-js/web"; -import { A } from "~/ui/i18n-anchor"; import { clientOnly } from "@solidjs/start"; -import { Callout } from "~/ui/callout"; -import { Tabs, TabList, TabPanel, Tab } from "~/ui/tabs"; +import { Callout } from "./ui/callout"; +import { Tabs, TabList, TabPanel, Tab } from "./ui/tabs"; -export { EditPageLink } from "~/ui/edit-page-link"; -export { PageIssueLink } from "~/ui/page-issue-link"; -export { Callout } from "~/ui/callout"; -export { QuickLinks } from "~/ui/quick-links"; -export { ImageLinks } from "~/ui/image-links"; +export { Callout } from "./ui/callout"; +export { QuickLinks } from "./ui/quick-links"; -const EraserLinkImpl = clientOnly(() => import("../ui/eraser-link")); +const EraserLinkImpl = clientOnly(() => import("./ui/eraser-link")); type CalloutType = "note" | "tip" | "advanced" | "caution" | "danger"; @@ -82,7 +78,7 @@ export const EraserLink = ( aria-hidden={true} tabIndex="-1" href={props.href} - class="font-semibold text-blue-700 no-underline shadow-[inset_0_-2px_0_0_var(--tw-prose-background,#38bdf8),inset_0_calc(-1*(var(--tw-prose-underline-size,2px)+2px))_0_0_var(--tw-prose-underline,theme(colors.blue.400))] hover:[--tw-prose-underline-size:4px] dark:text-blue-400 dark:shadow-[inset_0_calc(-1*var(--tw-prose-underline-size,2px))_0_0_var(--tw-prose-underline,theme(colors.blue.800))] dark:[--tw-prose-background:theme(colors.slate.900)] dark:hover:[--tw-prose-underline-size:6px]" + class="font-semibold text-blue-700 no-underline shadow-[inset_0_-2px_0_0_var(--tw-prose-background,#38bdf8),inset_0_calc(-1*(var(--tw-prose-underline-size,2px)+2px))_0_0_var(--tw-prose-underline,var(--color-blue-400))] hover:[--tw-prose-underline-size:4px] dark:text-blue-400 dark:shadow-[inset_0_calc(-1*var(--tw-prose-underline-size,2px))_0_0_var(--tw-prose-underline,var(--color-blue-800))] dark:[--tw-prose-background:var(--color-slate-900)] dark:hover:[--tw-prose-underline-size:6px]" rel="noopener noreferrer" > View on Eraser @@ -96,7 +92,7 @@ export const spa = () => <>; export const h1 = (props: ParentProps) => (

{props.children}

@@ -104,10 +100,10 @@ export const h1 = (props: ParentProps) => ( export const h2 = (props: ParentProps) => { return ( <> -
+

{props.children}

@@ -118,7 +114,7 @@ export const h3 = (props: ParentProps) => { return (

{props.children}

@@ -128,7 +124,7 @@ export const h4 = (props: ParentProps) => { return (

{props.children}

@@ -138,7 +134,7 @@ export const h5 = (props: ParentProps) => { return (
{props.children}
@@ -147,7 +143,7 @@ export const h5 = (props: ParentProps) => { export const h6 = (props: ParentProps) => (
{props.children}
@@ -172,23 +168,21 @@ export const a = (props: ParentProps & { href: string }) => { resolvedArray[0].nodeName === "CODE") ) { return ( - {resolved()} - + ); } else { return ( - {resolved()} - + ); } }; @@ -215,17 +209,12 @@ export const ol = (props: ParentProps) => ( export const nav = (props: ParentProps) => ( ); -export const TesterComponent = () => ( -

- Remove This Now!!! If you see this it means that markdown custom components - does work -

-); + export const pre = (props: ParentProps) => { return (
 			{props.children}
 		
@@ -234,7 +223,7 @@ export const pre = (props: ParentProps) => { export const code = (props: ParentProps) => { return ( {props.children} @@ -252,9 +241,6 @@ export const hr = (props: ParentProps) => { export const response = (props: ParentProps) => { return {props.children}; }; -// export const void = (props: ParentProps) => { -// return {props.children}; -// } export const unknown = (props: ParentProps) => { return {props.children}; }; diff --git a/src/styles/expressive-code.css b/osmium/src/styles/expressive-code.css similarity index 96% rename from src/styles/expressive-code.css rename to osmium/src/styles/expressive-code.css index bbb58b687..947113dfa 100644 --- a/src/styles/expressive-code.css +++ b/osmium/src/styles/expressive-code.css @@ -1,3 +1,5 @@ +@reference "../tailwind.css" + .expressive-code-overrides .expressive-code { @apply my-4 font-mono; } @@ -7,7 +9,7 @@ } .expressive-code-overrides .expressive-code .frame.is-terminal .header { - @apply border-x-0 border-b border-t-0 border-solid border-slate-600/20; + @apply border-x-0 border-t-0 border-b border-solid border-slate-600/20; } html .expressive-code-overrides .expressive-code pre { diff --git a/src/styles/prism.css b/osmium/src/styles/prism.css similarity index 62% rename from src/styles/prism.css rename to osmium/src/styles/prism.css index e38bc887c..6dcd53f71 100644 --- a/src/styles/prism.css +++ b/osmium/src/styles/prism.css @@ -1,5 +1,7 @@ +@reference "../tailwind.css" + pre[class*="language-"] { - color: theme("colors.slate.50"); + color: var(--color-slate-50); } .token.tag, @@ -8,7 +10,7 @@ pre[class*="language-"] { .token.selector .class, .token.selector.class, .token.function { - color: theme("colors.pink.400"); + color: var(--color-pink-400); } .token.attr-name, @@ -16,32 +18,32 @@ pre[class*="language-"] { .token.rule, .token.pseudo-class, .token.important { - color: theme("colors.slate.300"); + color: var(--color-slate-300); } .token.module { - color: theme("colors.pink.400"); + color: var(--color-pink-400); } .token.attr-value, .token.class, .token.string, .token.property { - color: theme("colors.sky.300"); + color: var(--color-sky-300); } .token.punctuation, .token.attr-equals { - color: theme("colors.slate.500"); + color: var(--color-slate-500); } .token.unit, .language-css .token.function { - color: theme("colors.teal.200"); + color: var(--color-teal-200); } .token.comment, .token.operator, .token.combinator { - color: theme("colors.slate.400"); + color: var(--color-slate-400); } diff --git a/osmium/src/tailwind.css b/osmium/src/tailwind.css new file mode 100644 index 000000000..2816c3267 --- /dev/null +++ b/osmium/src/tailwind.css @@ -0,0 +1,61 @@ +@plugin "@tailwindcss/typography"; +@plugin "@kobalte/tailwindcss" { + prefix: kb; +} + +@custom-variant dark (&:where([data-theme*='dark'], [data-theme*='dark'] *)); + +@theme { + --text-xs: 0.75rem; + --text-xs--line-height: 1rem; + + --text-sm: 0.875rem; + --text-sm--line-height: 1.5rem; + + --text-base: 1rem; + --text-base--line-height: 2rem; + + --text-lg: 1.125rem; + --text-lg--line-height: 1.75rem; + + --text-xl: 1.25rem; + --text-xl--line-height: 2rem; + + --text-2xl: 1.5rem; + --text-2xl--line-height: 2.5rem; + + --text-3xl: 2rem; + --text-3xl--line-height: 2.5rem; + + --text-4xl: 2.5rem; + --text-4xl--line-height: 3rem; + + --text-5xl: 3rem; + --text-5xl--line-height: 3.5rem; + + --text-6xl: 3.75rem; + --text-6xl--line-height: 1; + + --text-7xl: 4.5rem; + --text-7xl--line-height: 1; + + --text-8xl: 6rem; + --text-8xl--line-height: 1; + + --text-9xl: 8rem; + --text-9xl--line-height: 1; + + --font-sans: var(--font-geist); + --font-mono: var(--font-geist-mono); + + --font-display: var(--font-geist); + + --container-8xl: 88rem; +} + +@layer utilities { + .font-display { + font-family: var(--font-geist); + font-feature-settings: "ss01"; + } +} diff --git a/src/ui/button-link.tsx b/osmium/src/ui/button-link.tsx similarity index 82% rename from src/ui/button-link.tsx rename to osmium/src/ui/button-link.tsx index 5bfe0d0b5..fb123291a 100644 --- a/src/ui/button-link.tsx +++ b/osmium/src/ui/button-link.tsx @@ -1,7 +1,6 @@ -import { splitProps } from "solid-js"; -import { A, type RouterLinkProps } from "./i18n-anchor"; +import { ComponentProps, splitProps } from "solid-js"; -type ButtonLinkProps = RouterLinkProps & { +type ButtonLinkProps = ComponentProps<"a"> & { variant: "primary" | "secondary"; }; @@ -9,8 +8,7 @@ export const ButtonLink = (props: ButtonLinkProps) => { const [localProps, otherProps] = splitProps(props, ["variant"]); return ( - { + const frontmatter = useOsmiumThemeFrontmatter(); + + const pageData = useCurrentPageData(); + const config = useRouteConfig(); + + const formatter = createMemo( + () => new Intl.DateTimeFormat(undefined, config()?.lastUpdated || undefined) + ); + + const date = createMemo( + () => + new Date( + Number.isNaN(pageData()?.lastUpdated) + ? 0 + : (pageData()?.lastUpdated ?? 0) + ) + ); + + return ( +
+ + {(t) => ( + + {t()} + + )} + +

+ {frontmatter()?.title} +

+ + + +
{props.children}
+ + + Last updated:{" "} + + {formatter().format(date())} + + + + + + + +
+ ); +}; diff --git a/src/ui/edit-page-link.tsx b/osmium/src/ui/edit-page-link.tsx similarity index 71% rename from src/ui/edit-page-link.tsx rename to osmium/src/ui/edit-page-link.tsx index 094d5579b..89005d98c 100644 --- a/src/ui/edit-page-link.tsx +++ b/osmium/src/ui/edit-page-link.tsx @@ -3,22 +3,19 @@ import { Icon } from "solid-heroicons"; import { pencilSquare } from "solid-heroicons/outline"; import { useCurrentPageData } from "@kobalte/solidbase/client"; -import { useI18n } from "~/i18n/i18n-context"; - export const EditPageLink: Component = () => { - const i18n = useI18n(); const data = useCurrentPageData(); return ( {(editLink) => (
)} diff --git a/src/ui/eraser-link/eraser-link.css b/osmium/src/ui/eraser-link/eraser-link.css similarity index 100% rename from src/ui/eraser-link/eraser-link.css rename to osmium/src/ui/eraser-link/eraser-link.css diff --git a/src/ui/eraser-link/index.tsx b/osmium/src/ui/eraser-link/index.tsx similarity index 100% rename from src/ui/eraser-link/index.tsx rename to osmium/src/ui/eraser-link/index.tsx diff --git a/osmium/src/ui/layout.tsx b/osmium/src/ui/layout.tsx new file mode 100644 index 000000000..9776235f9 --- /dev/null +++ b/osmium/src/ui/layout.tsx @@ -0,0 +1,48 @@ +import { ParentComponent, Show } from "solid-js"; + +import { MainNavigation } from "./layout/main-navigation"; +import { MainHeader } from "./layout/main-header"; +import { Hero } from "./layout/hero"; +import { DocsLayout } from "./docs-layout"; +import { SidePanel } from "./layout/side-panel"; +import { useOsmiumThemeFrontmatter } from "../frontmatter"; + +export const Layout: ParentComponent<{ isError?: boolean }> = (props) => { + const frontmatter = useOsmiumThemeFrontmatter(); + + return ( +
+ + + + +
+ + ; +} diff --git a/src/ui/layout/hero.tsx b/osmium/src/ui/layout/hero.tsx similarity index 68% rename from src/ui/layout/hero.tsx rename to osmium/src/ui/layout/hero.tsx index 5f0b7ef94..5142a8921 100644 --- a/src/ui/layout/hero.tsx +++ b/osmium/src/ui/layout/hero.tsx @@ -1,8 +1,6 @@ -import { Component, Index, Match, Switch, createMemo } from "solid-js"; +import { Component, Match, Switch, createMemo } from "solid-js"; import { ButtonLink } from "../button-link"; -import { snippetLines } from "./hero-code-snippet"; import { useMatch } from "@solidjs/router"; -import { useI18n } from "~/i18n/i18n-context"; import RenderedCode from "./hero-code-snippet"; const TrafficLightsIcon: Component<{ class: string }> = (props) => { @@ -20,6 +18,8 @@ export const Hero: Component = () => { const isRouter = useMatch(() => "/solid-router/*"); const isMeta = useMatch(() => "/solid-meta/*"); + const i18n = { t: (s: string) => s }; + const buttonHref = createMemo(() => { if (isStart()) { return "solid-start/getting-started"; @@ -33,15 +33,13 @@ export const Hero: Component = () => { return "/quick-start"; }); - const i18n = useI18n(); - return (
-

+

SolidStart @@ -76,15 +74,15 @@ export const Hero: Component = () => {

-
-
+
+
-
-
+
+
-
+
Counter.jsx
@@ -92,19 +90,7 @@ export const Hero: Component = () => {
-
diff --git a/osmium/src/ui/layout/language-selector.tsx b/osmium/src/ui/layout/language-selector.tsx new file mode 100644 index 000000000..6e41bc164 --- /dev/null +++ b/osmium/src/ui/layout/language-selector.tsx @@ -0,0 +1,60 @@ +import { Component, For, Show } from "solid-js"; +import { Icon } from "solid-heroicons"; +import { language } from "solid-heroicons/solid"; +import { ResolvedLocale, useLocale } from "@kobalte/solidbase/client"; +import { Select } from "@kobalte/core/select"; +import { OsmiumThemeConfig } from "../.."; + +export const LanguageSelector: Component = () => { + const { locales, currentLocale, setLocale } = useLocale(); + + return ( + 1}> + {(_) => { + return ( + > + value={currentLocale()} + options={locales} + optionValue="code" + optionTextValue={(v) => v.config.label} + allowDuplicateSelectionEvents + onChange={(option) => option && setLocale(option)} + gutter={8} + sameWidth={false} + placement="bottom" + itemComponent={(props) => ( + + + {props.item.rawValue.config.label} + + + )} + > + + + + > class="prose prose-slate w-16 truncate pl-1 text-sm text-slate-700 dark:text-slate-300"> + {(state) => state.selectedOption().config.label} + + + + + + + + + ); + }} + + ); +}; diff --git a/osmium/src/ui/layout/main-header.tsx b/osmium/src/ui/layout/main-header.tsx new file mode 100644 index 000000000..74da4bae0 --- /dev/null +++ b/osmium/src/ui/layout/main-header.tsx @@ -0,0 +1,147 @@ +import { + ComponentProps, + For, + Show, + createSignal, + onCleanup, + onMount, +} from "solid-js"; +import { isServer } from "solid-js/web"; + +import { ProjectLogo, GitHubIcon, DiscordIcon } from "../logo"; +import { ThemeSelector } from "./theme-selector"; +import { MobileNavigation } from "./mobile-navigation"; +import { useMatch } from "@solidjs/router"; +import { LanguageSelector } from "./language-selector"; + +import { clientOnly } from "@solidjs/start"; +import { useCurrentProject, useRouteConfig } from "../../utils"; +import { useLocale } from "@kobalte/solidbase/client"; +import { useOsmiumThemeState } from "../../context"; + +const ClientSearch = clientOnly(() => + import("../search").then((m) => ({ default: m.Search })) +); + +interface NavLinkProps extends ComponentProps<"a"> { + active?: boolean; +} + +function NavLink(props: NavLinkProps) { + return ( + + {props.children} + + ); +} + +interface Entry { + title: string; + path: string; + children?: Entry[]; + mainNavExclude: boolean; + isTranslated?: boolean; +} + +interface MainHeaderProps {} + +export function MainHeader(props: MainHeaderProps) { + const [isScrolled, setIsScrolled] = createSignal(false); + + const config = useRouteConfig(); + const locale = useLocale(); + + const project = useCurrentProject(); + + const { setNavOpen } = useOsmiumThemeState(); + + if (!isServer) { + const onScroll = () => { + setIsScrolled(window.scrollY > 0); + }; + + onMount(() => { + onScroll(); + window.addEventListener("scroll", onScroll, { passive: true }); + }); + + onCleanup(() => { + window.removeEventListener("scroll", onScroll); + }); + } + + return ( +
+
+
+
+ +
+ + + +
+ + + {(projects) => ( +
    + + {(p) => { + return ( +
  • + setNavOpen(false)} + active={project()?.name === p.name} + > + {p.name} + +
  • + ); + }} +
    +
+ )} +
+ +
+ + + + + + + + + +
+
+
+ ); +} diff --git a/osmium/src/ui/layout/main-navigation.tsx b/osmium/src/ui/layout/main-navigation.tsx new file mode 100644 index 000000000..853264a69 --- /dev/null +++ b/osmium/src/ui/layout/main-navigation.tsx @@ -0,0 +1,191 @@ +import { createEffect, createMemo, createSignal, For, Show } from "solid-js"; +import { A, useBeforeLeave, useLocation, useMatch } from "@solidjs/router"; +import { Icon } from "solid-heroicons"; +import { chevronDown } from "solid-heroicons/solid"; +import { setIsOpen } from "./mobile-navigation"; +import { Dynamic } from "solid-js/web"; +import { + SidebarItem, + SidebarItemLink, + useLocale, + useSidebar, +} from "@kobalte/solidbase/client"; +import { Collapsible } from "@kobalte/core/collapsible"; +import { Tabs } from "@kobalte/core/tabs"; +import { useRouteConfig, useSolidBaseContext } from "../../utils"; + +interface Entry { + title: string; + path: string; + children?: Entry[]; + mainNavExclude: boolean; + isTranslated?: boolean; + isDeprecated?: boolean; +} + +interface MainNavigationProps {} + +function ListItemLink(props: { item: SidebarItemLink; prefix?: string }) { + const location = useLocation(); + const locale = useLocale(); + + const linkStyles = () => + location.pathname === props.item.link.replace(/\\/g, "/") + ? "font-semibold text-blue-700 before:bg-blue-700 dark:before:bg-blue-200 dark:text-blue-300 before:block" + : "text-slate-700 before:hidden before:bg-blue-600 before:dark:bg-blue-200 hover:text-blue-700 hover:before:block dark:text-slate-300 "; + return ( +
  • + setIsOpen(false)} + href={locale.applyPathPrefix( + `${props.prefix === "/" ? "" : (props.prefix ?? "")}${props.item.link === "/" ? "" : props.item.link}` + )} + class={`block w-full pl-3.5 before:pointer-events-none before:absolute before:top-1/2 before:-left-1 before:h-1.5 before:w-1.5 before:-translate-y-1/2 before:rounded-full hover:text-blue-700 lg:text-sm dark:hover:text-blue-300 ${linkStyles()}`} + > + {props.item.title} + +
  • + ); +} + +function DirList(props: { items: SidebarItem[] }) { + return ( + + {(child) => { + if ("items" in child) { + return ( + <> +
  • + + + + {child.title} + + + +
      + +
    +
    +
    +
  • + + ); + } + + if ("link" in child) { + return ; + } + + return ""; + }} +
    + ); +} + +interface NavigationProps { + sidebar: { prefix: string; items: SidebarItem[] }; +} +interface NavigationItemProps { + prefix: string; + item: SidebarItem; + depth?: number; +} + +export function MainNavigation(props: MainNavigationProps) { + const isReference = useMatch(() => "*/reference/*?"); + + const initialTab = () => (isReference() ? "reference" : "learn"); + + const [selectedTab, setSelectedTab] = createSignal(initialTab()); + + const sidebar = useSidebar(); + + const sidebarEntries = createMemo(() => { + const projects = useSolidBaseContext().config().themeConfig?.projects ?? []; + const projectNames = projects.map((p) => p.name.replaceAll(" ", "")); + + return sidebar().items.filter( + (i) => + !projectNames.includes(i.title.replaceAll(" ", "")) && + (!("link" in i) || i.link !== "/") + ); + }); + + createEffect(() => console.log(sidebar(), sidebarEntries())); + + /** + * Re-syncs the selected tab with the chosen route. + */ + useBeforeLeave(({ to }) => { + if (typeof to === "number") return; + + if (to.includes("/reference/")) { + setSelectedTab("reference"); + } else { + setSelectedTab("learn"); + } + }); + + return ( + + ); +} diff --git a/src/ui/layout/mobile-navigation.tsx b/osmium/src/ui/layout/mobile-navigation.tsx similarity index 89% rename from src/ui/layout/mobile-navigation.tsx rename to osmium/src/ui/layout/mobile-navigation.tsx index e1714da87..3d65a31ba 100644 --- a/src/ui/layout/mobile-navigation.tsx +++ b/osmium/src/ui/layout/mobile-navigation.tsx @@ -12,16 +12,11 @@ interface Entry { isTranslated?: boolean; } -interface NavProps { - tree: { - learn: Entry[]; - reference: Entry[]; - }; -} +interface MobileNavigationProps {} export const [isOpen, setIsOpen] = createSignal(false); -export const MobileNavigation = (props: NavProps) => { +export const MobileNavigation = (props: MobileNavigationProps) => { return ( { - +
    diff --git a/src/ui/layout/side-panel.tsx b/osmium/src/ui/layout/side-panel.tsx similarity index 100% rename from src/ui/layout/side-panel.tsx rename to osmium/src/ui/layout/side-panel.tsx diff --git a/src/ui/layout/table-of-contents.tsx b/osmium/src/ui/layout/table-of-contents.tsx similarity index 81% rename from src/ui/layout/table-of-contents.tsx rename to osmium/src/ui/layout/table-of-contents.tsx index e8181b503..6b8509de0 100644 --- a/src/ui/layout/table-of-contents.tsx +++ b/osmium/src/ui/layout/table-of-contents.tsx @@ -6,14 +6,10 @@ import { import { createEventListener } from "@solid-primitives/event-listener"; import { isServer } from "solid-js/web"; -import { useI18n } from "~/i18n/i18n-context"; - export const TableOfContents = () => { const data = useCurrentPageData(); const toc = () => data()?.toc; - const i18n = useI18n(); - const [currentSection, setCurrentSection] = createSignal(); const [headingElements, setHeadingElements] = createSignal< @@ -53,13 +49,10 @@ export const TableOfContents = () => { return (