diff --git a/tabby-core/src/services/themes.service.ts b/tabby-core/src/services/themes.service.ts index abf59ec2..0ed81fc5 100644 --- a/tabby-core/src/services/themes.service.ts +++ b/tabby-core/src/services/themes.service.ts @@ -29,44 +29,87 @@ export class ThemesService { private applyThemeVariables () { const theme = this.config.store.terminal.colorScheme + const isDark = Color(theme.background).luminosity() < Color(theme.foreground).luminosity() + + function more (some, factor) { + if (isDark) { + return Color(some).darken(factor) + } + return Color(some).lighten(factor) + } + + function less (some, factor) { + if (!isDark) { + return Color(some).darken(factor) + } + return Color(some).lighten(factor) + } + const background = this.config.store?.appearance.vibrancy ? 'rgba(255, 255, 255,.4)' : theme.background - const backgroundDark = this.config.store?.appearance.vibrancy ? 'rgba(255, 255, 255,.5)' : Color(theme.background).darken(0.25).string() + const backgroundMore = this.config.store?.appearance.vibrancy ? 'rgba(255, 255, 255,.5)' : more(theme.background, 0.25).string() const accentIndex = 4 - document.documentElement.style.setProperty('--bs-body-bg', background) - document.documentElement.style.setProperty('--bs-body-color', theme.foreground) - document.documentElement.style.setProperty('--bs-black', theme.colors[0]) - document.documentElement.style.setProperty('--bs-red', theme.colors[1]) - document.documentElement.style.setProperty('--bs-green', theme.colors[2]) - document.documentElement.style.setProperty('--bs-yellow', theme.colors[3]) - document.documentElement.style.setProperty('--bs-blue', theme.colors[4]) - document.documentElement.style.setProperty('--bs-purple', theme.colors[5]) - document.documentElement.style.setProperty('--bs-cyan', theme.colors[6]) - document.documentElement.style.setProperty('--bs-gray', theme.colors[7]) - document.documentElement.style.setProperty('--bs-gray-dark', theme.colors[8]) - // document.documentElement.style.setProperty('--bs-red', theme.colors[9]) - // document.documentElement.style.setProperty('--bs-green', theme.colors[10]) - // document.documentElement.style.setProperty('--bs-yellow', theme.colors[11]) - // document.documentElement.style.setProperty('--bs-blue', theme.colors[12]) - // document.documentElement.style.setProperty('--bs-purple', theme.colors[13]) - // document.documentElement.style.setProperty('--bs-cyan', theme.colors[14]) + const vars: Record = {} - document.documentElement.style.setProperty('--theme-fg-light', Color(theme.foreground).lighten(0.25).string()) - document.documentElement.style.setProperty('--theme-bg-dark', backgroundDark) - document.documentElement.style.setProperty('--theme-bg-darker', Color(backgroundDark).darken(0.25).string()) + vars['--bs-body-bg'] = background + vars['--bs-body-color'] = theme.foreground + vars['--bs-black'] = theme.colors[0] + vars['--bs-red'] = theme.colors[1] + vars['--bs-green'] = theme.colors[2] + vars['--bs-yellow'] = theme.colors[3] + vars['--bs-blue'] = theme.colors[4] + vars['--bs-purple'] = theme.colors[5] + vars['--bs-cyan'] = theme.colors[6] + vars['--bs-gray'] = theme.colors[7] + vars['--bs-gray-dark'] = theme.colors[8] + // vars['--bs-red'] = theme.colors[9] + // vars['--bs-green'] = theme.colors[10] + // vars['--bs-yellow'] = theme.colors[11] + // vars['--bs-blue'] = theme.colors[12] + // vars['--bs-purple'] = theme.colors[13] + // vars['--bs-cyan'] = theme.colors[14] - for (const [color, index] of Object.entries({ - primary: accentIndex, - secondary: 8, - warning: 3, - danger: 1, - success: 2, - dark: 0, - light: 15, - })) { - document.documentElement.style.setProperty(`--bs-${color}`, theme.colors[index]) - document.documentElement.style.setProperty(`--theme-${color}`, theme.colors[index]) - document.documentElement.style.setProperty(`--theme-${color}-dark`, Color(theme.colors[index]).darken(0.25).string()) - document.documentElement.style.setProperty(`--theme-${color}-darker`, Color(theme.colors[index]).darken(0.5).string()) + vars['--theme-fg-more-2'] = more(theme.foreground, 0.5).string() + vars['--theme-fg-more'] = more(theme.foreground, 0.25).string() + vars['--theme-fg'] = theme.foreground + vars['--theme-fg-less'] = less(theme.foreground, 0.25).string() + vars['--theme-fg-less-2'] = less(theme.foreground, 0.5).string() + + vars['--theme-bg-less-2'] = less(theme.background, 0.5).string() + vars['--theme-bg-less'] = less(theme.background, 0.25).string() + vars['--theme-bg'] = theme.background + vars['--theme-bg-more'] = backgroundMore + vars['--theme-bg-more-2'] = more(backgroundMore, 0.25).string() + + const themeColors = { + primary: theme.colors[accentIndex], + secondary: theme.colors[8], + tertiary: theme.colors[8], + warning: theme.colors[3], + danger: theme.colors[1], + success: theme.colors[2], + info: theme.colors[4], + dark: more(theme.background, 0.5).string(), + light: more(theme.foreground, 0.5).string(), + link: theme.colors[8], // for .btn-link + } + + for (const [key, color] of Object.entries(themeColors)) { + vars[`--bs-${key}-bg`] = more(color, 0.5).string() + vars[`--bs-${key}-color`] = less(color, 0.5).string() + vars[`--bs-${key}`] = color + vars[`--bs-${key}-rgb`] = Color(color).rgb().array().join(', ') + vars[`--theme-${key}-more-2`] = more(color, 1).string() + vars[`--theme-${key}-more`] = more(color, 0.5).string() + vars[`--theme-${key}`] = color + vars[`--theme-${key}-less`] = less(color, 0.25).string() + vars[`--theme-${key}-less-2`] = less(color, 0.75).string() + } + + const switchBackground = less(theme.colors[accentIndex], 0.25).string() + vars['--bs-form-switch-bg'] = `url("data:image/svg+xml,%3csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%27-4 -4 8 8%27%3e%3ccircle r=%273%27 fill=%27${switchBackground}%27/%3e%3c/svg%3e")` + + for (const [key, value] of Object.entries(vars)) { + document.documentElement.style.setProperty(key, value) } } diff --git a/tabby-core/src/theme.new.scss b/tabby-core/src/theme.new.scss index fdce8153..21285ed8 100644 --- a/tabby-core/src/theme.new.scss +++ b/tabby-core/src/theme.new.scss @@ -6,7 +6,7 @@ app-root { &> .content { .tab-bar { - background: var(--theme-bg-dark); + background: var(--theme-bg-more); .btn-tab-bar { background: transparent; @@ -144,8 +144,8 @@ $tab-border-radius: 5px; // $modal-content-bg: $content-bg-solid; // $modal-content-border-color: $body-bg; -// $modal-header-border-color: transparent; -// $modal-footer-border-color: transparent; +$modal-header-border-color: transparent; +$modal-footer-border-color: transparent; // $popover-bg: $body-bg; @@ -170,56 +170,61 @@ $tab-border-radius: 5px; @import '~bootstrap/scss/bootstrap.scss'; @import "./theme.vendor.scss"; +body { + --bs-border-color: var(--theme-bg-more-2); + --bs-form-control-bg: var(--theme-bg-more); + --bs-emphasis-color: var(--theme-fg-less-2); +} .list-group { - --bs-list-group-bg: var(--theme-bg-dark); - --bs-list-group-border-color: var(--theme-bg-darker); + --bs-list-group-bg: var(--theme-bg-more); + --bs-list-group-border-color: var(--theme-bg-more-2); --bs-list-group-border-width: 0; // --bs-list-group-item-padding-x: 1rem; // --bs-list-group-item-padding-y: 0.5rem; --bs-list-group-action-color: var(--bs-body-color); --bs-list-group-action-hover-color: var(--theme-fg); - --bs-list-group-action-hover-bg: var(--theme-bg-darker); + --bs-list-group-action-hover-bg: var(--theme-bg-more-2); --bs-list-group-action-active-color: var(--theme-fg); - --bs-list-group-action-active-bg: var(--theme-bg-darker); + --bs-list-group-action-active-bg: var(--theme-bg-more-2); --bs-list-group-disabled-color: var(--bs-secondary-color); --bs-list-group-disabled-bg: var(--bs-body-bg); - // --bs-list-group-active-color: #fff; - // --bs-list-group-active-bg: #0d6efd; + --bs-list-group-active-color: var(--bs-primary-color); + --bs-list-group-active-bg: var(--bs-primary-bg); // --bs-list-group-active-border-color: #0d6efd; } .nav { // scss-docs-start nav-css-vars - // --#{$prefix}nav-link-padding-x: #{$nav-link-padding-x}; - // --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y}; - // @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size); - // --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight}; - --#{$prefix}nav-link-color: var(--bs-body-color); - --#{$prefix}nav-link-hover-color: var(--theme-fg-light); - --#{$prefix}nav-link-disabled-color: var(--bs-gray); + // --bs-nav-link-padding-x: #{$nav-link-padding-x}; + // --bs-nav-link-padding-y: #{$nav-link-padding-y}; + // @include rfs($nav-link-font-size, --bs-nav-link-font-size); + // --bs-nav-link-font-weight: #{$nav-link-font-weight}; + --bs-nav-link-color: var(--bs-body-color); + --bs-nav-link-hover-color: var(--theme-fg-less-2); + --bs-nav-link-disabled-color: var(--bs-gray); // scss-docs-end nav-css-vars } .nav-tabs { // scss-docs-start nav-tabs-css-vars - --#{$prefix}nav-tabs-border-width: 2px; - --#{$prefix}nav-tabs-border-radius: 0; - --#{$prefix}nav-tabs-link-hover-border-color: var(--bs-body-bg); - --#{$prefix}nav-tabs-border-color: var(--bs-white); - --#{$prefix}nav-tabs-link-active-color: var(--bs-white); + --bs-nav-tabs-border-width: 2px; + --bs-nav-tabs-border-radius: 0; + --bs-nav-tabs-link-hover-border-color: var(--bs-body-bg); + --bs-nav-tabs-border-color: var(--theme-fg-less-2); + --bs-nav-tabs-link-active-color: var(--theme-fg-less-2); - --#{$prefix}nav-tabs-link-active-bg: transparent; - --#{$prefix}nav-tabs-link-active-border-color: transparent; + --bs-nav-tabs-link-active-bg: transparent; + --bs-nav-tabs-link-active-border-color: transparent; // scss-docs-end nav-tabs-css-vars } .nav-pills { // scss-docs-start nav-pills-css-vars - --#{$prefix}nav-pills-border-radius: #{$nav-pills-border-radius}; - --#{$prefix}nav-pills-link-active-color: var(--theme-light); - --#{$prefix}nav-pills-link-active-bg: var(--bs-primary); + --bs-nav-pills-border-radius: #{$nav-pills-border-radius}; + --bs-nav-pills-link-active-color: var(--theme-bg-more); + --bs-nav-pills-link-active-bg: var(--bs-primary); // scss-docs-end nav-pills-css-vars } @@ -258,6 +263,10 @@ $tab-border-radius: 5px; color: var(--bs-nav-tabs-link-active-color); border-color: var(--bs-nav-tabs-border-color); } + + .nav-item { + outline: none !important; + } } @@ -279,26 +288,32 @@ tab-body { --bs-btn-disabled-bg: var(--theme-#{$color}); --bs-btn-disabled-border-color: var(--theme-#{$color}); - --bs-btn-hover-border-color: var(--theme-#{$color}-dark); - --bs-btn-hover-bg: var(--theme-#{$color}-dark); + --bs-btn-hover-border-color: var(--theme-#{$color}-less); + --bs-btn-hover-bg: var(--theme-#{$color}-less); - --bs-btn-active-border-color: var(--theme-#{$color}-darker); - --bs-btn-active-bg: var(--theme-#{$color}-darker); + --bs-btn-active-border-color: var(--theme-#{$color}-less-2); + --bs-btn-active-bg: var(--theme-#{$color}-less-2); - - --bs-btn-color: #fff; - --bs-btn-hover-color: #fff; --bs-btn-focus-shadow-rgb: 130, 138, 145; - --bs-btn-active-color: #fff; --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); - --bs-btn-disabled-color: #fff; + + --bs-btn-color: var(--theme-#{$color}-more-2); + --bs-btn-hover-color: var(--theme-#{$color}-more-2); + --bs-btn-active-color: var(--theme-#{$color}-more-2); + --bs-btn-disabled-color: var(--theme-#{$color}-more-2); + } + + .alert-#{$color} { + --bs-alert-bg: var(--theme-#{$color}-more-2); + --bs-alert-border-color: var(--theme-#{$color}-more); + --bs-alert-color: var(--theme-#{$color}); } } multi-hotkey-input { .item { - background: var(--theme-bg-dark); + background: var(--theme-bg-more); border: 1px solid var(--bs-primary); border-radius: 3px; margin-right: 5px; @@ -328,13 +343,13 @@ multi-hotkey-input { } .add, .item .body, .item .remove { - &:hover { background: var(--theme-bg-dark); } - &:active { background: var(--theme-bg-darker); } + &:hover { background: var(--theme-bg-more); } + &:active { background: var(--theme-bg-more-2); } } .add:has(.duplicate), .item:has(.duplicate) .body, .item:has(.duplicate) .remove { - &:hover { background: var(--theme-danger-dark); } - &:active { background: var(--theme-danger-darker); } + &:hover { background: var(--theme-danger-less); } + &:active { background: var(--theme-danger-less-2); } } } @@ -347,7 +362,7 @@ hotkey-input-modal { height: 55px; .stroke { - background: var(--theme-bg-dark); + background: var(--theme-bg-more); border: 1px solid var(--bs-primary); border-radius: 3px; margin-right: 10px; @@ -401,12 +416,6 @@ hotkey-input-modal { &:not(:last-child) { border-bottom: none; } - - &.list-group-item-action { - &:hover, &.active { - // background: $list-group-hover-bg; - } - } } .list-group-light { @@ -417,11 +426,8 @@ hotkey-input-modal { border-radius: $border-radius; margin: 0 !important; - &.list-group-item-action { - &:hover, &.active { - background: var(--bs-primary); - color: var(--bs-body-color); - } + &.active { + background-color: var(--bs-list-group-active-bg); } } } @@ -460,7 +466,7 @@ hotkey-input-modal { } search-panel { - background: var(--theme-bg-dark) !important; + background: var(--theme-bg-more) !important; input { border-radius: 0 !important; @@ -479,18 +485,18 @@ search-panel { } } -// .btn-link { -// text-decoration: none; +.btn-link { + text-decoration: none; -// &:hover, &[aria-expanded=true], &:active, &.active { -// color: $link-hover-color; -// border-radius: $btn-border-radius; -// } + // &:hover, &[aria-expanded=true], &:active, &.active { + // color: $link-hover-color; + // border-radius: $btn-border-radius; + // } -// &[aria-expanded=true], &:active, &.active { -// background: rgba(255, 255, 255, 0.1); -// } -// } + // &[aria-expanded=true], &:active, &.active { + // background: rgba(255, 255, 255, 0.1); + // } +} // .btn-group .btn.active { // border-color: transparent !important; @@ -518,6 +524,20 @@ ngx-colors-panel .opened { } .text-muted { - color: var(--bs-body-color) !important; + // color: var(--bs-body-color) !important; opacity: .5; } + +.form-switch .form-check-input { + --bs-form-switch-bg: inherit; +} + +.form-control:focus { + border-color: var(--theme-fg-more-2); +} + +.accordion { + --bs-accordion-bg: var(--theme-bg-more); + --bs-accordion-active-color: var(--theme-fg); + --bs-accordion-active-bg: var(--theme-bg-more-2); +} diff --git a/tabby-ssh/src/components/sftpPanel.component.pug b/tabby-ssh/src/components/sftpPanel.component.pug index 9f5ba6fa..57e96941 100644 --- a/tabby-ssh/src/components/sftpPanel.component.pug +++ b/tabby-ssh/src/components/sftpPanel.component.pug @@ -17,11 +17,11 @@ .breadcrumb-spacer.flex-grow-1.h-100((dblclick)='editPath()') - button.btn.btn-link.btn-sm.d-flex((click)='openCreateDirectoryModal()') + button.btn.btn-link.btn-sm.flex-shrink-0.d-flex((click)='openCreateDirectoryModal()') i.fas.fa-plus.me-1 div(translate) Create directory - button.btn.btn-link.btn-sm.d-flex((click)='upload()') + button.btn.btn-link.btn-sm.flex-shrink-0.d-flex((click)='upload()') i.fas.fa-upload.me-1 div(translate) Upload diff --git a/tabby-ssh/src/components/sshPortForwardingConfig.component.pug b/tabby-ssh/src/components/sshPortForwardingConfig.component.pug index 0da63628..0df81aeb 100644 --- a/tabby-ssh/src/components/sshPortForwardingConfig.component.pug +++ b/tabby-ssh/src/components/sshPortForwardingConfig.component.pug @@ -1,7 +1,7 @@ .list-group.mb-3 .list-group-item.d-flex.align-items-center(*ngFor='let fw of model') div - .ms-2.d-flex.align-items-center + .d-flex.align-items-center strong(*ngIf='fw.type === PortForwardType.Local', translate) Local strong(*ngIf='fw.type === PortForwardType.Remote', translate) Remote strong(*ngIf='fw.type === PortForwardType.Dynamic', translate, translateContext='[Dynamic] port forwarding') id.port-forwarding.dynamic diff --git a/tabby-terminal/src/components/colorPicker.component.scss b/tabby-terminal/src/components/colorPicker.component.scss index 1b0ddf7f..c7c57838 100644 --- a/tabby-terminal/src/components/colorPicker.component.scss +++ b/tabby-terminal/src/components/colorPicker.component.scss @@ -1,3 +1,7 @@ +:host { + display: inline-block; +} + div { width: 32px; height: 32px;