diff --git a/src/renderer/components/BaseMap.vue b/src/renderer/components/BaseMap.vue index bf31db9d..87855c3e 100644 --- a/src/renderer/components/BaseMap.vue +++ b/src/renderer/components/BaseMap.vue @@ -99,7 +99,7 @@ onMounted(() => { display: flex; justify-content: center; align-items: center; - background: $primary-color; + background: var(--primary-color); border-radius: 50%; box-shadow: 0 0 5px 1px darken($body-font-color-dark, 40%); } diff --git a/src/renderer/components/ModalAllConnections.vue b/src/renderer/components/ModalAllConnections.vue index ff6fce48..6118f1fd 100644 --- a/src/renderer/components/ModalAllConnections.vue +++ b/src/renderer/components/ModalAllConnections.vue @@ -360,7 +360,7 @@ onBeforeUnmount(() => { outline: none; &:focus { - box-shadow: 0 0 3px 0.1rem rgba($primary-color, 80%); + box-shadow: 0 0 3px 0.1rem rgba(var(--primary-color), 80%); } &:hover { diff --git a/src/renderer/components/ModalConnectionAppearance.vue b/src/renderer/components/ModalConnectionAppearance.vue index 8c968ce4..e2860844 100644 --- a/src/renderer/components/ModalConnectionAppearance.vue +++ b/src/renderer/components/ModalConnectionAppearance.vue @@ -204,7 +204,7 @@ onBeforeUnmount(() => { cursor: pointer; &.selected { - outline: 2px solid $primary-color; + outline: 2px solid var(--primary-color); border-radius: 8px; } } diff --git a/src/renderer/components/ModalHistory.vue b/src/renderer/components/ModalHistory.vue index 18165634..97c22f44 100644 --- a/src/renderer/components/ModalHistory.vue +++ b/src/renderer/components/ModalHistory.vue @@ -287,7 +287,7 @@ onBeforeUnmount(() => { max-width: 100%; display: inline-block; font-size: 100%; - // color: $primary-color; + // color: var(--primary-color); opacity: 0.8; font-weight: 600; } diff --git a/src/renderer/components/ModalSettings.vue b/src/renderer/components/ModalSettings.vue index 60c28324..0292523f 100644 --- a/src/renderer/components/ModalSettings.vue +++ b/src/renderer/components/ModalSettings.vue @@ -703,7 +703,7 @@ onBeforeUnmount(() => { &.selected { img { - box-shadow: 0 0 0 3px $primary-color; + box-shadow: 0 0 0 3px var(--primary-color); } } @@ -731,7 +731,7 @@ onBeforeUnmount(() => { .badge-update::after { bottom: initial; - background: $primary-color; + background: var(--primary-color); } .form-label { diff --git a/src/renderer/components/QueryEditor.vue b/src/renderer/components/QueryEditor.vue index 70b2d2bd..e662f742 100644 --- a/src/renderer/components/QueryEditor.vue +++ b/src/renderer/components/QueryEditor.vue @@ -409,7 +409,7 @@ defineExpose({ editor }); position: absolute; left: 3px; top: 2px; - color: $primary-color; + color: var(--primary-color); display: inline-block; font: normal normal normal 24px/1 "Material Design Icons", sans-serif; font-size: inherit; diff --git a/src/renderer/components/TheFooter.vue b/src/renderer/components/TheFooter.vue index c8ff886a..702ffc2a 100644 --- a/src/renderer/components/TheFooter.vue +++ b/src/renderer/components/TheFooter.vue @@ -85,10 +85,11 @@ diff --git a/src/renderer/components/TheSettingBar.vue b/src/renderer/components/TheSettingBar.vue index 6ecaef2c..455dead6 100644 --- a/src/renderer/components/TheSettingBar.vue +++ b/src/renderer/components/TheSettingBar.vue @@ -233,6 +233,7 @@ if (!connectionsArr.value.length) border-radius: 0; padding: 0; position: relative; + border: none; &:hover { opacity: 1; diff --git a/src/renderer/components/WorkspaceExploreBar.vue b/src/renderer/components/WorkspaceExploreBar.vue index 3bd5c1b9..aca44bdf 100644 --- a/src/renderer/components/WorkspaceExploreBar.vue +++ b/src/renderer/components/WorkspaceExploreBar.vue @@ -501,7 +501,7 @@ const toggleSearchMethod = () => { transition: background 0.2s; &:hover { - background: rgba($primary-color, 50%); + background: rgba(var(--primary-color), 50%); } } diff --git a/src/renderer/components/WorkspaceQueryConsole.vue b/src/renderer/components/WorkspaceQueryConsole.vue index 76b6aba9..f8483549 100644 --- a/src/renderer/components/WorkspaceQueryConsole.vue +++ b/src/renderer/components/WorkspaceQueryConsole.vue @@ -145,7 +145,7 @@ onMounted(() => { transition: background 0.2s; &:hover { - background: rgba($primary-color, 50%); + background: rgba(var(--primary-color), 50%); } } diff --git a/src/renderer/components/WorkspaceTabQuery.vue b/src/renderer/components/WorkspaceTabQuery.vue index 83017eb7..161d5b3e 100644 --- a/src/renderer/components/WorkspaceTabQuery.vue +++ b/src/renderer/components/WorkspaceTabQuery.vue @@ -821,7 +821,7 @@ onBeforeUnmount(() => { transition: background 0.2s; &:hover { - background: rgba($primary-color, 50%); + background: rgba(var(--primary-color), 50%); } } diff --git a/src/renderer/libs/colorShade.ts b/src/renderer/libs/colorShade.ts new file mode 100644 index 00000000..4a506245 --- /dev/null +++ b/src/renderer/libs/colorShade.ts @@ -0,0 +1,18 @@ +export const colorShade = (color: string, amount: number) => { + color = color.replaceAll('#', ''); + if (color.length === 3) color = color[0] + color[0] + color[1] + color[1] + color[2] + color[2]; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let [r, g, b] = color.match(/.{2}/g) as any; + ([r, g, b] = [parseInt(r, 16) + amount, parseInt(g, 16) + amount, parseInt(b, 16) + amount]); + + r = Math.max(Math.min(255, r), 0).toString(16); + g = Math.max(Math.min(255, g), 0).toString(16); + b = Math.max(Math.min(255, b), 0).toString(16); + + const rr = (r.length < 2 ? '0' : '') + r; + const gg = (g.length < 2 ? '0' : '') + g; + const bb = (b.length < 2 ? '0' : '') + b; + + return `#${rr}${gg}${bb}`; +}; diff --git a/src/renderer/libs/hexToRgba.ts b/src/renderer/libs/hexToRgba.ts new file mode 100644 index 00000000..233cb365 --- /dev/null +++ b/src/renderer/libs/hexToRgba.ts @@ -0,0 +1,16 @@ +export const hexToRGBA = (hexCode: string, opacity = 1) => { + let hex = hexCode.replace('#', ''); + + if (hex.length === 3) + hex = `${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`; + + const r = parseInt(hex.substring(0, 2), 16); + const g = parseInt(hex.substring(2, 4), 16); + const b = parseInt(hex.substring(4, 6), 16); + + /* Backward compatibility for whole number based opacity values. */ + if (opacity > 1 && opacity <= 100) + opacity = opacity / 100; + + return `rgba(${r},${g},${b},${opacity})`; +}; diff --git a/src/renderer/scss/_variables.scss b/src/renderer/scss/_variables.scss index 0670124a..9e6ba963 100644 --- a/src/renderer/scss/_variables.scss +++ b/src/renderer/scss/_variables.scss @@ -1,5 +1,5 @@ /* Colors */ -$body-bg: #fdfdfd; +$body-bg: #f3f3f3; $body-bg-dark: #1d1d1d; $body-font-color-dark: #fff; $bg-color-dark: #1d1d1d; diff --git a/src/renderer/scss/main.scss b/src/renderer/scss/main.scss index e3d15839..f3ba82f1 100644 --- a/src/renderer/scss/main.scss +++ b/src/renderer/scss/main.scss @@ -1,4 +1,10 @@ /* stylelint-disable */ +:root { + --primary-color: #e36929; + --primary-color-dark: color-mix(in srgb, var(--primary-color), #000 30%); + --primary-color-shadow: 0 0 0 0.1rem rgba(227, 105, 41, 0.2); +} + @import "~spectre.css/src/variables"; @import "variables"; @import "transitions"; @@ -16,12 +22,16 @@ body { user-select: none; } +a { + color: var(--primary-color); +} + ::selection, option:hover, option:focus, option:active, option:checked { - background-color: $primary-color; + background-color: var(--primary-color); color: $light-color; } @@ -248,7 +258,7 @@ option:checked { height: 2px; width: 0; transition: width 0.2s; - background-color: $primary-color; + background-color: var(--primary-color); position: absolute; bottom: 0; } @@ -300,9 +310,23 @@ option:checked { height: auto; } +.form-checkbox input:checked + .form-icon, .form-radio input:checked + .form-icon, .form-switch input:checked + .form-icon { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.form-checkbox input:focus + .form-icon, .form-radio input:focus + .form-icon, .form-switch input:focus + .form-icon { + box-shadow: 0 0 0 0.1rem var(--primary-color-shadow); + border-color: var(--primary-color); +} + .form-select { cursor: pointer; + &:focus { + box-shadow: 0 0 0 0.1rem var(--primary-color-shadow); + } + &.small-select { height: 21px; font-size: 0.7rem; @@ -311,7 +335,8 @@ option:checked { &.select { &.select--open { - border-color: $primary-color !important; + border-color: var(--primary-color) !important; + box-shadow: 0 0 0 0.1rem var(--primary-color-shadow) !important; @include control-shadow(); } @@ -336,19 +361,28 @@ option:checked { z-index: 401 !important; border: 1px solid transparent; border-radius: $border-radius; - box-shadow: 0 8px 17px 0 rgb(0 0 0 / 20%), 0 6px 20px 0 rgb(0 0 0 / 19%); + box-shadow: + 0 8px 17px 0 rgb(0 0 0 / 20%), + 0 6px 20px 0 rgb(0 0 0 / 19%); } .select__option--selected { - background: rgba($primary-color, 0.25); + background: rgba(var(--primary-color), 0.25); } .select__option--highlight { - background: $primary-color; + background: var(--primary-color); + text-shadow: 0 0 15px #000; } -.form-input[type="file"] { - overflow: hidden; +.form-input { + &[type="file"] { + overflow: hidden; + } + &:focus { + border-color: var(--primary-color); + box-shadow: 0 0 0 0.1rem var(--primary-color-shadow); + } } .input-group .input-group-addon { @@ -370,13 +404,34 @@ option:checked { } .btn { + color: var(--primary-color); + border-color: var(--primary-color); + + &:not(.btn-link) { + text-shadow: 0 0 15px #000; + } + + &:hover { + border-color: var(--primary-color-dark); + } + &:focus { - box-shadow: 0 0 3px 1px rgba($primary-color, 90%); + box-shadow: 0 0 3px 1px rgba(var(--primary-color), 90%); } &.btn-success:focus { - border-color: $primary-color; - box-shadow: 0 0 3px 1px rgba($primary-color, 90%); + border-color: var(--primary-color); + box-shadow: 0 0 3px 1px rgba(var(--primary-color), 90%); + } + + &.btn-primary { + background: var(--primary-color); + border-color: var(--primary-color-dark); + + &:hover { + background: var(--primary-color-dark); + border-color: var(--primary-color-dark); + } } } @@ -435,7 +490,7 @@ code.sql { } .sql-hl-keyword { - color: $primary-color; + color: var(--primary-color); } .sql-hl-function { @@ -456,4 +511,4 @@ code.sql { .sql-hl-bracket { color: darkorchid; -} \ No newline at end of file +} diff --git a/src/renderer/scss/themes/dark-theme.scss b/src/renderer/scss/themes/dark-theme.scss index 0826b659..19ff2055 100644 --- a/src/renderer/scss/themes/dark-theme.scss +++ b/src/renderer/scss/themes/dark-theme.scss @@ -33,12 +33,41 @@ .menu-item a { &:hover { - color: $primary-color; + color: var(--primary-color); background: $bg-color-gray; } } } + .tab { + .tab-item { + a { + color: $body-font-color-dark; + opacity: .7; + + &:hover { + color: $body-font-color-dark; + opacity: 1; + } + } + + &.active { + a { + color: $body-font-color-dark; + opacity: 1; + } + + .tab-link { + border-color: transparent; + } + + &::after { + width: 100%; + } + } + } + } + .btn { &.btn-link { color: rgba($body-font-color-dark, 0.8); @@ -67,7 +96,7 @@ } &.active { - background-color: $primary-color; + background-color: var(--primary-color); } } @@ -124,7 +153,7 @@ } .form-select:not([multiple], [size]):focus { - border-color: $primary-color; + border-color: var(--primary-color); } .select { @@ -432,7 +461,7 @@ .settingbar-element { .settingbar-element-icon { &.badge-update::after { - background: $primary-color; + background: var(--primary-color); } } } @@ -447,7 +476,7 @@ } #footer { - background: $primary-color; + background: var(--primary-color); box-shadow: 0 0 1px 0 #000; .footer-elements { diff --git a/src/renderer/stores/workspaces.ts b/src/renderer/stores/workspaces.ts index 63a0f25f..9a5f06c0 100644 --- a/src/renderer/stores/workspaces.ts +++ b/src/renderer/stores/workspaces.ts @@ -530,8 +530,17 @@ export const useWorkspacesStore = defineStore('workspaces', { return { ...workspace, tabs: workspace.tabs.map(tab => { - if (tab.uid === tUid) - return { ...tab, type, schema, content, elementName, elementType, filePath }; + if (tab.uid === tUid) { + return { + ...tab, + type, + schema, + content, + elementName, + elementType, + filePath + }; + } return tab; }) @@ -603,17 +612,47 @@ export const useWorkspacesStore = defineStore('workspaces', { }); tabUid = uidGen('T'); - this._addTab({ uid, tab: tabUid, content, type, autorun, database: workspaceTabs.database, schema, elementName, elementType, filePath }); + this._addTab({ + uid, + tab: tabUid, + content, + type, + autorun, + database: workspaceTabs.database, + schema, + elementName, + elementType, + filePath + }); } else { - this._replaceTab({ uid, tab: tab.uid, type, schema, elementName, elementType, filePath }); + this._replaceTab({ + uid, + tab: tab.uid, + type, + schema, + elementName, + elementType, + filePath + }); tabUid = tab.uid; } } } else { tabUid = uidGen('T'); - this._addTab({ uid, tab: tabUid, content, type, autorun, database: workspaceTabs.database, schema, elementName, elementType, filePath }); + this._addTab({ + uid, + tab: tabUid, + content, + type, + autorun, + database: workspaceTabs.database, + schema, + elementName, + elementType, + filePath + }); } } }