Skip to content

Commit

Permalink
feat: allow custom head tags (#83)
Browse files Browse the repository at this point in the history
  • Loading branch information
ocavue authored Dec 13, 2024
1 parent ed1706e commit aebaa00
Show file tree
Hide file tree
Showing 24 changed files with 298 additions and 47 deletions.
7 changes: 7 additions & 0 deletions .changeset/light-plants-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'astrobook': minor
---

Add a new `head` option. This allows you to configure the global styles and fonts. Please check the README.md for more information.

Add a new `title` option to set the title for your Astrobook site.
3 changes: 3 additions & 0 deletions examples/custom-head/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
An example of using custom `<head>` tags with Astrobook.

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/ocavue/astrobook/tree/master/examples/custom-head)
18 changes: 18 additions & 0 deletions examples/custom-head/astro.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineConfig } from 'astro/config'
import astrobook from 'astrobook'

// https://astro.build/config
export default defineConfig({
server: {
port: 4305,
},

// Enable many frameworks to support all different kinds of components.
integrations: [
astrobook({
directory: 'src/components',
head: './src/components/CustomHead.astro',
title: 'Custom Title',
}),
],
})
21 changes: 21 additions & 0 deletions examples/custom-head/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "example-custom-head",
"type": "module",
"version": "0.0.0",
"private": true,
"stackblitz": {
"installDependencies": false,
"startCommand": "pnpm install && pnpm run dev"
},
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "^5.0.5",
"astrobook": "*"
}
}
27 changes: 27 additions & 0 deletions examples/custom-head/src/components/CustomFont.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!-- Custom font -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Freckle+Face&family=Lobster&family=Press+Start+2P&display=swap"
rel="stylesheet"
/>

<style>
.font-freckle-face {
font-family: 'Freckle Face', system-ui;
font-weight: 400;
font-style: normal;
}

.font-lobster {
font-family: 'Lobster', sans-serif;
font-weight: 400;
font-style: normal;
}

.font-press-start-2p {
font-family: 'Press Start 2P', system-ui;
font-weight: 400;
font-style: normal;
}
</style>
6 changes: 6 additions & 0 deletions examples/custom-head/src/components/CustomHead.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
import './global.css'
import CustomFont from './CustomFont.html'
---

<CustomFont />
13 changes: 13 additions & 0 deletions examples/custom-head/src/components/Typography.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
interface Props {
fontName: 'freckle-face' | 'lobster' | 'press-start-2p'
}
const { fontName } = Astro.props
---

<div>
<div class={`font-${fontName}`}>
<p>Lorem ipsum dolor sit amet</p>
</div>
</div>
23 changes: 23 additions & 0 deletions examples/custom-head/src/components/Typography.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Typography from './Typography.astro'

export default {
component: Typography,

Check warning on line 4 in examples/custom-head/src/components/Typography.stories.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value
}

export const Lobster = {
args: {
fontName: 'lobster',
},
}

export const FreckleFace = {
args: {
fontName: 'freckle-face',
},
}

export const PressStart2P = {
args: {
fontName: 'press-start-2p',
},
}
3 changes: 3 additions & 0 deletions examples/custom-head/src/components/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
p {
padding: 1rem;
}
5 changes: 5 additions & 0 deletions examples/custom-head/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

