Skip to content

Commit

Permalink
feat: web fonts auto importing
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jun 4, 2021
1 parent 92e8e9e commit a971df9
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 24 deletions.
92 changes: 83 additions & 9 deletions packages/parser/src/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import YAML from 'js-yaml'
import { isObject, isTruthy, objectMap } from '@antfu/utils'
import { SlideInfo, SlideInfoBase, SlidevConfig, SlidevFeatureFlags, SlidevMarkdown, SlidevThemeMeta } from '@slidev/types'
import { isObject, isTruthy, objectMap, toArray, uniq } from '@antfu/utils'
import { FontOptions, ResolvedFontOptions, SlideInfo, SlideInfoBase, SlidevConfig, SlidevFeatureFlags, SlidevMarkdown, SlidevThemeMeta } from '@slidev/types'
import { parseAspectRatio } from './utils'

export function stringify(data: SlidevMarkdown) {
Expand Down Expand Up @@ -152,6 +152,75 @@ export function parse(
}
}

function resolveFonts(fonts: FontOptions = {}): ResolvedFontOptions {
const {
fallbacks = true,
provider = 'google',
} = fonts
let sans = toArray(fonts.sans).flatMap(i => i.split(/,\s*/g)).map(i => i.trim())
let serif = toArray(fonts.serif).flatMap(i => i.split(/,\s*/g)).map(i => i.trim())
let mono = toArray(fonts.mono).flatMap(i => i.split(/,\s*/g)).map(i => i.trim())
const webfonts = fonts.webfonts
? fonts.webfonts
: fallbacks
? uniq([...sans, ...serif, ...mono])
: []

function toQuoted(font: string) {
if (/^(['"]).*\1$/.test(font))
return font
return `"${font}"`
}

if (fallbacks) {
sans = uniq([
...sans.map(toQuoted),
'ui-sans-serif',
'system-ui',
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'"Noto Sans"',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
'"Noto Color Emoji"',
])
serif = uniq([
...serif.map(toQuoted),
'ui-serif',
'Georgia',
'Cambria',
'"Times New Roman"',
'Times',
'serif',
])
mono = uniq([
...mono.map(toQuoted),
'ui-monospace',
'SFMono-Regular',
'Menlo',
'Monaco',
'Consolas',
'"Liberation Mono"',
'"Courier New"',
'monospace',
])
}

return {
sans,
serif,
mono,
webfonts,
provider,
}
}

export function resolveConfig(headmatter: any, themeMeta: SlidevThemeMeta = {}) {
const themeHightlighter = ['prism', 'shiki'].includes(themeMeta.highlighter || '') ? themeMeta.highlighter as 'prism' | 'shiki' : undefined
const themeColorSchema = ['light', 'dark'].includes(themeMeta.colorSchema || '') ? themeMeta.colorSchema as 'light' | 'dark' : undefined
Expand All @@ -170,14 +239,19 @@ export function resolveConfig(headmatter: any, themeMeta: SlidevThemeMeta = {})
canvasWidth: 980,
selectable: false,
themeConfig: {},
fonts: {},
fonts: {} as ResolvedFontOptions,
}
const config: SlidevConfig = {
...defaultConfig,
...themeMeta.defaults || {},
...headmatter.config || {},
...headmatter,
fonts: resolveFonts({
...themeMeta.defaults?.fonts,
...headmatter.config?.fonts,
...headmatter?.fonts,
}),
}
const config: SlidevConfig = Object.assign(
defaultConfig,
themeMeta.defaults || {},
headmatter.config || {},
headmatter,
)
if (config.colorSchema !== 'dark' && config.colorSchema !== 'light')
config.colorSchema = 'auto'
if (themeColorSchema && config.colorSchema === 'auto')
Expand Down
4 changes: 3 additions & 1 deletion packages/slidev/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { LogLevel, ViteDevServer } from 'vite'
import * as parser from '@slidev/parser/fs'
import { SlidevConfig } from '@slidev/types'
import isInstalledGlobally from 'is-installed-globally'
import equal from 'fast-deep-equal'
import { version } from '../package.json'
import { createServer } from './server'
import { getThemeRoots, isPath, ResolvedSlidevOptions, resolveOptions } from './options'
Expand All @@ -21,6 +22,7 @@ const CONFIG_RESTART_FIELDS: (keyof SlidevConfig)[] = [
'highlighter',
'monaco',
'routerMode',
'fonts',
]

const cli = yargs
Expand Down Expand Up @@ -99,7 +101,7 @@ cli.command(
console.log(yellow('\n restarting on theme change\n'))
initServer()
}
else if (CONFIG_RESTART_FIELDS.some(i => newData.config[i] !== data.config[i])) {
else if (CONFIG_RESTART_FIELDS.some(i => !equal(newData.config[i], data.config[i]))) {
console.log(yellow('\n restarting on config change\n'))
initServer()
}
Expand Down
5 changes: 5 additions & 0 deletions packages/slidev/node/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export async function getIndexHtml({ clientRoot, themeRoots, data, userRoot }: R
if (data.features.tweet)
body += '\n<script async src="https://platform.twitter.com/widgets.js"></script>'

if (data.config.fonts.webfonts.length && data.config.fonts.provider !== 'none') {
const fonts = data.config.fonts.webfonts.map(i => `family=${i.replace(/^(['"])(.*)\1$/, '$1').replace(/\s/g, '-')}`).join('&')
head += `\n<link href="https://fonts.googleapis.com/css2?${fonts}&display=swap" rel="stylesheet">`
}

main = main
.replace('__ENTRY__', toAtFS(join(clientRoot, 'main.ts')))
.replace('<!-- head -->', head)
Expand Down
17 changes: 16 additions & 1 deletion packages/slidev/node/plugins/windicss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { jiti } from './jiti'
import { loadSetups } from './setupNode'

export async function createWindiCSSPlugin(
{ themeRoots, clientRoot, userRoot, roots }: ResolvedSlidevOptions,
{ themeRoots, clientRoot, userRoot, roots, data }: ResolvedSlidevOptions,
{ windicss: windiOptions }: SlidevPluginOptions,
) {
const configFiles = [
Expand All @@ -28,6 +28,21 @@ export async function createWindiCSSPlugin(
{
configFiles: [configFile],
config,
onConfigResolved(config: any) {
if (!config.theme)
config.theme = {}
if (!config.theme.extend)
config.theme.extend = {}
if (!config.theme.extend.fontFamily)
config.theme.extend.fontFamily = {}

const fontFamily = config.theme.extend.fontFamily
fontFamily.sans ||= data.config.fonts.sans
fontFamily.mono ||= data.config.fonts.mono
fontFamily.serif ||= data.config.fonts.serif

return config
},
onOptionsResolved(config) {
config.scanOptions.include.push(`!${slash(resolve(userRoot, 'node_modules'))}`)
config.scanOptions.exclude.push(dirname(resolveImportPath('monaco-editor/package.json', true)))
Expand Down
16 changes: 15 additions & 1 deletion packages/types/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ export type FontOptions = {
* Specify web fonts names, will detect from `sans`, `mono`, `serif` if not provided
*/
webfonts?: string[]
/**
* Use fonts fallback
*
* @default true
*/
fallbacks?: boolean
}

export type ResolvedFontOptions = {
sans: string[]
mono: string[]
serif: string[]
provider: 'none' | 'google'
webfonts: string[]
}

export interface SlidevConfig {
Expand Down Expand Up @@ -135,7 +149,7 @@ export interface SlidevConfig {
*
* @default {}
*/
fonts: FontOptions
fonts: ResolvedFontOptions
}

export interface SlidevFeatureFlags {
Expand Down

0 comments on commit a971df9

Please sign in to comment.