mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 01:52:19 +08:00
feat(themes): theme builder app updates
* theme-builder wip * Theme Builder updates - new CSS variable support - realtime color updating with alpha support (rgb generation) - auto tint/shade/contrast generation - auto step generation - CSS variable highlighting (forward and backwards) - Colourlovers Palette search (via local proxy)
This commit is contained in:

committed by
Adam Bradley

parent
9e8a0c127a
commit
cdba38d004
@ -40,7 +40,8 @@
|
||||
"test.watch": "jest --watch --no-cache",
|
||||
"build-test-cmp": "stencil build --dev --config scripts/test-components/stencil.config.js",
|
||||
"theme-app-build": "stencil build --dev --config scripts/theme-builder/stencil.config.js",
|
||||
"theme-builder": "npm run theme-app-build && sd concurrent \"stencil build --dev --watch\" \"stencil-dev-server\" \"npm run theme-server\" ",
|
||||
"theme-builder": "sd concurrent \"npm run theme-app-build\" \"stencil build --dev --watch\" \"stencil-dev-server\" \"npm run theme-server\" ",
|
||||
"theme-builder:dev": "sd concurrent \"npm run theme-app-build -- --watch\" \"stencil build --dev --watch\" \"stencil-dev-server\" \"npm run theme-server\" ",
|
||||
"theme-server": "node scripts/theme-builder/server.js",
|
||||
"tslint": "tslint --project .",
|
||||
"tslint-fix": "tslint --project . --fix",
|
||||
|
@ -20,7 +20,8 @@ function requestHandler(request, response) {
|
||||
|
||||
if (parsedUrl.pathname === '/data') {
|
||||
requestDataHandler(response);
|
||||
|
||||
} else if (parsedUrl.pathname === '/color') {
|
||||
requestColorHandler(request, response);
|
||||
} else if (parsedUrl.pathname === '/save-css') {
|
||||
requestSaveCssHandler(parsedUrl, response);
|
||||
|
||||
@ -82,6 +83,29 @@ function requestDataHandler(response) {
|
||||
}
|
||||
}
|
||||
|
||||
function requestColorHandler (req, res) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
const params = {} = req.url.split('?').filter((e,i) => i > 0)[0].split('&').map(e => {let [name, value]=e.split('='); return {[name]:value}})[0],
|
||||
url = `http://www.colourlovers.com/api/palettes?format=json&keywords=${params.search}`;
|
||||
|
||||
// console.log (`Proxy: ${url}`, params);
|
||||
http.get(url, (resp) => {
|
||||
let data = '';
|
||||
|
||||
resp.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
// The whole response has been received. Print out the result.
|
||||
resp.on('end', () => {
|
||||
res.end(data);
|
||||
});
|
||||
|
||||
}).on("error", (err) => {
|
||||
console.log("Error: " + err.message);
|
||||
res.end('{success: false}');
|
||||
});
|
||||
}
|
||||
|
||||
function requestSaveCssHandler (parsedUrl, response) {
|
||||
try {
|
||||
|
@ -4,6 +4,9 @@
|
||||
* and imports for stencil collections that might be configured in your stencil.config.js file
|
||||
*/
|
||||
|
||||
import {
|
||||
Color,
|
||||
} from './components/Color';
|
||||
|
||||
import {
|
||||
AppPreview as AppPreview
|
||||
@ -32,38 +35,7 @@ declare global {
|
||||
cssText?: string;
|
||||
demoMode?: string;
|
||||
demoUrl?: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import {
|
||||
ColorSelector as ColorSelector
|
||||
} from './components/color-selector/color-selector';
|
||||
|
||||
declare global {
|
||||
interface HTMLColorSelectorElement extends ColorSelector, HTMLElement {
|
||||
}
|
||||
var HTMLColorSelectorElement: {
|
||||
prototype: HTMLColorSelectorElement;
|
||||
new (): HTMLColorSelectorElement;
|
||||
};
|
||||
interface HTMLElementTagNameMap {
|
||||
"color-selector": HTMLColorSelectorElement;
|
||||
}
|
||||
interface ElementTagNameMap {
|
||||
"color-selector": HTMLColorSelectorElement;
|
||||
}
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
"color-selector": JSXElements.ColorSelectorAttributes;
|
||||
}
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface ColorSelectorAttributes extends HTMLAttributes {
|
||||
isRgb?: boolean;
|
||||
property?: string;
|
||||
value?: string;
|
||||
hoverProperty?: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -186,9 +158,43 @@ declare global {
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface ThemeSelectorAttributes extends HTMLAttributes {
|
||||
propertiesUsed?: string[];
|
||||
themeData?: { name: string }[];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import {
|
||||
VariableSelector as VariableSelector
|
||||
} from './components/variable-selector/variable-selector';
|
||||
|
||||
declare global {
|
||||
interface HTMLVariableSelectorElement extends VariableSelector, HTMLElement {
|
||||
}
|
||||
var HTMLVariableSelectorElement: {
|
||||
prototype: HTMLVariableSelectorElement;
|
||||
new (): HTMLVariableSelectorElement;
|
||||
};
|
||||
interface HTMLElementTagNameMap {
|
||||
"variable-selector": HTMLVariableSelectorElement;
|
||||
}
|
||||
interface ElementTagNameMap {
|
||||
"variable-selector": HTMLVariableSelectorElement;
|
||||
}
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
"variable-selector": JSXElements.VariableSelectorAttributes;
|
||||
}
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface VariableSelectorAttributes extends HTMLAttributes {
|
||||
isRgb?: boolean;
|
||||
property?: string;
|
||||
type?: 'color' | 'percent';
|
||||
value?: Color | string | number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare global { namespace JSX { interface StencilJSX {} } }
|
||||
|
216
packages/core/scripts/theme-builder/src/components/Color.ts
Normal file
216
packages/core/scripts/theme-builder/src/components/Color.ts
Normal file
@ -0,0 +1,216 @@
|
||||
interface RGB {
|
||||
r: number,
|
||||
g: number,
|
||||
b: number
|
||||
}
|
||||
|
||||
interface HSL {
|
||||
h: number,
|
||||
s: number,
|
||||
l: number
|
||||
}
|
||||
|
||||
|
||||
export declare interface ColorStep {
|
||||
id: string,
|
||||
color: Color
|
||||
}
|
||||
|
||||
export declare interface ColorStepDefinition {
|
||||
color?: Color,
|
||||
increments: number[]
|
||||
}
|
||||
|
||||
function componentToHex (c) {
|
||||
const hex = c.toString(16);
|
||||
return hex.length == 1 ? `0${hex}` : hex;
|
||||
}
|
||||
|
||||
function expandHex (hex: string): string {
|
||||
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
hex = hex.replace(shorthandRegex, function (_m, r, g, b) {
|
||||
return r + r + g + g + b + b;
|
||||
});
|
||||
|
||||
return `#${hex.replace('#', '')}`;
|
||||
}
|
||||
|
||||
function hexToRGB (hex: string): RGB {
|
||||
hex = expandHex(hex);
|
||||
hex = hex.replace('#', '');
|
||||
const intValue: number = parseInt(hex, 16);
|
||||
|
||||
return {
|
||||
r: (intValue >> 16) & 255,
|
||||
g: (intValue >> 8) & 255,
|
||||
b: intValue & 255
|
||||
};
|
||||
}
|
||||
|
||||
function hslToRGB ({h, s, l}: HSL): RGB {
|
||||
h = h / 360;
|
||||
s = s / 100;
|
||||
l = l / 100;
|
||||
if (s == 0) {
|
||||
return {
|
||||
r: l,
|
||||
g: l,
|
||||
b: l
|
||||
};
|
||||
}
|
||||
|
||||
const hue2rgb = function hue2rgb (p, q, t) {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
},
|
||||
q = l < 0.5 ? l * (1 + s) : l + s - l * s,
|
||||
p = 2 * l - q,
|
||||
r = hue2rgb(p, q, h + (1 / 3)),
|
||||
g = hue2rgb(p, q, h),
|
||||
b = hue2rgb(p, q, h - (1 / 3));
|
||||
|
||||
return {
|
||||
r: Math.round(r * 255),
|
||||
g: Math.round(g * 255),
|
||||
b: Math.round(b * 255)
|
||||
};
|
||||
}
|
||||
|
||||
function mixColors (color: Color, mixColor: Color, weight: number = .5): RGB {
|
||||
const colorRGB: RGB = color.rgb,
|
||||
mixColorRGB: RGB = mixColor.rgb,
|
||||
mixColorWeight = 1 - weight;
|
||||
|
||||
return {
|
||||
r: Math.round(weight * mixColorRGB.r + mixColorWeight * colorRGB.r),
|
||||
g: Math.round(weight * mixColorRGB.g + mixColorWeight * colorRGB.g),
|
||||
b: Math.round(weight * mixColorRGB.b + mixColorWeight * colorRGB.b)
|
||||
};
|
||||
}
|
||||
|
||||
function rgbToHex ({r, g, b}: RGB) {
|
||||
return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b);
|
||||
}
|
||||
|
||||
function rgbToHSL ({r, g, b}: RGB): HSL {
|
||||
r = Math.max(Math.min(r / 255, 1), 0);
|
||||
g = Math.max(Math.min(g / 255, 1), 0);
|
||||
b = Math.max(Math.min(b / 255, 1), 0);
|
||||
const max = Math.max(r, g, b),
|
||||
min = Math.min(r, g, b),
|
||||
l = (max + min) / 2;
|
||||
let d, h, s;
|
||||
|
||||
if (max !== min) {
|
||||
d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
if (max === r) {
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
} else if (max === g) {
|
||||
h = (b - r) / d + 2;
|
||||
} else {
|
||||
h = (r - g) / d + 4;
|
||||
}
|
||||
h = h / 6;
|
||||
} else {
|
||||
h = s = 0;
|
||||
}
|
||||
return {
|
||||
h: Math.round(h * 360),
|
||||
s: Math.round(s * 100),
|
||||
l: Math.round(l * 100)
|
||||
};
|
||||
}
|
||||
|
||||
function rgbToYIQ ({r, g, b}: RGB): number {
|
||||
return ((r * 299) + (g * 587) + (b * 114)) / 1000;
|
||||
}
|
||||
|
||||
export class Color {
|
||||
readonly hex: string;
|
||||
readonly rgb: RGB;
|
||||
readonly hsl: HSL;
|
||||
readonly yiq: number;
|
||||
|
||||
public static isColor (value: string): Boolean {
|
||||
if (/rgb\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)/.test(value)) return true;
|
||||
|
||||
return /(^#[0-9a-fA-F]+)/.test(value.trim());
|
||||
}
|
||||
|
||||
constructor (value: string | RGB | HSL) {
|
||||
if (typeof(value) === 'string' && /rgb\(/.test(value)) {
|
||||
const matches = /rgb\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)/.exec(value);
|
||||
value = {r: parseInt(matches[0]), g: parseInt(matches[1]), b: parseInt(matches[2])};
|
||||
} else if (typeof(value) === 'string' && /hsl\(/.test(value)) {
|
||||
const matches = /hsl\((\d{1,3}), ?(\d{1,3}%), ?(\d{1,3}%)\)/.exec(value);
|
||||
value = {h: parseInt(matches[0]), s: parseInt(matches[1]), l: parseInt(matches[2])};
|
||||
}
|
||||
|
||||
|
||||
if (typeof(value) === 'string') {
|
||||
value = value.replace(/\s/g, '');
|
||||
this.hex = expandHex(value);
|
||||
this.rgb = hexToRGB(this.hex);
|
||||
this.hsl = rgbToHSL(this.rgb);
|
||||
} else if ('r' in value && 'g' in value && 'b' in value) {
|
||||
this.rgb = <RGB>value;
|
||||
this.hex = rgbToHex(this.rgb);
|
||||
this.hsl = rgbToHSL(this.rgb);
|
||||
} else if ('h' in value && 's' in value && 'l' in value) {
|
||||
this.hsl = <HSL>value;
|
||||
this.rgb = hslToRGB(this.hsl);
|
||||
this.hex = rgbToHex(this.rgb);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.yiq = rgbToYIQ(this.rgb);
|
||||
}
|
||||
|
||||
contrast (threshold: number = 128): Color {
|
||||
return new Color((this.yiq >= threshold ? '#000' : '#fff'));
|
||||
}
|
||||
|
||||
shiftLightness (percent: number): Color {
|
||||
const hsl: HSL = Object.assign({}, this.hsl, {
|
||||
l: this.hsl.l * percent
|
||||
});
|
||||
|
||||
return new Color(hsl);
|
||||
}
|
||||
|
||||
tint (percent: number = .1): Color {
|
||||
percent = 1 + percent;
|
||||
return this.shiftLightness(percent);
|
||||
}
|
||||
|
||||
shade (percent: number = .1): Color {
|
||||
percent = 1 - percent;
|
||||
return this.shiftLightness(percent);
|
||||
}
|
||||
|
||||
steps (from: ColorStepDefinition = {increments: [.2, .3, .5, .75]}): ColorStep[] {
|
||||
const steps: ColorStep[] = [],
|
||||
mixColor: Color = from.color || new Color((this.yiq > 128 ? '#000' : '#fff'));
|
||||
|
||||
for (let i = 1; i <= from.increments.length; i++) {
|
||||
const {r, g, b} = mixColors(this, mixColor, from.increments[i - 1]);
|
||||
steps.push({
|
||||
id: (i * 100).toString(),
|
||||
color: new Color({r,g,b})
|
||||
});
|
||||
}
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
toList (): string {
|
||||
const {r, g, b}: RGB = this.rgb;
|
||||
return `${r},${g},${b}`;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
import { Component, Prop, Watch } from '@stencil/core';
|
||||
let AppPreview = class AppPreview {
|
||||
onCssTextChange() {
|
||||
console.log('AppPreview onCssTextChange');
|
||||
this.applyStyles();
|
||||
}
|
||||
applyStyles() {
|
||||
if (this.iframe && this.iframe.contentDocument && this.iframe.contentDocument.documentElement) {
|
||||
const iframeDoc = this.iframe.contentDocument;
|
||||
const themerStyleId = 'themer-style';
|
||||
let themerStyle = iframeDoc.getElementById(themerStyleId);
|
||||
if (!themerStyle) {
|
||||
themerStyle = iframeDoc.createElement('style');
|
||||
themerStyle.id = themerStyleId;
|
||||
iframeDoc.documentElement.appendChild(themerStyle);
|
||||
}
|
||||
themerStyle.innerHTML = this.cssText;
|
||||
}
|
||||
}
|
||||
onIframeLoad() {
|
||||
this.applyStyles();
|
||||
}
|
||||
render() {
|
||||
const url = `${this.demoUrl}?ionicplatform=${this.demoMode}`;
|
||||
return [
|
||||
h("div", null,
|
||||
h("iframe", { src: url, ref: el => this.iframe = el, onLoad: this.onIframeLoad.bind(this) }))
|
||||
];
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
Prop()
|
||||
], AppPreview.prototype, "demoUrl", void 0);
|
||||
__decorate([
|
||||
Prop()
|
||||
], AppPreview.prototype, "demoMode", void 0);
|
||||
__decorate([
|
||||
Prop()
|
||||
], AppPreview.prototype, "cssText", void 0);
|
||||
__decorate([
|
||||
Watch('cssText')
|
||||
], AppPreview.prototype, "onCssTextChange", null);
|
||||
AppPreview = __decorate([
|
||||
Component({
|
||||
tag: 'app-preview',
|
||||
styleUrl: 'app-preview.css',
|
||||
shadow: true
|
||||
})
|
||||
], AppPreview);
|
||||
export { AppPreview };
|
@ -1,4 +1,5 @@
|
||||
import { Component, Prop, Watch } from '@stencil/core';
|
||||
import { Component, Event, EventEmitter, Listen, Prop, Watch } from '@stencil/core';
|
||||
import { Color } from '../Color';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -11,7 +12,11 @@ export class AppPreview {
|
||||
@Prop() demoUrl: string;
|
||||
@Prop() demoMode: string;
|
||||
@Prop() cssText: string;
|
||||
@Prop() hoverProperty: string;
|
||||
@Event() propertiesUsed: EventEmitter;
|
||||
|
||||
iframe: HTMLIFrameElement;
|
||||
hasIframeListener: boolean = false;
|
||||
|
||||
@Watch('cssText')
|
||||
onCssTextChange () {
|
||||
@ -20,6 +25,22 @@ export class AppPreview {
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
@Watch('hoverProperty')
|
||||
onHoverPropertyChange () {
|
||||
const el = this.iframe.contentDocument.documentElement;
|
||||
el.style.cssText = '';
|
||||
if (this.hoverProperty) {
|
||||
const computed = window.getComputedStyle(el),
|
||||
value = computed.getPropertyValue(this.hoverProperty);
|
||||
|
||||
if (Color.isColor(value)) {
|
||||
el.style.setProperty(this.hoverProperty, '#ff0000');
|
||||
} else {
|
||||
el.style.setProperty(this.hoverProperty, parseFloat(value) > .5 ? '.1': '1');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyStyles () {
|
||||
if (this.iframe && this.iframe.contentDocument && this.iframe.contentDocument.documentElement) {
|
||||
const iframeDoc = this.iframe.contentDocument;
|
||||
@ -30,14 +51,66 @@ export class AppPreview {
|
||||
themerStyle = iframeDoc.createElement('style');
|
||||
themerStyle.id = themerStyleId;
|
||||
iframeDoc.documentElement.appendChild(themerStyle);
|
||||
|
||||
const applicationStyle = iframeDoc.createElement('style');
|
||||
iframeDoc.documentElement.appendChild(applicationStyle);
|
||||
applicationStyle.innerHTML = 'html.theme-property-searching body * { pointer-events: auto !important}'
|
||||
}
|
||||
|
||||
themerStyle.innerHTML = this.cssText;
|
||||
}
|
||||
}
|
||||
|
||||
onIframeMouseMove (ev) {
|
||||
if (ev.ctrlKey) {
|
||||
const el: HTMLElement = this.iframe.contentDocument.documentElement;
|
||||
|
||||
if (!el.classList.contains('theme-property-searching')) {
|
||||
el.classList.add('theme-property-searching');
|
||||
}
|
||||
const sheets = (this.iframe.contentDocument.styleSheets),
|
||||
items: Element[] = Array.from(ev.currentTarget.querySelectorAll(':hover')),
|
||||
properties = [];
|
||||
|
||||
items.forEach(item => {
|
||||
for (let i in sheets) {
|
||||
const sheet: CSSStyleSheet = sheets[i] as CSSStyleSheet,
|
||||
rules = sheet.rules || sheet.cssRules;
|
||||
for (let r in rules) {
|
||||
const rule: CSSStyleRule = rules[r] as CSSStyleRule;
|
||||
if (item.matches(rule.selectorText)) {
|
||||
const matches = rule.cssText.match(/(--ion.+?),/mgi);
|
||||
if (matches) {
|
||||
properties.push(...matches.map(match => match.replace(',', '')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.propertiesUsed.emit({
|
||||
properties: Array.from(new Set(properties)).filter(prop => !/(-ios-|-md-)/.test(prop))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Listen('body:keyup', {capture: true})
|
||||
onKeyUp (ev: KeyboardEvent) {
|
||||
if (!ev.ctrlKey) {
|
||||
const el: HTMLElement = this.iframe.contentDocument.documentElement;
|
||||
el.classList.remove('theme-property-searching');
|
||||
|
||||
this.propertiesUsed.emit({
|
||||
properties: []
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onIframeLoad () {
|
||||
this.applyStyles();
|
||||
|
||||
this.iframe.contentDocument.documentElement.addEventListener('mousemove', this.onIframeMouseMove.bind(this));
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -1,78 +0,0 @@
|
||||
import { Component, Event, EventEmitter, Prop } from '@stencil/core';
|
||||
import { isValidColorValue } from '../helpers';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'color-selector',
|
||||
styleUrl: 'color-selector.css',
|
||||
shadow: true
|
||||
})
|
||||
export class ColorSelector {
|
||||
|
||||
@Prop() property: string;
|
||||
@Prop({ mutable: true }) value: string;
|
||||
@Prop() isRgb: boolean;
|
||||
isValid: boolean;
|
||||
|
||||
onChange(ev) {
|
||||
if (this.isRgb) {
|
||||
this.value = hexToRgb(ev.currentTarget.value);
|
||||
} else {
|
||||
this.value = ev.currentTarget.value;
|
||||
}
|
||||
|
||||
this.colorChange.emit({
|
||||
property: this.property,
|
||||
value: this.value
|
||||
});
|
||||
}
|
||||
|
||||
@Event() colorChange: EventEmitter;
|
||||
|
||||
render() {
|
||||
const value = this.value.trim().toLowerCase();
|
||||
const hex = rgbToHex(value);
|
||||
|
||||
return [
|
||||
<section class={isValidColorValue(value) ? 'valid' : 'invalid'}>
|
||||
<div class='color-square'>
|
||||
<input type='color' value={hex} onInput={this.onChange.bind(this)} tabindex='-1' />
|
||||
</div>
|
||||
<div class='color-value'>
|
||||
<input type='text' value={value} onInput={this.onChange.bind(this)} />
|
||||
</div>
|
||||
<div class='property-label'>
|
||||
{this.property}
|
||||
</div>
|
||||
</section>
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function rgbToHex(value: string) {
|
||||
if (value.indexOf('rgb') === -1) {
|
||||
return value;
|
||||
}
|
||||
|
||||
var c = value.replace(/[\sa-z\(\);]+/gi, '').split(',');
|
||||
c = c.map(s => parseInt(s, 10).toString(16).replace(/^([a-z\d])$/i, '0$1'));
|
||||
|
||||
return '#' + c[0] + c[1] + c[2];
|
||||
}
|
||||
|
||||
function hexToRgb(c: any) {
|
||||
if (c.indexOf('#') === -1) {
|
||||
return c;
|
||||
}
|
||||
c = c.replace(/#/, '');
|
||||
c = c.length % 6 ? c.replace(/(.)(.)(.)/, '$1$1$2$2$3$3') : c;
|
||||
c = parseInt(c, 16);
|
||||
|
||||
var a = parseFloat(a) || null;
|
||||
|
||||
const r = (c >> 16) & 255;
|
||||
const g = (c >> 8) & 255;
|
||||
const b = (c >> 0) & 255;
|
||||
|
||||
return `rgb${a ? 'a' : ''}(${[r, g, b, a].join().replace(/,$/, '')})`;
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
import { Component, Prop } from '@stencil/core';
|
||||
import { STORED_THEME_KEY, deleteCssUrl, getThemeUrl, saveCssUrl } from '../helpers';
|
||||
let CssText = class CssText {
|
||||
submitUpdate(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.saveCss(this.themeName, this.cssText);
|
||||
}
|
||||
saveCss(themeName, cssText) {
|
||||
const url = saveCssUrl(themeName, cssText);
|
||||
fetch(url).then(rsp => {
|
||||
return rsp.text().then(txt => {
|
||||
console.log('theme server response:', txt);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
createNew(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
const name = prompt(`New theme name:`);
|
||||
if (name) {
|
||||
const themeName = name.split('.')[0].trim().toLowerCase();
|
||||
if (themeName.length) {
|
||||
console.log('createNew themeName', themeName);
|
||||
localStorage.setItem(STORED_THEME_KEY, themeName);
|
||||
this.saveCss(themeName, this.cssText);
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteTheme(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
const shouldDelete = confirm(`Sure you want to delete "${this.themeName}"?`);
|
||||
if (shouldDelete) {
|
||||
const url = deleteCssUrl(this.themeName);
|
||||
fetch(url).then(rsp => {
|
||||
return rsp.text().then(txt => {
|
||||
console.log('theme server response:', txt);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
localStorage.removeItem(STORED_THEME_KEY);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return [
|
||||
h("h1", null, getThemeUrl(this.themeName)),
|
||||
h("div", null,
|
||||
h("textarea", { readOnly: true, spellcheck: 'false' }, this.cssText)),
|
||||
h("div", null,
|
||||
h("button", { type: 'button', onClick: this.submitUpdate.bind(this) }, "Save Theme"),
|
||||
h("button", { type: 'button', onClick: this.createNew.bind(this) }, "Create"),
|
||||
h("button", { type: 'button', onClick: this.deleteTheme.bind(this) }, "Delete"))
|
||||
];
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
Prop()
|
||||
], CssText.prototype, "themeName", void 0);
|
||||
__decorate([
|
||||
Prop()
|
||||
], CssText.prototype, "cssText", void 0);
|
||||
CssText = __decorate([
|
||||
Component({
|
||||
tag: 'css-text',
|
||||
styleUrl: 'css-text.css',
|
||||
shadow: true
|
||||
})
|
||||
], CssText);
|
||||
export { CssText };
|
@ -1,14 +1,14 @@
|
||||
import { Component, Prop } from '@stencil/core';
|
||||
import { STORED_THEME_KEY, deleteCssUrl, getThemeUrl, saveCssUrl } from '../helpers';
|
||||
import { Component, Element, Prop } from '@stencil/core';
|
||||
import { deleteCssUrl, getThemeUrl, saveCssUrl, STORED_THEME_KEY } from '../helpers';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'css-text',
|
||||
styleUrl: 'css-text.css',
|
||||
shadow: true
|
||||
styleUrl: 'css-text.css'
|
||||
})
|
||||
export class CssText {
|
||||
|
||||
@Element() el: HTMLElement;
|
||||
@Prop() themeName: string;
|
||||
@Prop() cssText: string;
|
||||
|
||||
@ -70,17 +70,18 @@ export class CssText {
|
||||
}
|
||||
|
||||
render () {
|
||||
|
||||
return [
|
||||
<h1>
|
||||
{getThemeUrl(this.themeName)}
|
||||
</h1>,
|
||||
<div>
|
||||
<textarea readOnly spellcheck='false'>{this.cssText}</textarea>
|
||||
<textarea readOnly spellcheck="false">{this.cssText}</textarea>
|
||||
</div>,
|
||||
<div>
|
||||
<button type='button' onClick={this.submitUpdate.bind(this)}>Save Theme</button>
|
||||
<button type='button' onClick={this.createNew.bind(this)}>Create</button>
|
||||
<button type='button' onClick={this.deleteTheme.bind(this)}>Delete</button>
|
||||
<button type="button" onClick={this.submitUpdate.bind(this)}>Save Theme</button>
|
||||
<button type="button" onClick={this.createNew.bind(this)}>Create</button>
|
||||
<button type="button" onClick={this.deleteTheme.bind(this)}>Delete</button>
|
||||
</div>
|
||||
];
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
import { Component, Event, Prop } from '@stencil/core';
|
||||
let DemoSelection = class DemoSelection {
|
||||
onChangeUrl(ev) {
|
||||
this.demoUrlChange.emit(ev.currentTarget.value);
|
||||
}
|
||||
onChangeMode(ev) {
|
||||
this.demoModeChange.emit(ev.currentTarget.value);
|
||||
}
|
||||
render() {
|
||||
return [
|
||||
h("div", null,
|
||||
h("select", { onChange: this.onChangeUrl.bind(this) }, this.demoData.map(d => h("option", { value: d.url, selected: d.url === this.demoUrl }, d.name))),
|
||||
h("select", { onChange: this.onChangeMode.bind(this) },
|
||||
h("option", { value: 'md', selected: 'md' === this.demoMode }, "md"),
|
||||
h("option", { value: 'ios', selected: 'ios' === this.demoMode }, "ios")))
|
||||
];
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
Prop()
|
||||
], DemoSelection.prototype, "demoData", void 0);
|
||||
__decorate([
|
||||
Prop()
|
||||
], DemoSelection.prototype, "demoUrl", void 0);
|
||||
__decorate([
|
||||
Prop()
|
||||
], DemoSelection.prototype, "demoMode", void 0);
|
||||
__decorate([
|
||||
Event()
|
||||
], DemoSelection.prototype, "demoUrlChange", void 0);
|
||||
__decorate([
|
||||
Event()
|
||||
], DemoSelection.prototype, "demoModeChange", void 0);
|
||||
DemoSelection = __decorate([
|
||||
Component({
|
||||
tag: 'demo-selection',
|
||||
styleUrl: 'demo-selection.css',
|
||||
shadow: true
|
||||
})
|
||||
], DemoSelection);
|
||||
export { DemoSelection };
|
@ -1,6 +1,7 @@
|
||||
|
||||
export const SERVER_DOMAIN = `http://localhost:5454`;
|
||||
export const DATA_URL = `${SERVER_DOMAIN}/data`;
|
||||
export const COLOR_URL = `${SERVER_DOMAIN}/color`;
|
||||
export const SAVE_CSS_URL = `${SERVER_DOMAIN}/save-css`;
|
||||
export const DELETE_CSS_URL = `${SERVER_DOMAIN}/delete-css`;
|
||||
export const CSS_THEME_FILE_PATH = `/src/themes/css`;
|
||||
@ -21,50 +22,3 @@ export function getThemeUrl(themeName: string) {
|
||||
export const STORED_DEMO_URL_KEY = 'theme-builder-demo-url';
|
||||
export const STORED_DEMO_MODE_KEY = 'theme-builder-demo-mode';
|
||||
export const STORED_THEME_KEY = 'theme-builder-theme-url';
|
||||
|
||||
|
||||
export function cleanCssValue(value: string) {
|
||||
if (typeof value === 'string') {
|
||||
value = (value || '').trim().toLowerCase().replace(/ /g, '');
|
||||
|
||||
if (value.length) {
|
||||
if (value.charAt(0) === '#') {
|
||||
return cleanHexValue(value);
|
||||
}
|
||||
|
||||
if (value.charAt(0) === 'r') {
|
||||
return cleanRgb(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function cleanHexValue(value: string) {
|
||||
return '#' + value.substr(1).split('').map(c => {
|
||||
return /[a-f]|[0-9]/.test(c) ? c : '';
|
||||
}).join('').substr(0, 6);
|
||||
}
|
||||
|
||||
|
||||
function cleanRgb(value: string) {
|
||||
return value.split('').map(c => {
|
||||
return /[rgba0-9\,\.\(\)]/.test(c) ? c : '';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
export function isValidColorValue(value: string) {
|
||||
if (value) {
|
||||
if (value.charAt(0) === '#') {
|
||||
const rxValidHex = /^#[0-9a-f]{6}$/i;
|
||||
return rxValidHex.test(value);
|
||||
}
|
||||
if (value.charAt(0) === 'r') {
|
||||
const rxValidRgb = /([R][G][B][A]?[(]\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\s*,\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\s*,\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])(\s*,\s*((0\.[0-9]{1})|(1\.0)|(1)))?[)])/i;
|
||||
return rxValidRgb.test(value);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
import { Component, Listen, State } from '@stencil/core';
|
||||
import { DATA_URL, STORED_DEMO_MODE_KEY, STORED_DEMO_URL_KEY } from '../helpers';
|
||||
let ThemeBuilder = class ThemeBuilder {
|
||||
constructor() {
|
||||
this.cssText = '';
|
||||
this.themeName = '';
|
||||
}
|
||||
componentWillLoad() {
|
||||
return fetch(DATA_URL).then(rsp => {
|
||||
return rsp.json().then(data => {
|
||||
this.demoData = data.demos;
|
||||
this.themeData = data.themes;
|
||||
this.initUrl();
|
||||
});
|
||||
}).catch(err => {
|
||||
console.log('ThemeBuilder componentWillLoad', err);
|
||||
});
|
||||
}
|
||||
initUrl() {
|
||||
console.log('ThemeBuilder initUrl');
|
||||
const storedUrl = localStorage.getItem(STORED_DEMO_URL_KEY);
|
||||
const defaultUrl = this.demoData[0].url;
|
||||
this.demoUrl = storedUrl || defaultUrl;
|
||||
const storedMode = localStorage.getItem(STORED_DEMO_MODE_KEY);
|
||||
const defaultMode = 'md';
|
||||
this.demoMode = storedMode || defaultMode;
|
||||
}
|
||||
onDemoUrlChange(ev) {
|
||||
this.demoUrl = ev.detail;
|
||||
localStorage.setItem(STORED_DEMO_URL_KEY, this.demoUrl);
|
||||
}
|
||||
onDemoModeChange(ev) {
|
||||
this.demoMode = ev.detail;
|
||||
localStorage.setItem(STORED_DEMO_MODE_KEY, this.demoMode);
|
||||
}
|
||||
onThemeCssChange(ev) {
|
||||
this.cssText = ev.detail.cssText;
|
||||
this.themeName = ev.detail.themeName;
|
||||
console.log('ThemeBuilder themeCssChange', this.themeName);
|
||||
}
|
||||
render() {
|
||||
return [
|
||||
h("main", null,
|
||||
h("section", { class: 'preview-column' },
|
||||
h("demo-selection", { demoData: this.demoData, demoUrl: this.demoUrl, demoMode: this.demoMode }),
|
||||
h("app-preview", { demoUrl: this.demoUrl, demoMode: this.demoMode, cssText: this.cssText })),
|
||||
h("section", { class: 'selector-column' },
|
||||
h("theme-selector", { themeData: this.themeData })),
|
||||
h("section", null,
|
||||
h("css-text", { themeName: this.themeName, cssText: this.cssText })))
|
||||
];
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
State()
|
||||
], ThemeBuilder.prototype, "demoUrl", void 0);
|
||||
__decorate([
|
||||
State()
|
||||
], ThemeBuilder.prototype, "demoMode", void 0);
|
||||
__decorate([
|
||||
State()
|
||||
], ThemeBuilder.prototype, "cssText", void 0);
|
||||
__decorate([
|
||||
State()
|
||||
], ThemeBuilder.prototype, "themeName", void 0);
|
||||
__decorate([
|
||||
Listen('demoUrlChange')
|
||||
], ThemeBuilder.prototype, "onDemoUrlChange", null);
|
||||
__decorate([
|
||||
Listen('demoModeChange')
|
||||
], ThemeBuilder.prototype, "onDemoModeChange", null);
|
||||
__decorate([
|
||||
Listen('themeCssChange')
|
||||
], ThemeBuilder.prototype, "onThemeCssChange", null);
|
||||
ThemeBuilder = __decorate([
|
||||
Component({
|
||||
tag: 'theme-builder',
|
||||
styleUrl: 'theme-builder.css',
|
||||
shadow: true
|
||||
})
|
||||
], ThemeBuilder);
|
||||
export { ThemeBuilder };
|
@ -15,6 +15,8 @@ export class ThemeBuilder {
|
||||
@State() demoUrl: string;
|
||||
@State() demoMode: string;
|
||||
@State() cssText: string = '';
|
||||
@State() hoverProperty: string;
|
||||
@State() propertiesUsed: string[];
|
||||
@State() themeName: string = '';
|
||||
|
||||
componentWillLoad() {
|
||||
@ -60,17 +62,31 @@ export class ThemeBuilder {
|
||||
console.log('ThemeBuilder themeCssChange', this.themeName);
|
||||
}
|
||||
|
||||
@Listen('propertyHoverStart')
|
||||
onPropertyHoverStart(ev) {
|
||||
this.hoverProperty = ev.detail.property;
|
||||
}
|
||||
|
||||
@Listen('propertyHoverStop')
|
||||
onPropertyHoverStop() {
|
||||
this.hoverProperty = undefined;
|
||||
}
|
||||
|
||||
@Listen('propertiesUsed')
|
||||
onPropertiesUsed(ev) {
|
||||
this.propertiesUsed = ev.detail.properties;
|
||||
}
|
||||
|
||||
render() {
|
||||
return [
|
||||
<main>
|
||||
|
||||
<section class='preview-column'>
|
||||
<demo-selection demoData={this.demoData} demoUrl={this.demoUrl} demoMode={this.demoMode}></demo-selection>
|
||||
<app-preview demoUrl={this.demoUrl} demoMode={this.demoMode} cssText={this.cssText}></app-preview>
|
||||
<app-preview demoUrl={this.demoUrl} demoMode={this.demoMode} cssText={this.cssText} hoverProperty={this.hoverProperty}></app-preview>
|
||||
</section>
|
||||
|
||||
<section class='selector-column'>
|
||||
<theme-selector themeData={this.themeData}></theme-selector>
|
||||
<theme-selector themeData={this.themeData} propertiesUsed={this.propertiesUsed}></theme-selector>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
@ -6,3 +6,147 @@ select {
|
||||
section {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.palettes {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.palette {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 75px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.palette:after {
|
||||
content: attr(data-title);
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 28px;
|
||||
opacity: .2;
|
||||
}
|
||||
|
||||
.palette .color {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.color:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
content: "#" attr(data-color);
|
||||
pointer-events: none;
|
||||
font-size: 12px;
|
||||
text-shadow: rgba(255, 255, 255, .5) 1px 1px;
|
||||
}
|
||||
|
||||
.color-buttons {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.color:hover .color-buttons {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.color-buttons button {
|
||||
outline: none;
|
||||
border: none;
|
||||
font-size: 12px;
|
||||
margin: 1px;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
opacity: .5;
|
||||
text-shadow: rgba(255, 255, 255, .5) 1px 1px;
|
||||
}
|
||||
|
||||
.color-buttons button.primary {
|
||||
background-color: var(--ion-color-primary);
|
||||
}
|
||||
|
||||
.color-buttons button.secondary {
|
||||
background-color: var(--ion-color-secondary);
|
||||
}
|
||||
|
||||
.color-buttons button.tertiary {
|
||||
background-color: var(--ion-color-tertiary);
|
||||
}
|
||||
|
||||
.color-buttons button.success {
|
||||
background-color: var(--ion-color-success);
|
||||
}
|
||||
|
||||
.color-buttons button.warning {
|
||||
background-color: var(--ion-color-warning);
|
||||
}
|
||||
|
||||
.color-buttons button.danger {
|
||||
background-color: var(--ion-color-danger);
|
||||
}
|
||||
|
||||
.color-buttons button.light {
|
||||
background-color: var(--ion-color-light);
|
||||
}
|
||||
|
||||
.color-buttons button.medium {
|
||||
background-color: var(--ion-color-medium);
|
||||
}
|
||||
|
||||
.color-buttons button.dark {
|
||||
background-color: var(--ion-color-dark);
|
||||
}
|
||||
|
||||
.color-buttons button.background {
|
||||
background-color: var(--ion-background-color);
|
||||
}
|
||||
|
||||
.color-buttons button.text {
|
||||
background-color: var(--ion-text-color);
|
||||
}
|
||||
|
||||
.color-buttons button:hover {
|
||||
background-color: rgba(161, 60, 68, 0.53);
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
display: flex;
|
||||
padding: 8px;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.search-button {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.search-toggle, .search-button {
|
||||
background-color: rgb(89, 124, 155);
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 4px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
@ -0,0 +1,130 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
import { Component, Event, Listen, Prop, State } from '@stencil/core';
|
||||
import { THEME_VARIABLES } from '../../theme-variables';
|
||||
import * as Helpers from '../helpers';
|
||||
console.log(Helpers);
|
||||
let ThemeSelector = class ThemeSelector {
|
||||
constructor() {
|
||||
this.themeVariables = [];
|
||||
}
|
||||
onChangeUrl(ev) {
|
||||
this.themeName = ev.currentTarget.value;
|
||||
localStorage.setItem(Helpers.STORED_THEME_KEY, this.themeName);
|
||||
this.loadThemeCss();
|
||||
}
|
||||
componentWillLoad() {
|
||||
const storedThemeName = localStorage.getItem(Helpers.STORED_THEME_KEY);
|
||||
const defaultThemeName = this.themeData[0].name;
|
||||
this.themeName = storedThemeName || defaultThemeName;
|
||||
this.loadThemeCss();
|
||||
}
|
||||
loadThemeCss() {
|
||||
console.log('ThemeSelector loadThemeCss');
|
||||
const themeUrl = Helpers.getThemeUrl(this.themeName);
|
||||
return fetch(themeUrl).then(rsp => {
|
||||
return rsp.text().then(css => {
|
||||
this.parseCss(css);
|
||||
this.generateCss();
|
||||
});
|
||||
});
|
||||
}
|
||||
parseCss(css) {
|
||||
console.log('ThemeSelector parseCss');
|
||||
const themer = document.getElementById('themer');
|
||||
themer.innerHTML = css;
|
||||
const computed = window.getComputedStyle(document.body);
|
||||
this.themeVariables = THEME_VARIABLES.map(themeVariable => {
|
||||
const value = (computed.getPropertyValue(themeVariable.property) || PLACEHOLDER_COLOR);
|
||||
return {
|
||||
property: themeVariable.property.trim(),
|
||||
value: value,
|
||||
type: themeVariable.type,
|
||||
computed: themeVariable.computed,
|
||||
isRgb: value.indexOf('rgb') > -1
|
||||
};
|
||||
});
|
||||
}
|
||||
generateCss() {
|
||||
console.log('ThemeSelector generateCss', this.themeName);
|
||||
const c = [];
|
||||
c.push(`/** ${this.themeName} theme **/`);
|
||||
c.push(`\n`);
|
||||
c.push(':root {');
|
||||
this.themeVariables.forEach(themeVariable => {
|
||||
themeVariable.value = Helpers.cleanCssValue(themeVariable.value);
|
||||
c.push(` ${themeVariable.property}: ${themeVariable.value};`);
|
||||
});
|
||||
c.push('}');
|
||||
const cssText = c.join('\n');
|
||||
this.themeCssChange.emit({
|
||||
cssText: cssText,
|
||||
themeName: this.themeName
|
||||
});
|
||||
}
|
||||
onColorChange(ev) {
|
||||
console.log('ThemeSelector colorChange');
|
||||
this.themeVariables = this.themeVariables.map(themeVariable => {
|
||||
let value = themeVariable.value;
|
||||
if (ev.detail.property === themeVariable.property) {
|
||||
value = ev.detail.value;
|
||||
}
|
||||
return {
|
||||
property: themeVariable.property,
|
||||
value: value,
|
||||
type: themeVariable.type,
|
||||
computed: themeVariable.computed,
|
||||
isRgb: themeVariable.isRgb
|
||||
};
|
||||
});
|
||||
this.themeVariables
|
||||
.filter(themeVariable => !!themeVariable.computed)
|
||||
.forEach(themeVariable => {
|
||||
const computed = themeVariable.computed || {}, fn = computed.fn, params = computed.params;
|
||||
if (Helpers[fn]) {
|
||||
themeVariable.value = Helpers[fn].apply(fn, params);
|
||||
}
|
||||
else {
|
||||
console.log(`Unknown Helpers Function '${fn}'`);
|
||||
}
|
||||
});
|
||||
this.generateCss();
|
||||
}
|
||||
render() {
|
||||
return [
|
||||
h("div", null,
|
||||
h("select", { onChange: this.onChangeUrl.bind(this) }, this.themeData.map(d => h("option", { value: d.name, selected: this.themeName === d.name }, d.name))),
|
||||
h("section", null, this.themeVariables
|
||||
.filter(d => !d.computed)
|
||||
.map(d => h("variable-selector", { property: d.property, value: d.value, isRgb: d.isRgb, type: d.type }))))
|
||||
];
|
||||
}
|
||||
};
|
||||
__decorate([
|
||||
State()
|
||||
], ThemeSelector.prototype, "themeName", void 0);
|
||||
__decorate([
|
||||
State()
|
||||
], ThemeSelector.prototype, "themeVariables", void 0);
|
||||
__decorate([
|
||||
Prop()
|
||||
], ThemeSelector.prototype, "themeData", void 0);
|
||||
__decorate([
|
||||
Event()
|
||||
], ThemeSelector.prototype, "themeCssChange", void 0);
|
||||
__decorate([
|
||||
Listen('colorChange')
|
||||
], ThemeSelector.prototype, "onColorChange", null);
|
||||
ThemeSelector = __decorate([
|
||||
Component({
|
||||
tag: 'theme-selector',
|
||||
styleUrl: 'theme-selector.css',
|
||||
shadow: true
|
||||
})
|
||||
], ThemeSelector);
|
||||
export { ThemeSelector };
|
||||
const PLACEHOLDER_COLOR = `#ff00ff`;
|
@ -1,48 +1,60 @@
|
||||
import { Component, Event, EventEmitter, Listen, Prop, State } from '@stencil/core';
|
||||
import { STORED_THEME_KEY, cleanCssValue, getThemeUrl } from '../helpers';
|
||||
import { Component, Element, Event, EventEmitter, Listen, Prop, State } from '@stencil/core';
|
||||
import { THEME_VARIABLES } from '../../theme-variables';
|
||||
import { Color, ColorStep } from '../Color';
|
||||
import { COLOR_URL, getThemeUrl, STORED_THEME_KEY } from '../helpers';
|
||||
|
||||
interface ThemeVariable {
|
||||
property: string;
|
||||
value?: Color | number | string;
|
||||
computed?: string;
|
||||
}
|
||||
|
||||
const PLACEHOLDER_COLOR = '#ff00ff';
|
||||
|
||||
@Component({
|
||||
tag: 'theme-selector',
|
||||
styleUrl: 'theme-selector.css',
|
||||
shadow: true
|
||||
styleUrl: 'theme-selector.css'
|
||||
})
|
||||
|
||||
export class ThemeSelector {
|
||||
|
||||
@Element() el: HTMLThemeSelectorElement;
|
||||
@State() themeName: string;
|
||||
@State() themeVariables: { property: string; value?: string; isRgb?: boolean; }[] = [];
|
||||
@State() themeVariables: ThemeVariable[] = [];
|
||||
@State() searchMode: boolean;
|
||||
@State() palettes: any[];
|
||||
@Prop() propertiesUsed: string[] = [];
|
||||
@Prop() themeData: { name: string }[];
|
||||
@Event() themeCssChange: EventEmitter;
|
||||
@Event() propertyHoverStart: EventEmitter;
|
||||
@Event() propertyHoverStop: EventEmitter;
|
||||
|
||||
private currentHoveredProperty: string;
|
||||
|
||||
onChangeUrl(ev) {
|
||||
async onChangeUrl (ev) {
|
||||
this.themeName = ev.currentTarget.value;
|
||||
localStorage.setItem(STORED_THEME_KEY, this.themeName);
|
||||
|
||||
this.loadThemeCss();
|
||||
await this.loadThemeCss();
|
||||
}
|
||||
|
||||
componentWillLoad() {
|
||||
async componentWillLoad () {
|
||||
const storedThemeName = localStorage.getItem(STORED_THEME_KEY);
|
||||
const defaultThemeName = this.themeData[0].name;
|
||||
|
||||
this.themeName = storedThemeName || defaultThemeName;
|
||||
|
||||
this.loadThemeCss();
|
||||
await this.loadThemeCss();
|
||||
}
|
||||
|
||||
loadThemeCss() {
|
||||
async loadThemeCss () {
|
||||
console.log('ThemeSelector loadThemeCss');
|
||||
|
||||
const themeUrl = getThemeUrl(this.themeName);
|
||||
|
||||
return fetch(themeUrl).then(rsp => {
|
||||
return rsp.text().then(css => {
|
||||
const css = await fetch(themeUrl).then(r => r.text());
|
||||
this.parseCss(css);
|
||||
this.generateCss();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parseCss (css: string) {
|
||||
@ -54,12 +66,12 @@ export class ThemeSelector {
|
||||
const computed = window.getComputedStyle(document.body);
|
||||
|
||||
this.themeVariables = THEME_VARIABLES.map(themeVariable => {
|
||||
const value = (computed.getPropertyValue(themeVariable.property) || PLACEHOLDER_COLOR).trim().toLowerCase();
|
||||
return {
|
||||
const value = (computed.getPropertyValue(themeVariable.property) || PLACEHOLDER_COLOR);
|
||||
|
||||
return Object.assign({}, themeVariable, {
|
||||
property: themeVariable.property.trim(),
|
||||
value: value,
|
||||
isRgb: value.indexOf('rgb') > -1
|
||||
};
|
||||
value: themeVariable.computed ? value : (!Color.isColor(value) ? parseFloat(value) : new Color(value))
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -72,8 +84,8 @@ export class ThemeSelector {
|
||||
c.push(':root {');
|
||||
|
||||
this.themeVariables.forEach(themeVariable => {
|
||||
themeVariable.value = cleanCssValue(themeVariable.value);
|
||||
c.push(` ${themeVariable.property}: ${themeVariable.value};`);
|
||||
const value = themeVariable.value;
|
||||
c.push(` ${themeVariable.property}: ${value instanceof Color ? value.hex : value};`);
|
||||
});
|
||||
|
||||
c.push('}');
|
||||
@ -85,40 +97,200 @@ export class ThemeSelector {
|
||||
});
|
||||
}
|
||||
|
||||
hoverProperty () {
|
||||
const targets: Element[] = Array.from(this.el.querySelectorAll(':hover')),
|
||||
selector: Element = targets.find(target => {
|
||||
return target.tagName.toLowerCase() === 'variable-selector';
|
||||
});
|
||||
|
||||
if (selector) {
|
||||
const property = (selector as HTMLVariableSelectorElement).property;
|
||||
|
||||
if (this.currentHoveredProperty !== property) {
|
||||
this.propertyHoverStop.emit({
|
||||
property: this.currentHoveredProperty
|
||||
});
|
||||
|
||||
this.currentHoveredProperty = property;
|
||||
this.propertyHoverStart.emit({
|
||||
property: this.currentHoveredProperty
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Listen('colorChange')
|
||||
onColorChange (ev) {
|
||||
console.log('ThemeSelector colorChange');
|
||||
|
||||
this.themeVariables = this.themeVariables.map(themeVariable => {
|
||||
let value = themeVariable.value;
|
||||
|
||||
if (ev.detail.property === themeVariable.property) {
|
||||
value = ev.detail.value;
|
||||
this.changeColor(ev.detail.property, ev.detail.value);
|
||||
}
|
||||
|
||||
return {
|
||||
property: themeVariable.property,
|
||||
value: value,
|
||||
isRgb: themeVariable.isRgb
|
||||
};
|
||||
changeColor (property: string, value: Color | string) {
|
||||
this.themeVariables = this.themeVariables.map(themeVariable => {
|
||||
if (property === themeVariable.property) {
|
||||
return Object.assign({}, themeVariable, {
|
||||
value: value instanceof Color ? value : themeVariable.value instanceof Color ? new Color(value) : value
|
||||
});
|
||||
}
|
||||
return themeVariable;
|
||||
});
|
||||
|
||||
this.themeVariables
|
||||
.filter(themeVariable => !!themeVariable.computed)
|
||||
.forEach(themeVariable => {
|
||||
const computed = themeVariable.computed,
|
||||
referenceVariable = this.themeVariables.find(themeVariable => themeVariable.property === computed),
|
||||
value = referenceVariable.value;
|
||||
if (value instanceof Color) {
|
||||
themeVariable.value = value.toList();
|
||||
}
|
||||
});
|
||||
|
||||
this.generateCss();
|
||||
}
|
||||
|
||||
@Listen('generateColors')
|
||||
onGenerateColors (ev) {
|
||||
const color: Color = ev.detail.color,
|
||||
steps: Boolean = ev.detail.steps,
|
||||
property = ev.detail.property;
|
||||
|
||||
if (color && property) {
|
||||
if (steps) {
|
||||
const steps: ColorStep[] = color.steps();
|
||||
steps.forEach((step: ColorStep) => {
|
||||
const themeVariable: ThemeVariable = this.themeVariables.find((variable: ThemeVariable) => variable.property === `${property}-step-${step.id}`);
|
||||
themeVariable && (themeVariable.value = step.color);
|
||||
});
|
||||
} else {
|
||||
const tint: ThemeVariable = this.themeVariables.find((variable: ThemeVariable) => variable.property === `${property}-tint`),
|
||||
shade: ThemeVariable = this.themeVariables.find((variable: ThemeVariable) => variable.property === `${property}-shade`),
|
||||
contrast: ThemeVariable = this.themeVariables.find((variable: ThemeVariable) => variable.property === `${property}-contrast`);
|
||||
|
||||
tint && (tint.value = color.tint());
|
||||
shade && (shade.value = color.shade());
|
||||
contrast && (contrast.value = color.contrast());
|
||||
}
|
||||
|
||||
this.generateCss();
|
||||
//TODO: Figure out why we need this typed to any
|
||||
(this.el as any).forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Listen('body:keydown')
|
||||
onKeyDown (ev: MouseEvent) {
|
||||
if (ev.ctrlKey) {
|
||||
this.hoverProperty();
|
||||
}
|
||||
}
|
||||
|
||||
@Listen('body:keyup')
|
||||
onKeyUp (ev: KeyboardEvent) {
|
||||
if (this.currentHoveredProperty && !ev.ctrlKey) {
|
||||
this.propertyHoverStop.emit({
|
||||
property: this.currentHoveredProperty
|
||||
});
|
||||
this.currentHoveredProperty = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Listen('mousemove')
|
||||
onMouseMove (ev: MouseEvent) {
|
||||
if (ev.ctrlKey) {
|
||||
this.hoverProperty();
|
||||
}
|
||||
}
|
||||
|
||||
onSearchInput (ev: KeyboardEvent) {
|
||||
if (ev.keyCode == 13) {
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
|
||||
toggleSearchMode () {
|
||||
this.searchMode = !this.searchMode;
|
||||
}
|
||||
|
||||
async search () {
|
||||
const input: HTMLInputElement = this.el.querySelector('#searchInput') as HTMLInputElement,
|
||||
value = input.value;
|
||||
|
||||
input.value = '';
|
||||
|
||||
try {
|
||||
this.palettes = await fetch(`${COLOR_URL}?search=${value}&stuff=poop`).then(r => r.json()) || [];
|
||||
} catch (e) {
|
||||
this.palettes = [];
|
||||
}
|
||||
}
|
||||
|
||||
onColorClick (ev: MouseEvent) {
|
||||
console.log(ev);
|
||||
let target: HTMLElement = ev.currentTarget as HTMLElement;
|
||||
const property = target.getAttribute('data-property');
|
||||
|
||||
while (target && !target.classList.contains('color')) {
|
||||
target = target.parentElement as HTMLElement;
|
||||
}
|
||||
|
||||
const color = target.getAttribute('data-color');
|
||||
this.changeColor(property, color);
|
||||
}
|
||||
|
||||
render () {
|
||||
const
|
||||
onColorClick = this.onColorClick.bind(this),
|
||||
variables = <section>
|
||||
{
|
||||
this.themeVariables
|
||||
.filter(d => !d.computed)
|
||||
.map(d => <variable-selector class={this.propertiesUsed.indexOf(d.property) >= 0 ? 'used' : ''}
|
||||
property={d.property} value={d.value}></variable-selector>)
|
||||
}
|
||||
</section>,
|
||||
search = <section>
|
||||
<div>
|
||||
<input type="text" id="searchInput" onKeyUp={this.onSearchInput.bind(this)}/>
|
||||
<button class="search-button" onClick={this.search.bind(this)}>Search</button>
|
||||
</div>
|
||||
<div class="palettes">
|
||||
{
|
||||
(this.palettes || []).map((d: any) => <div class="palette" data-title={d.title}>
|
||||
{(d.colors || []).map((c: string) => <div class="color" data-color={`#${c}`}
|
||||
style={{backgroundColor: `#${c}`}}>
|
||||
<div class="color-buttons">
|
||||
<button onClick={onColorClick} data-property="--ion-color-primary" class="primary">p</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-secondary" class="secondary">s</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-tertiary" class="tertiary">t</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-success" class="success">ss</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-warning" class="warning">w</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-danger" class="danger">d</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-light" class="light">l</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-medium" class="medium">m</button>
|
||||
<button onClick={onColorClick} data-property="--ion-color-dark" class="dark">dk</button>
|
||||
<button onClick={onColorClick} data-property="--ion-background-color" class="background">bg</button>
|
||||
<button onClick={onColorClick} data-property="--ion-text-color" class="text">txt</button>
|
||||
</div>
|
||||
</div>)}
|
||||
</div>)
|
||||
}
|
||||
</div>
|
||||
|
||||
</section>;
|
||||
|
||||
return [
|
||||
<div>
|
||||
<div class="top-bar">
|
||||
<select onChange={this.onChangeUrl.bind(this)}>
|
||||
{this.themeData.map(d => <option value={d.name} selected={this.themeName === d.name}>{d.name}</option>)}
|
||||
</select>
|
||||
|
||||
<section>
|
||||
{this.themeVariables.map(d => <color-selector property={d.property} value={d.value} isRgb={d.isRgb}></color-selector>)}
|
||||
</section>
|
||||
<button type="button" class="search-toggle"
|
||||
onClick={this.toggleSearchMode.bind(this)}>{this.searchMode ? 'Close' : 'Open'} Search
|
||||
</button>
|
||||
</div>
|
||||
{this.searchMode ? search : variables}
|
||||
</div>
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
const PLACEHOLDER_COLOR = `#ff00ff`;
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ section {
|
||||
.property-label {
|
||||
font-family: Courier New, Courier, monospace;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
|
||||
flex: 1;
|
||||
padding-left: 10px;
|
||||
@ -37,3 +38,7 @@ input[type="color"]::-webkit-color-swatch-wrapper {
|
||||
input[type="color"]::-webkit-color-swatch {
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
:host(.used) section {
|
||||
background-color: var(--variable-selector-color, rgba(255, 149, 243, 0.91));
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Color } from '../Color';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'variable-selector',
|
||||
styleUrl: 'variable-selector.css',
|
||||
shadow: true
|
||||
})
|
||||
export class VariableSelector {
|
||||
|
||||
@Element() el: HTMLElement;
|
||||
@Prop() property: string;
|
||||
@Prop() type: 'color' | 'percent';
|
||||
@Prop({mutable: true}) value: Color | string | number;
|
||||
@Prop() isRgb: boolean;
|
||||
@Event() colorChange: EventEmitter;
|
||||
@Event() generateColors: EventEmitter;
|
||||
|
||||
@Method()
|
||||
getProperty () {
|
||||
return this.property;
|
||||
}
|
||||
|
||||
onChange (ev) {
|
||||
const input: HTMLInputElement = ev.currentTarget,
|
||||
value = ev.currentTarget.value;
|
||||
|
||||
if (input.type === 'color') {
|
||||
this.value = new Color(value);
|
||||
} else if (input.type === 'text') {
|
||||
if (Color.isColor(value)) {
|
||||
this.value = new Color(value);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (input.type === 'range') {
|
||||
this.value = value / 100;
|
||||
}
|
||||
|
||||
this.colorChange.emit({
|
||||
property: this.property,
|
||||
value: this.value
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Listen('dblclick')
|
||||
onMouseUp (ev) {
|
||||
if (ev.altKey) {
|
||||
const color = this.value as Color;
|
||||
if (/(primary|secondary|tertiary|success|warning|danger|light|medium|dark)$/.test(this.property)) {
|
||||
this.generateColors.emit({
|
||||
color,
|
||||
property: this.property
|
||||
});
|
||||
} else if (/(^--ion-background-color$|^--ion-text-color$)/.test(this.property)) {
|
||||
this.generateColors.emit({
|
||||
color,
|
||||
steps: true,
|
||||
property: this.property
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
if (this.value instanceof Color || this.value == null) {
|
||||
const color = this.value && this.value as Color,
|
||||
value = color.hex, {r, g, b} = color.rgb;
|
||||
this.el.style.setProperty('--variable-selector-color', `rgba(${r}, ${g}, ${b}, .5`);
|
||||
return [
|
||||
<section class={value ? 'valid' : 'invalid'}>
|
||||
<div class="color-square">
|
||||
<input type="color" value={value} onInput={this.onChange.bind(this)} tabindex="-1"/>
|
||||
</div>
|
||||
<div class="color-value">
|
||||
<input type="text" value={value} onChange={this.onChange.bind(this)}/>
|
||||
</div>
|
||||
<div class="property-label">
|
||||
{this.property}
|
||||
</div>
|
||||
</section>
|
||||
];
|
||||
}
|
||||
const value = parseFloat(this.value as string);
|
||||
return [
|
||||
<section>
|
||||
<div class="property-value">
|
||||
<input type="range" value={value * 100} min="0" max="100" step="1" onInput={this.onChange.bind(this)}/>
|
||||
</div>
|
||||
<div class="property-label">
|
||||
{this.property}
|
||||
</div>
|
||||
</section>
|
||||
];
|
||||
}
|
||||
}
|
@ -12,8 +12,6 @@
|
||||
<style id="themer"></style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<theme-builder></theme-builder>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
310
packages/core/scripts/theme-builder/src/theme-variables.js
Normal file
310
packages/core/scripts/theme-builder/src/theme-variables.js
Normal file
@ -0,0 +1,310 @@
|
||||
export const THEME_VARIABLES = [
|
||||
{
|
||||
property: '--ion-alpha-lowest',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-low',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-medium',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-high',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-highest',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-primary'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-secondary'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-tertiary'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-success'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-warning'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-danger'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-light'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-medium'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-color-dark'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-backdrop-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-background-color'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-step-100'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-step-200'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-step-300'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-step-400'
|
||||
},
|
||||
{
|
||||
property: '--ion-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-box-shadow-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-rgb',
|
||||
computed: {
|
||||
fn: 'colorToRGBList',
|
||||
params: [
|
||||
'--ion-text-color'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-100'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-200'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-300'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-400'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-text-color-active'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-color-active'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-color-inactive'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-item-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-item-background-color-active'
|
||||
},
|
||||
{
|
||||
property: '--ion-item-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-item-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-placeholder-text-color'
|
||||
}
|
||||
];
|
@ -1,151 +1,250 @@
|
||||
|
||||
export const THEME_VARIABLES = [
|
||||
export const THEME_VARIABLES: {property: string, type?: 'percent' | 'color', computed?: string}[] = [
|
||||
{
|
||||
property: '--ion-alpha-lowest'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-low'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-medium'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-high'
|
||||
},
|
||||
{
|
||||
property: '--ion-alpha-highest'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-rgb',
|
||||
computed: '--ion-color-primary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-primary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-rgb',
|
||||
computed: '--ion-color-secondary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-secondary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-rgb',
|
||||
computed: '--ion-color-tertiary'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-tertiary-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-rgb',
|
||||
computed: '--ion-color-success'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-success-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-rgb',
|
||||
computed: '--ion-color-warning'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-warning-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-rgb',
|
||||
computed: '--ion-color-danger'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-danger-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-rgb',
|
||||
computed: '--ion-color-light'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-light-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-rgb',
|
||||
computed: '--ion-color-medium'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-medium-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-contrast'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color'
|
||||
property: '--ion-color-dark-rgb',
|
||||
computed: '--ion-color-dark'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-alt'
|
||||
property: '--ion-color-dark-shade'
|
||||
},
|
||||
{
|
||||
property: '--ion-color-dark-tint'
|
||||
},
|
||||
{
|
||||
property: '--ion-backdrop-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-alt'
|
||||
property: '--ion-background-color-rgb',
|
||||
computed: '--ion-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-background-color'
|
||||
property: '--ion-background-color-step-100'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-step-200'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-step-300'
|
||||
},
|
||||
{
|
||||
property: '--ion-background-color-step-400'
|
||||
},
|
||||
{
|
||||
property: '--ion-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-box-shadow-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-rgb',
|
||||
computed: '--ion-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-100'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-200'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-300'
|
||||
},
|
||||
{
|
||||
property: '--ion-text-color-step-400'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-tabbar-text-color-active'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-color-active'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-color-inactive'
|
||||
},
|
||||
{
|
||||
property: '--ion-toolbar-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-item-background-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-item-background-color-alt'
|
||||
property: '--ion-item-background-color-active'
|
||||
},
|
||||
{
|
||||
property: '--ion-border-color'
|
||||
property: '--ion-item-border-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-backdrop-color'
|
||||
property: '--ion-item-text-color'
|
||||
},
|
||||
{
|
||||
property: '--ion-box-shadow-color'
|
||||
},
|
||||
|
||||
property: '--ion-placeholder-text-color'
|
||||
}
|
||||
];
|
||||
|
@ -8,4 +8,4 @@ exports.devServer = {
|
||||
root: '../../',
|
||||
watchGlob: 'src/**',
|
||||
openUrl: '/theme-builder'
|
||||
}
|
||||
};
|
||||
|
@ -156,7 +156,7 @@ $alert-ios-button-border-width: $hairlines-width !default;
|
||||
$alert-ios-button-border-style: solid !default;
|
||||
|
||||
/// @prop - Border color of the alert button
|
||||
$alert-ios-button-border-color: $background-ios-color-step-100 !default;
|
||||
$alert-ios-button-border-color: ion-color-alpha($text-ios-color-value, text-ios-color, $alpha-low) !default;
|
||||
|
||||
/// @prop - Border radius of the alert button
|
||||
$alert-ios-button-border-radius: 0 !default;
|
||||
|
@ -34,6 +34,13 @@
|
||||
opacity: $button-ios-opacity-hover;
|
||||
}
|
||||
|
||||
a[disabled],
|
||||
button[disabled],
|
||||
.button[disabled] {
|
||||
opacity: $button-ios-opacity-disabled;
|
||||
}
|
||||
|
||||
|
||||
// iOS Default Button Color Mixin
|
||||
// --------------------------------------------------
|
||||
|
||||
|
@ -57,6 +57,9 @@ $button-ios-opacity-hover: .8 !default;
|
||||
/// @prop - Background color of the focused button
|
||||
$button-ios-background-color-focused: ion-color($colors-ios, $button-ios-background-color, shade, ios) !default;
|
||||
|
||||
/// @prop - Opacity of the button when disabled
|
||||
$button-ios-opacity-disabled: $alpha-ios-medium !default;
|
||||
|
||||
|
||||
// iOS Large Button
|
||||
// --------------------------------------------------
|
||||
|
@ -46,6 +46,11 @@
|
||||
background-color: $button-md-text-color;
|
||||
}
|
||||
|
||||
a[disabled],
|
||||
button[disabled],
|
||||
.button[disabled] {
|
||||
opacity: $button-md-opacity-disabled;
|
||||
}
|
||||
|
||||
// Material Design Default Button Color Mixin
|
||||
// --------------------------------------------------
|
||||
|
@ -78,6 +78,9 @@ $button-md-ripple-background-color: $text-md-color-step-200 !default;
|
||||
/// @prop - Background color of the focused button
|
||||
$button-md-background-color-focused: ion-color($colors-md, $button-md-background-color, shade, md) !default;
|
||||
|
||||
/// @prop - Opacity of the button when disabled
|
||||
$button-md-opacity-disabled: $alpha-md-medium !default;
|
||||
|
||||
|
||||
// Material Design Large Button
|
||||
// --------------------------------------------------
|
||||
|
@ -57,7 +57,6 @@ a[disabled],
|
||||
button[disabled],
|
||||
.button[disabled] {
|
||||
cursor: default;
|
||||
opacity: .4;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -1,119 +1,84 @@
|
||||
/** default theme **/
|
||||
|
||||
|
||||
:root {
|
||||
--ion-alpha-lowest: .06;
|
||||
--ion-alpha-low: .1;
|
||||
--ion-alpha-medium: .4;
|
||||
--ion-alpha-high: .75;
|
||||
--ion-alpha-highest: .9;
|
||||
--ion-alpha-lowest: 0.06;
|
||||
--ion-alpha-low: 0.1;
|
||||
--ion-alpha-medium: 0.4;
|
||||
--ion-alpha-high: 0.75;
|
||||
--ion-alpha-highest: 0.9;
|
||||
--ion-color-primary: #488aff;
|
||||
--ion-color-primary-contrast: #fff;
|
||||
--ion-color-primary-rgb: '72,138,255';
|
||||
--ion-color-primary-contrast: #ffffff;
|
||||
--ion-color-primary-rgb: "72,138,255";
|
||||
--ion-color-primary-shade: #3f79e0;
|
||||
--ion-color-primary-tint: #427feb;
|
||||
--ion-color-secondary: #32db64;
|
||||
--ion-color-secondary-contrast: #fff;
|
||||
--ion-color-secondary-rgb: '50,219,100';
|
||||
--ion-color-secondary-contrast: #ffffff;
|
||||
--ion-color-secondary-rgb: "50,219,100";
|
||||
--ion-color-secondary-shade: #2cc158;
|
||||
--ion-color-secondary-tint: #2ec95c;
|
||||
--ion-color-tertiary: #f4a942;
|
||||
--ion-color-tertiary-contrast: #fff;
|
||||
--ion-color-tertiary-rgb: '244,169,66';
|
||||
--ion-color-tertiary-contrast: #ffffff;
|
||||
--ion-color-tertiary-rgb: "244,169,66";
|
||||
--ion-color-tertiary-shade: #d6903d;
|
||||
--ion-color-tertiary-tint: #ffa529;
|
||||
--ion-color-success: #10dc60;
|
||||
--ion-color-success-contrast: #fff;
|
||||
--ion-color-success-rgb: '16,220,96';
|
||||
--ion-color-success-contrast: #ffffff;
|
||||
--ion-color-success-rgb: "16,220,96";
|
||||
--ion-color-success-shade: #10cb60;
|
||||
--ion-color-success-tint: #23df6d;
|
||||
--ion-color-warning: #ffce00;
|
||||
--ion-color-warning-contrast: #000;
|
||||
--ion-color-warning-rgb: '255,206,0';
|
||||
--ion-color-warning-contrast: #000000;
|
||||
--ion-color-warning-rgb: "255,206,0";
|
||||
--ion-color-warning-shade: #f1c100;
|
||||
--ion-color-warning-tint: #ffd214;
|
||||
--ion-color-danger: #f53d3d;
|
||||
--ion-color-danger-contrast: #fff;
|
||||
--ion-color-danger-rgb: '245,61,61';
|
||||
--ion-color-danger-contrast: #ffffff;
|
||||
--ion-color-danger-rgb: "245,61,61";
|
||||
--ion-color-danger-shade: #d83636;
|
||||
--ion-color-danger-tint: #e13838;
|
||||
--ion-color-light: #f4f4f4;
|
||||
--ion-color-light-contrast: #000;
|
||||
--ion-color-light-rgb: '244,244,244';
|
||||
--ion-color-light-contrast: #000000;
|
||||
--ion-color-light-rgb: "244,244,244";
|
||||
--ion-color-light-shade: #d7d7d7;
|
||||
--ion-color-light-tint: #e0e0e0;
|
||||
--ion-color-medium: #989aa2;
|
||||
--ion-color-medium-contrast: #000;
|
||||
--ion-color-medium-rgb: '152,154,162';
|
||||
--ion-color-medium-contrast: #000000;
|
||||
--ion-color-medium-rgb: "152,154,162";
|
||||
--ion-color-medium-shade: #8c8e95;
|
||||
--ion-color-medium-tint: #86888f;
|
||||
--ion-color-dark: #222;
|
||||
--ion-color-dark-contrast: #fff;
|
||||
--ion-color-dark-rgb: '34,34,34';
|
||||
--ion-color-dark: #222222;
|
||||
--ion-color-dark-contrast: #ffffff;
|
||||
--ion-color-dark-rgb: "34,34,34";
|
||||
--ion-color-dark-shade: #343434;
|
||||
--ion-color-dark-tint: #3d3d3d;
|
||||
--ion-backdrop-color: #000;
|
||||
--ion-background-color: #fff;
|
||||
--ion-background-color-rgb: '255,255,255';
|
||||
--ion-backdrop-color: #000000;
|
||||
--ion-background-color: #ffffff;
|
||||
--ion-background-color-rgb: "255,255,255";
|
||||
--ion-background-color-step-100: #f2f2f2;
|
||||
--ion-background-color-step-200: #dcdcdc;
|
||||
--ion-background-color-step-300: #bdbdbd;
|
||||
--ion-background-color-step-400: #444;
|
||||
--ion-background-color-step-400: #444444;
|
||||
--ion-border-color: #b2b2b2;
|
||||
--ion-box-shadow-color: #000;
|
||||
--ion-text-color: #000;
|
||||
--ion-text-color-rgb: '0,0,0';
|
||||
--ion-text-color-step-100: #222;
|
||||
--ion-text-color-step-200: #666;
|
||||
--ion-text-color-step-300: #999;
|
||||
--ion-box-shadow-color: #000000;
|
||||
--ion-text-color: #000000;
|
||||
--ion-text-color-rgb: "0,0,0";
|
||||
--ion-text-color-step-100: #222222;
|
||||
--ion-text-color-step-200: #666666;
|
||||
--ion-text-color-step-300: #999999;
|
||||
--ion-text-color-step-400: #c5c5c5;
|
||||
--ion-tabbar-background-color: #f8f8f8;
|
||||
--ion-tabbar-border-color: var(--ion-border-color);
|
||||
--ion-tabbar-border-color: #b2b2b2;
|
||||
--ion-tabbar-text-color: #8c8c8c;
|
||||
--ion-tabbar-text-color-active: #488aff;
|
||||
--ion-toolbar-background-color: #f8f8f8;
|
||||
--ion-toolbar-border-color: var(--ion-border-color);
|
||||
--ion-toolbar-border-color: #b2b2b2;
|
||||
--ion-toolbar-color-active: #488aff;
|
||||
--ion-toolbar-color-inactive: #8c8c8c;
|
||||
--ion-toolbar-text-color: var(--ion-text-color);
|
||||
--ion-item-background-color: var(--ion-background-color);
|
||||
--ion-item-background-color-active: var(--ion-background-color);
|
||||
--ion-toolbar-text-color: #000000;
|
||||
--ion-item-background-color: #ffffff;
|
||||
--ion-item-background-color-active: #ffffff;
|
||||
--ion-item-border-color: #c8c7cc;
|
||||
--ion-item-text-color: var(--ion-text-color);
|
||||
--ion-placeholder-text-color: #999;
|
||||
|
||||
/* Material Design */
|
||||
--ion-color-md-light: #e3e3e3;
|
||||
--ion-color-md-light-contrast: #000;
|
||||
--ion-color-md-light-rgb: '227,227,227';
|
||||
--ion-color-md-light-shade: #d0d0d0;
|
||||
--ion-color-md-light-tint: #f0f0f0;
|
||||
--ion-border-md-color: #c1c4cd;
|
||||
--ion-text-md-color-step-200: var(--ion-text-color-step-200);
|
||||
--ion-tabbar-md-border-color: rgba(0, 0, 0, .07);
|
||||
--ion-tabbar-md-text-color: var(--ion-text-md-color-step-200);
|
||||
--ion-toolbar-md-border-color: var(--ion-border-md-color);
|
||||
--ion-toolbar-md-text-color: #424242;
|
||||
--ion-item-md-background-color-active: #f1f1f1;
|
||||
--ion-item-md-border-color: #dedede;
|
||||
|
||||
/* iOS */
|
||||
--ion-color-ios-primary: var(--ion-color-primary);
|
||||
--ion-background-ios-color: var(--ion-background-color);
|
||||
--ion-background-ios-color-step-100: #f7f7f7;
|
||||
--ion-background-ios-color-step-200: #bdbdbd;
|
||||
--ion-background-ios-color-step-300: #999;
|
||||
--ion-background-ios-color-step-400: #222;
|
||||
--ion-text-ios-color-step-100: #222;
|
||||
--ion-text-ios-color-step-200: #666;
|
||||
--ion-text-ios-color-step-300: #8f8f8f;
|
||||
--ion-text-ios-color-step-400: #aeaeae;
|
||||
--ion-border-ios-color: #c1c4cd;
|
||||
--ion-tabbar-ios-translucent-background-color: rgba(248, 248, 248, 0.8);
|
||||
--ion-tabbar-ios-border-color: rgba(0, 0, 0, .2);
|
||||
--ion-tabbar-ios-text-color-active: var(--ion-color-ios-primary);
|
||||
--ion-toolbar-ios-translucent-background-color: rgba(248, 248, 248, 0.8);
|
||||
--ion-toolbar-ios-border-color: rgba(0, 0, 0, .2);
|
||||
--ion-toolbar-ios-color-active: var(--ion-color-ios-primary);
|
||||
--ion-item-ios-background-color: var(--ion-background-ios-color);
|
||||
--ion-item-ios-background-color-active: #d9d9d9;
|
||||
--ion-item-text-color: #000000;
|
||||
--ion-placeholder-text-color: #999999;
|
||||
}
|
Reference in New Issue
Block a user