From 19934bbd15917227bc3413cc1a7943b7f1404229 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Fri, 14 Aug 2020 17:56:40 -0400 Subject: [PATCH] Revert "Revert "Revert "Revert "Initial dark theme (WIP)"""" This reverts commit 389b9248dbac7502ce6e61ab8dce2e08e4b091eb. --- docs/assets/images/undraw-content-team.svg | 81 +++++++++- docs/assets/plugins/code-block/code-block.css | 41 +++++- docs/assets/plugins/theme/theme.css | 14 ++ docs/assets/plugins/theme/theme.js | 41 ++++++ docs/assets/styles/demos.css | 8 + docs/assets/styles/docs-dark.css | 122 +++++++++++++++ docs/assets/styles/docs.css | 25 +++- docs/components/card.md | 2 +- docs/index.html | 3 + src/components/avatar/avatar.scss | 1 - src/components/button/button.tsx | 14 +- src/components/checkbox/checkbox.tsx | 4 +- src/components/radio/radio.tsx | 2 +- src/components/switch/switch.scss | 1 + src/components/switch/switch.tsx | 2 +- src/styles/shoelace.scss | 139 +++++++++++++++++- 16 files changed, 481 insertions(+), 19 deletions(-) create mode 100644 docs/assets/plugins/theme/theme.css create mode 100644 docs/assets/plugins/theme/theme.js create mode 100644 docs/assets/styles/docs-dark.css diff --git a/docs/assets/images/undraw-content-team.svg b/docs/assets/images/undraw-content-team.svg index 08bc7482..3ea01ce1 100644 --- a/docs/assets/images/undraw-content-team.svg +++ b/docs/assets/images/undraw-content-team.svg @@ -1 +1,80 @@ - \ No newline at end of file + + + + undraw-content-team + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/assets/plugins/code-block/code-block.css b/docs/assets/plugins/code-block/code-block.css index 42e6b56e..66781f77 100644 --- a/docs/assets/plugins/code-block/code-block.css +++ b/docs/assets/plugins/code-block/code-block.css @@ -49,7 +49,7 @@ border: solid 1px var(--sl-color-gray-90); border-bottom: none; border-radius: 0 !important; - margin: 0 !important; + margin: 0; display: none; } @@ -106,3 +106,42 @@ .code-block--expanded .code-block__toggle svg { transform: rotate(180deg); } + +/* Dark theme */ +.sl-theme-dark .code-block { + background-color: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 13%); +} + +.sl-theme-dark .code-block__preview { + background-color: var(--sl-color-gray-10); + border-color: var(--sl-color-gray-20); +} + +.sl-theme-dark .code-block__source { + border-color: var(--sl-color-gray-20); +} + +.sl-theme-dark .code-block__resizer { + border-left-color: var(--sl-color-gray-20); + background-color: var(--sl-color-gray-10); + color: var(--sl-color-gray-60); +} + +.sl-theme-dark .code-block__toggle { + background-color: var(--sl-color-gray-10); + border-color: var(--sl-color-gray-20); + color: var(--sl-color-gray-60); +} + +.sl-theme-dark .code-block__toggle:hover, +.sl-theme-dark .code-block__toggle:active { + background-color: var(--sl-color-gray-10); + border-color: var(--sl-color-gray-20); + color: var(--sl-color-gray-60); +} + +.sl-theme-dark .code-block__toggle:focus { + border-color: var(--sl-color-primary-50); + background-color: var(--sl-color-primary-10); + color: var(--sl-color-primary-50); +} diff --git a/docs/assets/plugins/theme/theme.css b/docs/assets/plugins/theme/theme.css new file mode 100644 index 00000000..abfc95a9 --- /dev/null +++ b/docs/assets/plugins/theme/theme.css @@ -0,0 +1,14 @@ +.theme-toggle { + position: fixed; + top: .5rem; + right: .5rem; + z-index: 100; +} + +@media screen and (max-width: 768px) { + .theme-toggle { + top: .25rem; + right: .25rem; + transform: scale(.8); + } +} diff --git a/docs/assets/plugins/theme/theme.js b/docs/assets/plugins/theme/theme.js new file mode 100644 index 00000000..7e4a3648 --- /dev/null +++ b/docs/assets/plugins/theme/theme.js @@ -0,0 +1,41 @@ +(() => { + if (!window.$docsify) { + throw new Error('Docsify must be loaded before installing this plugin.'); + } + + window.$docsify.plugins.push((hook, vm) => { + hook.mounted(function () { + let isDark = localStorage.getItem('theme') === 'sl-theme-dark'; + const sidebarToggle = document.querySelector('.sidebar-toggle'); + const noTransitions = Object.assign(document.createElement('style'), { + textContent: '* { transition: none !important; }' + }); + const toggle = Object.assign(document.createElement('sl-icon-button'), { + name: isDark ? 'sun' : 'moon', + label: 'Toggle dark mode' + }); + toggle.classList.add('theme-toggle'); + + // Set initial theme + if (isDark) { + document.body.classList.add('sl-theme-dark'); + } + + // Toggle theme + toggle.addEventListener('click', () => { + isDark = !isDark; + isDark ? localStorage.setItem('theme', 'sl-theme-dark') : localStorage.removeItem('theme'); + toggle.name = isDark ? 'sun' : 'moon'; + + // Disable transitions as the theme changes + document.body.appendChild(noTransitions); + requestAnimationFrame(() => { + document.body.classList.toggle('sl-theme-dark', isDark); + requestAnimationFrame(() => document.body.removeChild(noTransitions)); + }); + }); + + sidebarToggle.insertAdjacentElement('afterend', toggle); + }); + }); +})(); diff --git a/docs/assets/styles/demos.css b/docs/assets/styles/demos.css index ac95ce68..559dfa0e 100644 --- a/docs/assets/styles/demos.css +++ b/docs/assets/styles/demos.css @@ -37,6 +37,10 @@ width: 100%; } +.sl-theme-dark .transition-demo { + background: var(--sl-color-gray-20); +} + /* Spacing demo */ .spacing-demo { width: 100px; @@ -50,3 +54,7 @@ width: 4rem; height: 4rem; } + +.sl-theme-dark .elevation-demo { + background-color: var(--sl-color-gray-20); +} diff --git a/docs/assets/styles/docs-dark.css b/docs/assets/styles/docs-dark.css new file mode 100644 index 00000000..bab51b61 --- /dev/null +++ b/docs/assets/styles/docs-dark.css @@ -0,0 +1,122 @@ +.sl-theme-dark { + background: var(--sl-color-gray-10); + color: var(--sl-color-gray-80); +} + +/* Sidebar **/ +.sl-theme-dark .sidebar { + background: var(--sl-color-gray-10); + border-right-color: var(--sl-color-gray-15); +} + +.sl-theme-dark .sidebar li > p { + color: var(--sl-color-white); + border-bottom-color: var(--sl-color-gray-20); +} + +.sl-theme-dark .sidebar-toggle { + background-color: hsla(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 10%, 0.8); +} + +.sl-theme-dark .docsify-pagination-container { + border-top-color: var(--sl-color-gray-20) !important; +} + +/* Search */ +.sl-theme-dark .sidebar .search input[type='search'] { + background: var(--sl-input-background-color); + border-color: var(--sl-input-border-color); + color: var(--sl-input-color); +} + +.sl-theme-dark .sidebar .search input[type='search']:hover { + border-color: var(--sl-input-border-color-hover); +} + +.sl-theme-dark .sidebar .search input[type='search']:focus { + border-color: var(--sl-input-border-color-focus); +} + +.sl-theme-dark .sidebar .clear-button { + color: var(--sl-color-gray-30); +} + +.sl-theme-dark .sidebar .clear-button svg circle { + fill: currentColor; +} + +/* Content */ +.sl-theme-dark .component-header { + border-bottom-color: var(--sl-color-gray-20); +} + +.sl-theme-dark .anchor span { + color: var(--sl-color-white); +} + +.sl-theme-dark .markdown-section h2 { + border-bottom-color: var(--sl-color-gray-20); +} + +.sl-theme-dark .markdown-section blockquote { + border-left-color: var(--sl-color-gray-20); +} + +.sl-theme-dark .markdown-section kbd { + border-color: var(--sl-color-gray-20); +} + +/* Tables */ +.sl-theme-dark .markdown-section tr:nth-child(2n) { + background: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 13%); +} + +.sl-theme-dark .markdown-section td { + border-top-color: var(--sl-color-gray-20); + border-bottom-color: var(--sl-color-gray-20); +} + +.sl-theme-dark .markdown-section table .attribute-tooltip { + border-bottom-color: var(--sl-color-gray-30); +} + +/* Tips & warnings */ +.sl-theme-dark .markdown-section p.tip, +.sl-theme-dark .markdown-section p.warn { + background-color: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 13%) +} + +.sl-theme-dark .markdown-section p.tip code, +.sl-theme-dark .markdown-section p.warn code { + background-color: var(--sl-color-gray-15); +} + +/* Code blocks */ +.sl-theme-dark .markdown-section pre { + background-color: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 13%); +} + +.sl-theme-dark .markdown-section pre > code { + color: var(--sl-color-gray-80); +} + +/* Repo buttons */ +.sl-theme-dark .repo-button { + background-color: var(--sl-color-gray-10); + border-color: var(--sl-color-gray-25); + color: var(--sl-color-gray-80); +} + +.sl-theme-dark .repo-button--github sl-icon { + color: var(--sl-color-white); +} + +.sl-theme-dark .repo-button:hover { + background-color: var(--sl-color-gray-15); + border: solid 1px var(--sl-color-gray-30); +} + +.sl-theme-dark .repo-button:focus { + border-color: var(--sl-color-primary-50); +} + diff --git a/docs/assets/styles/docs.css b/docs/assets/styles/docs.css index b9e93920..8272926b 100644 --- a/docs/assets/styles/docs.css +++ b/docs/assets/styles/docs.css @@ -60,7 +60,11 @@ strong { padding-left: 1rem; padding-right: 2rem; margin: 0 1.25rem; - transition: var(--sl-transition-fast) box-shadow; + transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow; +} + +.sidebar .search input[type='search']:hover { + border-color: var(--sl-input-border-color-hover); } .sidebar .search input[type='search']:focus { @@ -124,6 +128,15 @@ strong { padding: .5rem; } +.sidebar-toggle:focus { + outline: none; + box-shadow: var(--sl-focus-ring-box-shadow); +} + +.sidebar-toggle span:last-child { + margin-bottom: 0; +} + @media screen and (max-width: 768px) { body.close .sidebar-toggle { width: 2rem; @@ -258,8 +271,8 @@ strong { margin: 0; } -.markdown-section .anchor { - color: var(--sl-color-primary-50); +.docsify-pagination-container { + border-top-color: var(--sl-color-gray-90) !important; } .markdown-section h1, @@ -332,6 +345,7 @@ strong { .markdown-section pre > code { display: block; background: none; + border-radius: 0; color: var(--sl-color-gray-30); padding: var(--sl-spacing-medium); overflow: auto; @@ -488,6 +502,11 @@ strong { background-color: var(--sl-color-danger-50); } +.markdown-section p.tip code, +.markdown-section p.warn code { + background-color: var(--sl-color-gray-95); +} + /* Component headers */ .component-header { border-bottom: solid 1px var(--sl-color-gray-90); diff --git a/docs/components/card.md b/docs/components/card.md index 97151231..ab9e922e 100644 --- a/docs/components/card.md +++ b/docs/components/card.md @@ -28,7 +28,7 @@ Cards can be used to group related subjects in a container. } .card-overview small { - color: var(--sl-color-gray-60); + color: var(--sl-color-gray-50); } .card-overview [slot="footer"] { diff --git a/docs/index.html b/docs/index.html index 62d2f01c..7326c6cf 100644 --- a/docs/index.html +++ b/docs/index.html @@ -33,8 +33,10 @@ + + @@ -93,5 +95,6 @@ + diff --git a/src/components/avatar/avatar.scss b/src/components/avatar/avatar.scss index 33ecd887..e5ba240b 100644 --- a/src/components/avatar/avatar.scss +++ b/src/components/avatar/avatar.scss @@ -1,7 +1,6 @@ @import 'component'; /** - * @prop --background-color: The avatar's background color. * @prop --size: The size of the avatar. */ :host { diff --git a/src/components/button/button.tsx b/src/components/button/button.tsx index 0ea08c78..5b93e311 100644 --- a/src/components/button/button.tsx +++ b/src/components/button/button.tsx @@ -26,28 +26,28 @@ export class Button { @State() hasFocus = false; /** The button's type. */ - @Prop() type: 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'text' = 'default'; + @Prop({ reflect: true }) type: 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'text' = 'default'; /** The button's size. */ - @Prop() size: 'small' | 'medium' | 'large' = 'medium'; + @Prop({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; /** Set to true to draw the button with a caret for use with dropdowns, popovers, etc. */ @Prop() caret = false; /** Set to true to disable the button. */ - @Prop() disabled = false; + @Prop({ reflect: true }) disabled = false; /** Set to true to draw the button in a loading state. */ - @Prop() loading = false; + @Prop({ reflect: true }) loading = false; /** Set to true to draw a pill-style button with rounded edges. */ - @Prop() pill = false; + @Prop({ reflect: true }) pill = false; /** Set to true to draw a circle button. */ - @Prop() circle = false; + @Prop({ reflect: true }) circle = false; /** Indicates if activating the button should submit the form. Ignored when `href` is set. */ - @Prop() submit = false; + @Prop({ reflect: true }) submit = false; /** An optional name for the button. Ignored when `href` is set. */ @Prop() name: string; diff --git a/src/components/checkbox/checkbox.tsx b/src/components/checkbox/checkbox.tsx index b142ae90..c6805403 100644 --- a/src/components/checkbox/checkbox.tsx +++ b/src/components/checkbox/checkbox.tsx @@ -37,10 +37,10 @@ export class Checkbox { @Prop() disabled = false; /** Set to true to draw the checkbox in a checked state. */ - @Prop({ mutable: true }) checked = false; + @Prop({ mutable: true, reflect: true }) checked = false; /** Set to true to draw the checkbox in an indeterminate state. */ - @Prop({ mutable: true }) indeterminate = false; + @Prop({ mutable: true, reflect: true }) indeterminate = false; /** Emitted when the control loses focus. */ @Event() slBlur: EventEmitter; diff --git a/src/components/radio/radio.tsx b/src/components/radio/radio.tsx index 89de2bc5..c1cfe6ce 100644 --- a/src/components/radio/radio.tsx +++ b/src/components/radio/radio.tsx @@ -38,7 +38,7 @@ export class Radio { @Prop() disabled = false; /** Set to true to draw the radio in a checked state. */ - @Prop({ mutable: true }) checked = false; + @Prop({ mutable: true, reflect: true }) checked = false; @Watch('checked') handleCheckedChange() { diff --git a/src/components/switch/switch.scss b/src/components/switch/switch.scss index 19331212..f54c16f4 100644 --- a/src/components/switch/switch.scss +++ b/src/components/switch/switch.scss @@ -12,6 +12,7 @@ .switch { display: inline-flex; align-items: center; + width: var(--width); font-family: var(--sl-input-font-family); font-size: var(--sl-input-font-size-medium); font-weight: var(--sl-input-font-weight); diff --git a/src/components/switch/switch.tsx b/src/components/switch/switch.tsx index fc2d91c4..05daa24d 100644 --- a/src/components/switch/switch.tsx +++ b/src/components/switch/switch.tsx @@ -36,7 +36,7 @@ export class Switch { @Prop() disabled = false; /** Set to true to draw the switch in a checked state. */ - @Prop({ mutable: true }) checked = false; + @Prop({ mutable: true, reflect: true }) checked = false; @Watch('checked') handleCheckedChange() { diff --git a/src/styles/shoelace.scss b/src/styles/shoelace.scss index e4755ae3..daa06860 100644 --- a/src/styles/shoelace.scss +++ b/src/styles/shoelace.scss @@ -1,5 +1,4 @@ /*! Shoelace */ - @import 'mixins/make-color-palette'; :root { @@ -271,3 +270,141 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @import '../components/button-group/button-group.light-dom'; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Dark theme +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +.sl-theme-dark { + // Theme colors + --sl-color-primary-saturation: 80%; + --sl-color-success-saturation: 50%; + --sl-color-info-saturation: 10%; + --sl-color-warning-saturation: 70%; + --sl-color-danger-saturation: 75%; + --sl-color-gray-saturation: 10%; + + @include make-color-palette('primary'); + @include make-color-palette('success'); + @include make-color-palette('info'); + @include make-color-palette('warning'); + @include make-color-palette('danger'); + @include make-color-palette('gray'); + + // Inputs + --sl-input-background-color: var(--sl-color-gray-10); + --sl-input-background-color-hover: var(--sl-color-gray-10); + --sl-input-background-color-focus: var(--sl-color-gray-10); + --sl-input-background-color-disabled: var(--sl-color-gray-15); + + --sl-input-border-color: var(--sl-color-gray-30); + --sl-input-border-color-hover: var(--sl-color-gray-40); + --sl-input-border-color-focus: var(--sl-color-primary-50); + --sl-input-border-color-disabled: var(--sl-color-gray-80); + --sl-input-border-color-valid: var(--sl-color-success-50); + --sl-input-border-color-invalid: var(--sl-color-danger-50); + + --sl-input-font-family: var(--sl-font-sans); + --sl-input-font-weight: var(--sl-font-weight-normal); + --sl-input-font-size-small: var(--sl-font-size-small); + --sl-input-font-size-medium: var(--sl-font-size-medium); + --sl-input-font-size-large: var(--sl-font-size-large); + --sl-input-letter-spacing: var(--sl-letter-spacing-normal); + + --sl-input-border-color: var(--sl-color-gray-30); + --sl-input-border-color-hover: var(--sl-color-gray-40); + --sl-input-border-color-focus: var(--sl-color-primary-60); + --sl-input-border-color-disabled: var(--sl-color-gray-30); + --sl-input-border-color-valid: var(--sl-color-success-50); + --sl-input-border-color-invalid: var(--sl-color-danger-50); + + --sl-input-color: var(--sl-color-gray-80); + --sl-input-color-hover: var(--sl-color-gray-80); + --sl-input-color-focus: var(--sl-color-gray-80); + --sl-input-color-disabled: var(--sl-color-gray-90); + --sl-input-color-valid: var(--sl-color-success-60); + --sl-input-color-invalid: var(--sl-color-danger-40); + + --sl-input-icon-color: var(--sl-color-gray-40); + --sl-input-icon-color-hover: var(--sl-color-gray-60); + --sl-input-icon-color-focus: var(--sl-color-gray-60); + + --sl-input-placeholder-color: var(--sl-color-gray-30); + --sl-input-placeholder-color-disabled: var(--sl-color-gray-40); + + // Tooltips + --sl-tooltip-background-color: var(--sl-color-gray-80); + --sl-tooltip-color: var(--sl-color-black); + + // Alert + sl-alert::part(base) { + background-color: var(--sl-color-gray-10); + border-left-color: var(--sl-color-gray-20); + border-right-color: var(--sl-color-gray-20); + border-bottom-color: var(--sl-color-gray-20); + color: var(--sl-color-gray-80); + } + + // Avatar + sl-avatar::part(base) { + background-color: var(--sl-color-gray-30); + color: var(--sl-color-gray-70); + } + + // Button + sl-button[type="default"]::part(base) { + background-color: var(--sl-color-gray-10); + border-color: var(--sl-color-gray-30); + color: var(--sl-color-gray-60); + } + + sl-button[type="default"]:not([disabled])::part(base):hover { + background-color: var(--sl-color-primary-15); + border-color: var(--sl-color-primary-30); + color: var(--sl-color-primary-60); + } + + sl-button[type="default"]:not([disabled])::part(base):focus { + background-color: var(--sl-color-primary-15); + border-color: var(--sl-color-primary-30); + color: var(--sl-color-primary-60); + box-shadow: 0 0 0 var(--sl-focus-ring-width) + hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha)); + } + + sl-button[type="default"]:not([disabled])::part(base):active { + background-color: var(--sl-color-primary-15); + border-color: var(--sl-color-primary-40); + color: var(--sl-color-primary-70); + } + + // Card + sl-card::part(base) { + background-color: var(--sl-color-gray-10); + --border-color: var(--sl-color-gray-20); + } + + // Color picker + sl-color-picker::part(base) { + background-color: var(--sl-color-gray-10); + border-color: var(--sl-color-gray-20); + } + + sl-color-picker::part(swatches) { + border-top-color: var(--sl-color-gray-20); + } + + // Details + sl-details::part(base) { + border-color: var(--sl-color-gray-20); + } + + // Dialog + + // TODO: + + // Rating + sl-rating { + --symbol-color: var(--sl-color-gray-35); + } +} \ No newline at end of file