feat(color): support custom colors
This commit is contained in:
parent
cde237f706
commit
b1e2927570
23
README.md
23
README.md
|
@ -12,6 +12,7 @@ Inspired by [jsonresume-theme-flat](https://github.com/erming/jsonresume-theme-f
|
|||
- 💄 Markdown support
|
||||
- 📐 CSS grid layout
|
||||
- 🌗 Light and dark modes
|
||||
- 🎨 Customizable colors
|
||||
- 🧩 Standalone CLI
|
||||
- 📦 ESM and CommonJS builds
|
||||
|
||||
|
@ -50,3 +51,25 @@ _Even_ comes with a barebones CLI that reads resumes from `stdin` and outputs HT
|
|||
```console
|
||||
npx jsonresume-theme-even < resume.json > resume.html
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### Colors
|
||||
|
||||
You can override theme colors via the `.meta.colors` resume field. Each entry defines a tuple of light and (optional) dark color values. If only one array value is defined, it will be used in both light and dark modes.
|
||||
|
||||
Here's an example using the default theme colors:
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"colors": {
|
||||
"background": ["#ffffff", "#191e23"],
|
||||
"dimmed": ["#f3f4f5", "#23282d"],
|
||||
"primary": ["#191e23", "#fbfbfc"],
|
||||
"secondary": ["#6c7781", "#ccd0d4"],
|
||||
"accent": ["#0073aa", "#00a0d2"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -11,11 +11,12 @@ import References from './components/references.js'
|
|||
import Skills from './components/skills.js'
|
||||
import Volunteer from './components/volunteer.js'
|
||||
import Work from './components/work.js'
|
||||
import colors from './utils/colors.js'
|
||||
import html from './utils/html.js'
|
||||
|
||||
export default function Resume(resume, css) {
|
||||
return html`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" style="${colors(resume.meta)}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
${Meta(resume.basics)}
|
||||
|
|
38
style.css
38
style.css
|
@ -1,11 +1,23 @@
|
|||
:root {
|
||||
color-scheme: light dark;
|
||||
|
||||
--color-background: #ffffff; /* White */
|
||||
--color-muted: #f3f4f5; /* Light Gray 200 */
|
||||
--color-primary: #191e23; /* Dark Gray 900 */
|
||||
--color-secondary: #6c7781; /* Dark Gray 300 */
|
||||
--color-accent: #0073aa; /* WordPress Blue */
|
||||
--color-background-light: #ffffff; /* White */
|
||||
--color-dimmed-light: #f3f4f5; /* Light Gray 200 */
|
||||
--color-primary-light: #191e23; /* Dark Gray 900 */
|
||||
--color-secondary-light: #6c7781; /* Dark Gray 300 */
|
||||
--color-accent-light: #0073aa; /* WordPress Blue */
|
||||
|
||||
--color-background-dark: #191e23; /* Dark Gray 900 */
|
||||
--color-dimmed-dark: #23282d; /* Dark Gray 800 */
|
||||
--color-primary-dark: #fbfbfc; /* Light Gray 100 */
|
||||
--color-secondary-dark: #ccd0d4; /* Light Gray 700 */
|
||||
--color-accent-dark: #00a0d2; /* Medium Blue */
|
||||
|
||||
--color-background: var(--color-background-light);
|
||||
--color-dimmed: var(--color-dimmed-light);
|
||||
--color-primary: var(--color-primary-light);
|
||||
--color-secondary: var(--color-secondary-light);
|
||||
--color-accent: var(--color-accent-light);
|
||||
|
||||
--scale-ratio: 1.25;
|
||||
--scale0: 1rem;
|
||||
|
@ -18,11 +30,11 @@
|
|||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-background: #191e23; /* Dark Gray 900 */
|
||||
--color-muted: #23282d; /* Dark Gray 800 */
|
||||
--color-primary: #fbfbfc; /* Light Gray 100 */
|
||||
--color-secondary: #ccd0d4; /* Light Gray 700 */
|
||||
--color-accent: #00a0d2; /* Medium Blue */
|
||||
--color-background: var(--color-background-dark);
|
||||
--color-dimmed: var(--color-dimmed-dark);
|
||||
--color-primary: var(--color-primary-dark);
|
||||
--color-secondary: var(--color-secondary-dark);
|
||||
--color-accent: var(--color-accent-dark);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +140,7 @@ h6 {
|
|||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 0.2em solid var(--color-muted);
|
||||
border-left: 0.2em solid var(--color-dimmed);
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
|
@ -147,7 +159,7 @@ svg {
|
|||
}
|
||||
|
||||
.masthead {
|
||||
background: var(--color-muted);
|
||||
background: var(--color-dimmed);
|
||||
display: inherit;
|
||||
gap: inherit;
|
||||
grid-column: full;
|
||||
|
@ -206,7 +218,7 @@ blockquote > * + *,
|
|||
}
|
||||
|
||||
.tag-list > li {
|
||||
background: var(--color-muted);
|
||||
background: var(--color-dimmed);
|
||||
border-radius: 0.2em;
|
||||
padding: 0.2em 0.6em;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`renders a resume 1`] = `
|
||||
"<!DOCTYPE html>
|
||||
<html lang=\\"en\\">
|
||||
<html lang=\\"en\\" style=\\"--color-background-light:lightgray; --color-background-dark:darkgray;\\">
|
||||
<head>
|
||||
<meta charset=\\"utf-8\\">
|
||||
|
||||
|
|
|
@ -2,10 +2,21 @@ import { HtmlValidate } from 'html-validate'
|
|||
import { expect, it } from 'vitest'
|
||||
|
||||
import { render } from '../index.js'
|
||||
import resume from 'resume-schema/sample.resume.json' assert { type: 'json' }
|
||||
import sampleResume from 'resume-schema/sample.resume.json' assert { type: 'json' }
|
||||
|
||||
// Overwrite empty sample resume values
|
||||
resume.basics.image = 'image.jpg'
|
||||
const resume = {
|
||||
...sampleResume,
|
||||
meta: {
|
||||
...sampleResume.meta,
|
||||
colors: {
|
||||
background: ['lightgray', 'darkgray'],
|
||||
},
|
||||
},
|
||||
basics: {
|
||||
...sampleResume.basics,
|
||||
image: 'image.jpg',
|
||||
},
|
||||
}
|
||||
|
||||
it('renders a resume', () => {
|
||||
expect(render(resume)).toMatchSnapshot()
|
||||
|
@ -15,6 +26,7 @@ it('renders valid HTML', async () => {
|
|||
const htmlvalidate = new HtmlValidate({
|
||||
extends: ['html-validate:recommended'],
|
||||
rules: {
|
||||
'no-inline-style': 'off',
|
||||
'no-trailing-whitespace': 'off',
|
||||
'tel-non-breaking': 'off',
|
||||
},
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export default function colors(meta = {}) {
|
||||
const { colors } = meta
|
||||
return colors && Object.entries(colors)
|
||||
.map(([name, [light, dark = light]]) => `--color-${name}-light:${light}; --color-${name}-dark:${dark};`)
|
||||
.join(' ')
|
||||
}
|
Loading…
Reference in New Issue