This commit is contained in:
darenhsu
2022-07-17 13:16:16 +08:00
parent 84759556ff
commit befd344ab0
28070 changed files with 4008428 additions and 1 deletions
+258
View File
@@ -0,0 +1,258 @@
/* eslint-disable no-multi-spaces */
// Extensions
import { Service } from '../service'; // Utilities
import * as ThemeUtils from './utils';
import { getNestedValue } from '../../util/helpers'; // Types
import Vue from 'vue';
export class Theme extends Service {
constructor(preset) {
super();
this.disabled = false;
this.isDark = null;
this.vueInstance = null;
this.vueMeta = null;
const {
dark,
disable,
options,
themes
} = preset[Theme.property];
this.dark = Boolean(dark);
this.defaults = this.themes = themes;
this.options = options;
if (disable) {
this.disabled = true;
return;
}
this.themes = {
dark: this.fillVariant(themes.dark, true),
light: this.fillVariant(themes.light, false)
};
} // When setting css, check for element
// and apply new values
set css(val) {
if (this.vueMeta) {
if (this.isVueMeta23) {
this.applyVueMeta23();
}
return;
}
this.checkOrCreateStyleElement() && (this.styleEl.innerHTML = val);
}
set dark(val) {
const oldDark = this.isDark;
this.isDark = val; // Only apply theme after dark
// has already been set before
oldDark != null && this.applyTheme();
}
get dark() {
return Boolean(this.isDark);
} // Apply current theme default
// only called on client side
applyTheme() {
if (this.disabled) return this.clearCss();
this.css = this.generatedStyles;
}
clearCss() {
this.css = '';
} // Initialize theme for SSR and SPA
// Attach to ssrContext head or
// apply new theme to document
init(root, ssrContext) {
if (this.disabled) return;
/* istanbul ignore else */
if (root.$meta) {
this.initVueMeta(root);
} else if (ssrContext) {
this.initSSR(ssrContext);
}
this.initTheme();
} // Allows for you to set target theme
setTheme(theme, value) {
this.themes[theme] = Object.assign(this.themes[theme], value);
this.applyTheme();
} // Reset theme defaults
resetThemes() {
this.themes.light = Object.assign({}, this.defaults.light);
this.themes.dark = Object.assign({}, this.defaults.dark);
this.applyTheme();
} // Check for existence of style element
checkOrCreateStyleElement() {
this.styleEl = document.getElementById('vuetify-theme-stylesheet');
/* istanbul ignore next */
if (this.styleEl) return true;
this.genStyleElement(); // If doesn't have it, create it
return Boolean(this.styleEl);
}
fillVariant(theme = {}, dark) {
const defaultTheme = this.themes[dark ? 'dark' : 'light'];
return Object.assign({}, defaultTheme, theme);
} // Generate the style element
// if applicable
genStyleElement() {
/* istanbul ignore if */
if (typeof document === 'undefined') return;
/* istanbul ignore next */
this.styleEl = document.createElement('style');
this.styleEl.type = 'text/css';
this.styleEl.id = 'vuetify-theme-stylesheet';
if (this.options.cspNonce) {
this.styleEl.setAttribute('nonce', this.options.cspNonce);
}
document.head.appendChild(this.styleEl);
}
initVueMeta(root) {
this.vueMeta = root.$meta();
if (this.isVueMeta23) {
// vue-meta needs to apply after mounted()
root.$nextTick(() => {
this.applyVueMeta23();
});
return;
}
const metaKeyName = typeof this.vueMeta.getOptions === 'function' ? this.vueMeta.getOptions().keyName : 'metaInfo';
const metaInfo = root.$options[metaKeyName] || {};
root.$options[metaKeyName] = () => {
metaInfo.style = metaInfo.style || [];
const vuetifyStylesheet = metaInfo.style.find(s => s.id === 'vuetify-theme-stylesheet');
if (!vuetifyStylesheet) {
metaInfo.style.push({
cssText: this.generatedStyles,
type: 'text/css',
id: 'vuetify-theme-stylesheet',
nonce: (this.options || {}).cspNonce
});
} else {
vuetifyStylesheet.cssText = this.generatedStyles;
}
return metaInfo;
};
}
applyVueMeta23() {
const {
set
} = this.vueMeta.addApp('vuetify');
set({
style: [{
cssText: this.generatedStyles,
type: 'text/css',
id: 'vuetify-theme-stylesheet',
nonce: this.options.cspNonce
}]
});
}
initSSR(ssrContext) {
// SSR
const nonce = this.options.cspNonce ? ` nonce="${this.options.cspNonce}"` : '';
ssrContext.head = ssrContext.head || '';
ssrContext.head += `<style type="text/css" id="vuetify-theme-stylesheet"${nonce}>${this.generatedStyles}</style>`;
}
initTheme() {
// Only watch for reactivity on client side
if (typeof document === 'undefined') return; // If we get here somehow, ensure
// existing instance is removed
if (this.vueInstance) this.vueInstance.$destroy(); // Use Vue instance to track reactivity
// TODO: Update to use RFC if merged
// https://github.com/vuejs/rfcs/blob/advanced-reactivity-api/active-rfcs/0000-advanced-reactivity-api.md
this.vueInstance = new Vue({
data: {
themes: this.themes
},
watch: {
themes: {
immediate: true,
deep: true,
handler: () => this.applyTheme()
}
}
});
}
get currentTheme() {
const target = this.dark ? 'dark' : 'light';
return this.themes[target];
}
get generatedStyles() {
const theme = this.parsedTheme;
/* istanbul ignore next */
const options = this.options || {};
let css;
if (options.themeCache != null) {
css = options.themeCache.get(theme);
/* istanbul ignore if */
if (css != null) return css;
}
css = ThemeUtils.genStyles(theme, options.customProperties);
if (options.minifyTheme != null) {
css = options.minifyTheme(css);
}
if (options.themeCache != null) {
options.themeCache.set(theme, css);
}
return css;
}
get parsedTheme() {
return ThemeUtils.parse(this.currentTheme || {}, undefined, getNestedValue(this.options, ['variations'], true));
} // Is using v2.3 of vue-meta
// https://github.com/nuxt/vue-meta/releases/tag/v2.3.0
get isVueMeta23() {
return typeof this.vueMeta.addApp === 'function';
}
}
Theme.property = 'theme';
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+136
View File
@@ -0,0 +1,136 @@
import { colorToInt, intToHex, colorToHex } from '../../util/colorUtils';
import * as sRGB from '../../util/color/transformSRGB';
import * as LAB from '../../util/color/transformCIELAB';
export function parse(theme, isItem = false, variations = true) {
const {
anchor,
...variant
} = theme;
const colors = Object.keys(variant);
const parsedTheme = {};
for (let i = 0; i < colors.length; ++i) {
const name = colors[i];
const value = theme[name];
if (value == null) continue;
if (!variations) {
parsedTheme[name] = {
base: intToHex(colorToInt(value))
};
} else if (isItem) {
/* istanbul ignore else */
if (name === 'base' || name.startsWith('lighten') || name.startsWith('darken')) {
parsedTheme[name] = colorToHex(value);
}
} else if (typeof value === 'object') {
parsedTheme[name] = parse(value, true, variations);
} else {
parsedTheme[name] = genVariations(name, colorToInt(value));
}
}
if (!isItem) {
parsedTheme.anchor = anchor || parsedTheme.base || parsedTheme.primary.base;
}
return parsedTheme;
}
/**
* Generate the CSS for a base color (.primary)
*/
const genBaseColor = (name, value) => {
return `
.v-application .${name} {
background-color: ${value} !important;
border-color: ${value} !important;
}
.v-application .${name}--text {
color: ${value} !important;
caret-color: ${value} !important;
}`;
};
/**
* Generate the CSS for a variant color (.primary.darken-2)
*/
const genVariantColor = (name, variant, value) => {
const [type, n] = variant.split(/(\d)/, 2);
return `
.v-application .${name}.${type}-${n} {
background-color: ${value} !important;
border-color: ${value} !important;
}
.v-application .${name}--text.text--${type}-${n} {
color: ${value} !important;
caret-color: ${value} !important;
}`;
};
const genColorVariableName = (name, variant = 'base') => `--v-${name}-${variant}`;
const genColorVariable = (name, variant = 'base') => `var(${genColorVariableName(name, variant)})`;
export function genStyles(theme, cssVar = false) {
const {
anchor,
...variant
} = theme;
const colors = Object.keys(variant);
if (!colors.length) return '';
let variablesCss = '';
let css = '';
const aColor = cssVar ? genColorVariable('anchor') : anchor;
css += `.v-application a { color: ${aColor}; }`;
cssVar && (variablesCss += ` ${genColorVariableName('anchor')}: ${anchor};\n`);
for (let i = 0; i < colors.length; ++i) {
const name = colors[i];
const value = theme[name];
css += genBaseColor(name, cssVar ? genColorVariable(name) : value.base);
cssVar && (variablesCss += ` ${genColorVariableName(name)}: ${value.base};\n`);
const variants = Object.keys(value);
for (let i = 0; i < variants.length; ++i) {
const variant = variants[i];
const variantValue = value[variant];
if (variant === 'base') continue;
css += genVariantColor(name, variant, cssVar ? genColorVariable(name, variant) : variantValue);
cssVar && (variablesCss += ` ${genColorVariableName(name, variant)}: ${variantValue};\n`);
}
}
if (cssVar) {
variablesCss = `:root {\n${variablesCss}}\n\n`;
}
return variablesCss + css;
}
export function genVariations(name, value) {
const values = {
base: intToHex(value)
};
for (let i = 5; i > 0; --i) {
values[`lighten${i}`] = intToHex(lighten(value, i));
}
for (let i = 1; i <= 4; ++i) {
values[`darken${i}`] = intToHex(darken(value, i));
}
return values;
}
export function lighten(value, amount) {
const lab = LAB.fromXYZ(sRGB.toXYZ(value));
lab[0] = lab[0] + amount * 10;
return sRGB.fromXYZ(LAB.toXYZ(lab));
}
export function darken(value, amount) {
const lab = LAB.fromXYZ(sRGB.toXYZ(value));
lab[0] = lab[0] - amount * 10;
return sRGB.fromXYZ(LAB.toXYZ(lab));
}
//# sourceMappingURL=utils.js.map
File diff suppressed because one or more lines are too long