Skip to content

Commit

Permalink
feat: work on theme management
Browse files Browse the repository at this point in the history
  • Loading branch information
albanm committed Dec 23, 2024
1 parent 32c72dd commit 3d69e4e
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 27 deletions.
2 changes: 2 additions & 0 deletions api/config/default.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ module.exports = {
analytics: {}, // a "modules" definition for @koumoul/vue-multianalytics
theme: {
logo: undefined,
bodyFontFamilyCss: "@font-face{font-family:{FONT_FAMILY};font-style:italic;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXX3I6Li01BKofIMNaORs71cA-Bm_i0Dk1.woff2) format('woff2');unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:{FONT_FAMILY};font-style:italic;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXX3I6Li01BKofIMNaHRs71cA-Cznx39fA.woff2) format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:{FONT_FAMILY};font-style:italic;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXX3I6Li01BKofIMNaMRs71cA-CuWrHpFO.woff2) format('woff2');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:{FONT_FAMILY};font-style:italic;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXX3I6Li01BKofIMNaNRs71cA-D1eeM49Z.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:{FONT_FAMILY};font-style:italic;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXX3I6Li01BKofIMNaDRs4-BbMn9XSX.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:{FONT_FAMILY};font-style:normal;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXV3I6Li01BKofIOOaBXso-BWI5zH9R.woff2) format('woff2');unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:{FONT_FAMILY};font-style:normal;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXV3I6Li01BKofIMeaBXso-C3IBG1kp.woff2) format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:{FONT_FAMILY};font-style:normal;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXV3I6Li01BKofIOuaBXso-B55YuedR.woff2) format('woff2');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:{FONT_FAMILY};font-style:normal;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXV3I6Li01BKofIO-aBXso-DcJfvmGA.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:{FONT_FAMILY};font-style:normal;font-weight:200 1000;font-display:swap;src:url({SITE_PATH}/simple-directory/fonts/XRXV3I6Li01BKofINeaB-BaTF6Vo7.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}",
headingFontFamilyCss: undefined,
colors: {
// standard vuetify colors, see https://vuetifyjs.com/en/styles/colors/#material-colors
background: '#FAFAFA', // grey-lighten-5
Expand Down
16 changes: 16 additions & 0 deletions api/config/type/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,8 @@
"required": ["colors"],
"layout": [
"logo",
"bodyFontFamilyCss",
"headingFontFamilyCss",
{
"comp": "tabs",
"children": [{
Expand All @@ -654,6 +656,20 @@
"title": "URL d'un logo",
"type": "string"
},
"bodyFontFamilyCss": {
"title": "CSS police de caractères pour le corps du texte",
"description": "Par défaut une police Nunito auto-hébergée est utilisée. Vous pouvez aussi copier le CSS proposé par une plateforme comme Google Fonts, dans ce cas il faut remplacer le nom de la police par '{FONT_FAMILY}'.",
"type": "string",
"layout": "textarea"
},
"headingFontFamilyCss": {
"title": "CSS police de caractères pour les titres",
"layout": {
"comp": "textarea",
"hint": "laissez vide pour utiliser la police du corps du texte"
},
"type": "string"
},
"colors": { "$ref": "#/$defs/colors" },
"dark": { "type": "boolean", "title": "proposer ce thème aux utilisateurs" },
"darkColors": { "$ref": "#/$defs/colors" },
Expand Down
1 change: 0 additions & 1 deletion api/resources/webfonts.css

This file was deleted.

33 changes: 26 additions & 7 deletions api/src/sites/router.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { type SitePublic } from '#types'
import { type Colors } from '#types/site-public/index.ts'
import { Router, type Request } from 'express'
import config from '#config'
import { reqUser, reqUserAuthenticated, reqSiteUrl, httpError, reqSessionAuthenticated, reqHost, reqSitePath } from '@data-fair/lib-express'
Expand Down Expand Up @@ -106,8 +105,6 @@ router.delete('/:id', async (req, res, next) => {
res.status(204).send()
})

const webfontsCssRaw = readFileSync(resolve(import.meta.dirname, '../../resources/webfonts.css'), 'utf8')
const webfontsCache: Record<string, string> = {}
router.get('/_public', async (req, res, next) => {
res.setHeader('Cache-Control', 'public, max-age=60')

Expand Down Expand Up @@ -136,12 +133,34 @@ router.get('/_public', async (req, res, next) => {
}
})

router.get('/_webfonts.css', async (req, res, next) => {
const getTextColorsCss = (colors: Colors, theme: string) => {
let css = ''
for (const color of ['primary', 'secondary', 'accent', 'error', 'info', 'success', 'warning', 'admin']) {
const key = `text-${color}` as keyof Colors
if (colors[key]) {
css += `
.v-application.v-theme--${theme} .text-${color} {
color: ${colors[key]}!important;
}`
}
}
return css
}

router.get('/_theme.css', async (req, res, next) => {
res.setHeader('Cache-Control', 'public, max-age=60')
const site = await reqSite(req)
const sitePath = reqSitePath(req)
webfontsCache[sitePath] = webfontsCache[sitePath] ?? microTemplate(webfontsCssRaw, { SITE_PATH: sitePath })
let css = ''
const theme = site?.theme ?? config.theme
css += getTextColorsCss(theme.colors, 'dark')
if (theme.dark && theme.darkColors) css += getTextColorsCss(theme.darkColors, 'dark')
if (theme.hc && theme.hcColors) css += getTextColorsCss(theme.hcColors, 'hc')
if (theme.hcDark && theme.hcDarkColors) css += getTextColorsCss(theme.hcDarkColors, 'hc-dark')
css += '\n' + microTemplate(site?.theme?.bodyFontFamilyCss ?? config.theme.bodyFontFamilyCss ?? '', { SITE_PATH: sitePath, FONT_FAMILY: 'BodyFontFamily' })
css += '\n' + microTemplate(site?.theme?.headingFontFamilyCss ?? site?.theme?.bodyFontFamilyCss ?? config.theme.headingFontFamilyCss ?? config.theme.bodyFontFamilyCss ?? '', { SITE_PATH: sitePath, FONT_FAMILY: 'HeadingFontFamily' })
res.contentType('css')
res.send(webfontsCache[sitePath])
res.send(css)
})

router.get('/:id/_theme_warnings', async (req, res, next) => {
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions test-it/sites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ describe('sites api', () => {
const siteDirectoryUrl = 'http://127.0.0.1:5989/simple-directory'
const publicSite = (await anonymousAx.get(`${siteDirectoryUrl}/api/sites/_public`)).data
assert.equal(publicSite.authMode, 'onlyBackOffice')
assert.ok(publicSite.colors.primary)
assert.ok(publicSite.logo.startsWith('http://127.0.0.1:5989/'))
const webfonts = (await anonymousAx.get<string>(`${siteDirectoryUrl}/api/sites/_webfonts.css`)).data
assert.ok(webfonts.startsWith('@font-face'))
assert.ok(publicSite.theme.colors.primary)
assert.ok(publicSite.theme.logo.startsWith('http://127.0.0.1:5989/'))
const themeCss = (await anonymousAx.get<string>(`${siteDirectoryUrl}/api/sites/_theme.css`)).data
assert.ok(themeCss.includes('@font-face{font-family:BodyFontFamily'))

let sites = (await ax.get('/api/sites')).data
assert.equal(sites.count, 0)
Expand Down
2 changes: 1 addition & 1 deletion ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="{SITE_PATH}/simple-directory/api/sites/_webfonts.css" rel="stylesheet">
<link href="{SITE_PATH}/simple-directory/api/sites/_theme.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
Expand Down
4 changes: 2 additions & 2 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
},
"dependencies": {
"@data-fair/frame": "^0.2.1",
"@data-fair/lib-vue": "^1.14.0",
"@data-fair/lib-vuetify": "^1.7.1",
"@data-fair/lib-vue": "^1.15.0",
"@data-fair/lib-vuetify": "^1.8.0",
"@intlify/unplugin-vue-i18n": "^5.2.0",
"@koumoul/v-iframe": "^2.4.4",
"@koumoul/vjsf": "^3.6.2",
Expand Down
2 changes: 0 additions & 2 deletions ui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,12 @@
<script lang="ts" setup>
import uiNotif from '@data-fair/lib-vuetify/ui-notif.vue'
import inIframe from '@data-fair/lib-utils/in-iframe.js'
import { vuetifySessionStyle } from '@data-fair/lib-vuetify'
const session = useSession()
const route = useRoute()
useHead({
htmlAttrs: () => ({ lang: session.lang.value ?? 'fr' }),
style: [vuetifySessionStyle(session)]
// style: () => globalStyle
// __dangerouslyDisableSanitizers: ['style']
})
Expand Down
3 changes: 2 additions & 1 deletion ui/src/vuetify-settings.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@use 'vuetify' with (
$color-pack: false,
$body-font-family: 'BodyFontFamily'
$body-font-family: 'BodyFontFamily',
$heading-font-family: 'HeadingFontFamily'
);

// v-icon has an opacity when it is prepended in a list of items.
Expand Down

0 comments on commit 3d69e4e

Please sign in to comment.