declare module '*.vue'
declare module '*.astro'
23 changes: 23 additions & 0 deletions examples/custom-head/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "es2022",
"module": "esnext",
"lib": ["esnext"],
"jsx": "preserve",
"declaration": true,
"emitDeclarationOnly": true,
"moduleResolution": "Bundler",
"esModuleInterop": true,
"outDir": "${configDir}/node_modules/.cache/tsc",
"strict": true,
"allowJs": true,
"composite": true,
"strictNullChecks": true,
"verbatimModuleSyntax": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"skipDefaultLibCheck": true
},
"include": ["./src", "./*.js", "./*.mjs", "./*.ts"]
}
48 changes: 48 additions & 0 deletions packages/astrobook/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,54 @@ export default defineConfig({

You Astro project will be available at `http://localhost:4321/base` and Astrobook will be available at `http://localhost:4321/base/docs/components`.

### `head`

The path to an Astro component that includes custom tags to the `<head>` of your Astrobook site. It should only include [elements permitted inside `<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head#see_also).

Below is an example of a custom head component that configures the global styles and fonts.

```astro
---
// src/components/CustomHead.astro
// Apply global styles from a CSS file
import './global.css'
---
<!-- Load custom fonts -->
<link rel="preconnect" href="https://rsms.me/" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<!-- Apply global styles -->
<style is:global>
html {
font-family: 'Inter', sans-serif;
}
</style>
```

```js
// astro.config.mjs
import { defineConfig } from 'astro/config'

export default defineConfig({
head: './src/components/CustomHead.astro',
})
```

### `title`

You can set the title for your website.

```js
// astro.config.mjs
import { defineConfig } from 'astro/config'

export default defineConfig({
title: 'My Awesome Playground',
})
```

## Advanced

### Toggle theme via message
Expand Down
1 change: 1 addition & 0 deletions packages/astrobook/lib/components/head.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<slot />
12 changes: 12 additions & 0 deletions packages/astrobook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
},
"./pages/*": {
"default": "./lib/pages/*"
},
"./components/*": {
"default": "./lib/components/*"
}
},
"typesVersions": {
Expand All @@ -51,6 +54,9 @@
],
"./pages/*": [
"./lib/pages/*"
],
"./components/*": [
"./lib/components/*"
]
}
},
Expand Down Expand Up @@ -95,6 +101,9 @@
},
"./pages/*": {
"default": "./lib/pages/*"
},
"./components/*": {
"default": "./lib/components/*"
}
},
"main": "./dist/index.js",
Expand All @@ -110,6 +119,9 @@
],
"./pages/*": [
"./lib/pages/*"
],
"./components/*": [
"./lib/components/*"
]
}
}
Expand Down
14 changes: 10 additions & 4 deletions packages/core/src/astro-integration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'node:fs/promises'
import path from 'node:path'
import pathPosix from 'node:path/posix'
import { fileURLToPath } from 'node:url'

import type { IntegrationOptions } from '@astrobook/types'
import type { AstroIntegration } from 'astro'
Expand All @@ -20,8 +21,8 @@ export function createAstrobookIntegration(
'astro:config:setup': async ({
updateConfig,
injectRoute,
config,
createCodegenDir,
config,
logger,
}) => {
const rootDir = path.resolve(options?.directory || '.')
Expand All @@ -32,8 +33,7 @@ export function createAstrobookIntegration(
logger.debug(`Creating dedicated folder`)
let codegenDir: string
if (createCodegenDir) {
const codegenDirURL = createCodegenDir()
codegenDir = await fs.realpath(codegenDirURL)
codegenDir = fileURLToPath(createCodegenDir())
} else {
// Astro v4, where `createCodegenDir()` is not available
codegenDir = path.resolve('.astro', 'integrations', 'astrobook')
Expand All @@ -56,7 +56,13 @@ export function createAstrobookIntegration(

updateConfig({
vite: {
plugins: [createVirtualFilesPlugin(rootDir, baseUrl)],
plugins: [
createVirtualFilesPlugin(rootDir, {
baseUrl,
head: options?.head || 'astrobook/components/head.astro',
title: options?.title || 'Astrobook',
}),
],
},
})

Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/virtual-module/virtual-module-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@ export const STORY_MODULES_ID = 'virtual:astrobook/story-modules.mjs'
export const STORY_MODULES_RESOLVED_ID =
'__virtual_astrobook_story_modules__.mjs'

export const BASE_URL_ID = 'virtual:astrobook/base-url.mjs'
export const BASE_URL_RESOLVED_ID = '__virtual_astrobook_base_url__.mjs'
export const GLOBAL_CONFIG_ID = 'virtual:astrobook/global-config.mjs'
export const GLOBAL_CONFIG_RESOLVED_ID = '__virtual_astrobook_user_config__.mjs'

export const COMPONENT_HEAD_ID = 'virtual:astrobook/components/head.mjs'
export const COMPONENT_HEAD_RESOLVED_ID =
'__virtual_astrobook_COMPONENT_HEAD__.mjs'
21 changes: 14 additions & 7 deletions packages/core/src/virtual-module/vite-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,40 @@
import type { GlobalConfig } from '@astrobook/types'
import type { Plugin } from 'vite'

import { loadStoryModules } from './story-modules'
import {
BASE_URL_ID,
BASE_URL_RESOLVED_ID,
COMPONENT_HEAD_ID,
COMPONENT_HEAD_RESOLVED_ID,
STORY_MODULES_ID,
STORY_MODULES_RESOLVED_ID,
GLOBAL_CONFIG_ID,
GLOBAL_CONFIG_RESOLVED_ID,
} from './virtual-module-ids'

export function createVirtualFilesPlugin(
rootDir: string,
baseUrl: string,
config: GlobalConfig,
): Plugin {
return {
name: 'astrobook/virtual-files',
resolveId(id) {
switch (id) {
case STORY_MODULES_ID:
return STORY_MODULES_RESOLVED_ID
case BASE_URL_ID:
return BASE_URL_RESOLVED_ID
case GLOBAL_CONFIG_ID:
return GLOBAL_CONFIG_RESOLVED_ID
case COMPONENT_HEAD_ID:
return COMPONENT_HEAD_RESOLVED_ID
}
},
load(id) {
switch (id) {
case STORY_MODULES_RESOLVED_ID:
return loadStoryModules(rootDir)
case BASE_URL_RESOLVED_ID:
return `const baseUrl = ${JSON.stringify(baseUrl)}; export default baseUrl`
case GLOBAL_CONFIG_RESOLVED_ID:
return `const config = ${JSON.stringify(config)}; export default config;`
case COMPONENT_HEAD_RESOLVED_ID:
return `export { default } from ${JSON.stringify(config.head)};`
}
},
}
Expand Down
21 changes: 21 additions & 0 deletions packages/types/lib/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ export interface IntegrationOptions {
* @example '/docs/components'
*/
subpath?: string

/**
* Set the title for your website. Will be used in metadata and in the browser tab title.
*
* @default 'Astrobook'
*/
title?: string

/**
* The path to an Astro component to provide custom tags in the `<head>`.
*
* @example './src/components/CustomHead.astro'
* @example './src/components/CustomHead.html'
*/
head?: string
}

export interface StoryModule {
Expand Down Expand Up @@ -69,6 +84,12 @@ export interface Story {
name: string
}

export interface GlobalConfig {
baseUrl: string
head: string
title: string
}

declare global {
interface Window {
astrobook?: {
Expand Down
Loading

0 comments on commit aebaa00

Please sign in to comment.