Skip to content

Commit

Permalink
Dark mode (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eugeny authored Jul 1, 2022
1 parent 1e16c5f commit 6a9b965
Show file tree
Hide file tree
Showing 18 changed files with 296 additions and 72 deletions.
2 changes: 1 addition & 1 deletion warpgate-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@tsconfig/svelte": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^5.28.0",
"@typescript-eslint/parser": "^5.28.0",
"bootstrap": "^5.1.3",
"bootstrap": "^5.2.0-beta1",
"eslint": "^8.18.0",
"eslint-config-standard": "^16.0.3",
"eslint-import-resolver-typescript": "^2.7.1",
Expand Down
21 changes: 10 additions & 11 deletions warpgate-web/src/admin/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Router, { link } from 'svelte-spa-router'
import active from 'svelte-spa-router/active'
import { wrap } from 'svelte-spa-router/wrap'
import { Spinner } from 'sveltestrap'
import ThemeSwitcher from 'common/ThemeSwitcher.svelte'
async function init () {
await reloadServerInfo()
Expand Down Expand Up @@ -67,26 +68,29 @@ const routes = {
<a use:link use:active href="/log">Log</a>
{/if}
{#if $serverInfo?.username}
<div class="username">
<div class="username ms-auto">
{$serverInfo?.username}
</div>
<button class="btn btn-link" on:click={logout}>
<ThemeSwitcher />
<button class="btn btn-link" on:click={logout} title="Log out">
<Fa icon={faSignOut} fw />
</button>
{/if}
</header>
<main>
<Router {routes}/>
</main>
<footer>
{$serverInfo?.version}

<footer class="mt-5">
<span class="me-auto">
v{$serverInfo?.version}
</span>
<ThemeSwitcher />
</footer>
</div>
{/await}

<style lang="scss">
@import "../vars";
.app {
min-height: 100vh;
display: flex;
Expand All @@ -111,7 +115,6 @@ const routes = {
align-items: center;
padding: 10px 0;
margin: 10px 0 20px;
border-bottom: 1px solid rgba($body-color, .75);
a, .logo {
font-size: 1.5rem;
Expand All @@ -120,9 +123,5 @@ const routes = {
a:not(:first-child) {
margin-left: 15px;
}
.username {
margin-left: auto;
}
}
</style>
2 changes: 1 addition & 1 deletion warpgate-web/src/admin/LogViewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ onDestroy(() => {


<style lang="scss">
@import "../vars";
@import "../theme/vars.light";
.table-wrapper {
max-width: 100%;
Expand Down
3 changes: 2 additions & 1 deletion warpgate-web/src/admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
<link rel="icon" href="/assets/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Warpgate</title>
</head>
<style>#app { display: none }</style>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/admin/index.ts"></script>
Expand Down
3 changes: 1 addition & 2 deletions warpgate-web/src/admin/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import '@fontsource/work-sans'
import '../theme.scss'
import '../theme'
import App from './App.svelte'

new App({
Expand Down
37 changes: 37 additions & 0 deletions warpgate-web/src/common/ThemeSwitcher.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script lang="ts">
import Fa from 'svelte-fa'
import { faCloudSun, faMoon, faSun } from '@fortawesome/free-solid-svg-icons'
import { Button, Tooltip } from 'sveltestrap'
import { get } from 'svelte/store'
import { currentTheme, setCurrentTheme } from 'theme'
function toggle () {
if (get(currentTheme) === 'auto') {
setCurrentTheme('dark')
} else if (get(currentTheme) === 'dark') {
setCurrentTheme('light')
} else {
setCurrentTheme('auto')
}
}
</script>

<Button color="link" on:click={toggle} id="button" alt="Switch theme">
{#if $currentTheme === 'dark'}
<Fa fw icon={faMoon} />
{:else if $currentTheme === 'light'}
<Fa fw icon={faSun} />
{:else}
<Fa fw icon={faCloudSun} />
{/if}
</Button>
<Tooltip target="button" animation>
{#if $currentTheme === 'dark'}
Dark theme
{:else if $currentTheme === 'light'}
Light theme
{:else}
Automatic theme
{/if}
</Tooltip>
2 changes: 1 addition & 1 deletion warpgate-web/src/embed/EmbeddedUI.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ async function logout () {
border: 0;
border-radius: 4px;
color: #888;
color: rgba(0, 0, 0, .5);
&:not(:first-child) {
margin-top: 5px;
Expand Down
22 changes: 14 additions & 8 deletions warpgate-web/src/gateway/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Fa from 'svelte-fa'
import { api } from 'gateway/lib/api'
import { reloadServerInfo, serverInfo } from 'gateway/lib/store'
import logo from '../../public/assets/logo.svg'
import ThemeSwitcher from 'common/ThemeSwitcher.svelte'
import Login from './Login.svelte'
import TargetList from './TargetList.svelte'
Expand Down Expand Up @@ -42,21 +43,26 @@ init()

{#if $serverInfo?.username}
<div class="ms-auto">{$serverInfo.username}</div>
<button class="btn btn-link" on:click={logout}>
<button class="btn btn-link" on:click={logout} title="Log out">
<Fa icon={faSignOut} fw />
</button>
{/if}
</div>

{#if $serverInfo?.username}
<TargetList
<main>
{#if $serverInfo?.username}
<TargetList
on:navigation={() => redirecting = true} />
{:else}
<Login />
{/if}
{:else}
<Login />
{/if}
</main>

<footer class="mt-5">
{$serverInfo?.version}
<span class="me-auto">
v{$serverInfo?.version}
</span>
<ThemeSwitcher />
</footer>
{/if}
{:catch error}
Expand All @@ -71,7 +77,7 @@ init()
}
.logo {
width: 6rem;
width: 5rem;
margin: 0 -0.5rem;
}
</style>
9 changes: 6 additions & 3 deletions warpgate-web/src/gateway/TargetList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ init()
}}
>
<span class="me-auto">{target.name}</span>
{#if target.kind === TargetKind.Ssh}
<Badge color="success">SSH</Badge>
{:else}
<small class="protocol text-muted ms-auto">
{#if target.kind === TargetKind.Ssh}
SSH
{/if}
</small>
{#if target.kind === TargetKind.Http || target.kind === TargetKind.WebAdmin}
<Fa icon={faArrowRight} fw />
{/if}
</a>
Expand Down
1 change: 1 addition & 0 deletions warpgate-web/src/gateway/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<link rel="icon" href="/assets/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Warpgate</title>
<style>#app { display: none }</style>
</head>
<body>
<div id="app"></div>
Expand Down
3 changes: 1 addition & 2 deletions warpgate-web/src/gateway/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import '@fontsource/work-sans'
import '../theme.scss'
import '../theme'
import App from './App.svelte'

new App({
Expand Down
63 changes: 27 additions & 36 deletions warpgate-web/src/theme.scss → warpgate-web/src/theme/_theme.scss
Original file line number Diff line number Diff line change
@@ -1,36 +1,18 @@
@import "bootstrap/scss/functions";
// @import "bootstrap/scss/variables";
@import "./vars";

// $component-hover-bg: rgba(#fff, .05);
// $component-active-color: hsl(224deg 100% 78%);
// $component-active-bg: hsl(224deg 73% 21% / 52%);

// $list-group-bg: transparent;
// $list-group-color: #bbb;
// $list-group-hover-bg: $component-hover-bg;
// $list-group-action-hover-color: #fff;


// Configuration
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";

// Layout & components
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
// @import "bootstrap/scss/images";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
// @import "bootstrap/scss/grid";
// @import "bootstrap/scss/tables";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/transitions";
// @import "bootstrap/scss/dropdown";
// @import "bootstrap/scss/button-group";
@import "bootstrap/scss/nav";
@import "bootstrap/scss/navbar";
// @import "bootstrap/scss/nav";
// @import "bootstrap/scss/navbar";
// @import "bootstrap/scss/card";
// @import "bootstrap/scss/accordion";
// @import "bootstrap/scss/breadcrumb";
Expand All @@ -55,19 +37,11 @@
// Utilities
@import "bootstrap/scss/utilities/api";

$font-family-os: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;

// .list-group-flush > .list-group-item {
// border-radius: $border-radius;
// text-shadow: 0 0 1px black;
// }

a {
text-decoration-color: rgba($body-color, 0.25);
text-underline-offset: 2px;

&:hover, &.active {
text-decoration-color: $body-color;
}
#app {
display: block;
}

.page-summary-bar {
Expand All @@ -81,19 +55,36 @@ a {
}

.alert {
background: none !important;
border-top-style: none;
border-bottom-style: none;
border-right-style: none;
border-left-width: 2px;
font-style: italic;
padding: 0 10px;
margin: 20px 0;
background: rgba(0,0,0,.25) !important;
padding: 0.7rem 1rem;
margin: 1rem 0;
}

footer {
display: flex;
padding: 1rem 0;
align-items: center;
padding: .5rem 0;
margin: 2rem 0 1rem;
border-top: 1px solid rgba($body-color, .5);
}

input:-webkit-autofill {
-webkit-background-clip: text;
-webkit-box-shadow: 0 0 0 50px $input-bg inset;
-webkit-text-fill-color: $input-color;
}

input:-webkit-autofill:focus {
-webkit-background-clip: text;
-webkit-box-shadow: 0 0 0 50px $input-focus-bg inset;
-webkit-text-fill-color: $input-focus-color;
}

.badge {
font-family: $font-family-os;
}
49 changes: 49 additions & 0 deletions warpgate-web/src/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import '@fontsource/work-sans'

import { get, writable } from 'svelte/store'

type ThemeFileName = 'dark'|'light'
type ThemeName = ThemeFileName|'auto'

const savedTheme = (localStorage.getItem('theme') ?? 'auto') as ThemeName
export const currentTheme = writable(savedTheme)

const styleElement = document.createElement('style')
document.head.appendChild(styleElement)

function loadThemeFile (name: ThemeFileName) {
if (name === 'dark') {
return import('./theme.dark.scss?inline')
}
return import('./theme.light.scss?inline')
}

async function loadTheme (name: ThemeFileName) {
const theme = (await loadThemeFile(name)).default
styleElement.innerHTML = theme
}


window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
if (get(currentTheme) === 'auto') {
loadTheme(event.matches ? 'dark' : 'light')
}
})


export function setCurrentTheme (theme: ThemeName): void {
localStorage.setItem('theme', theme)
currentTheme.set(theme)
if (theme === 'auto') {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (window.matchMedia?.('(prefers-color-scheme: dark)').matches) {
loadTheme('dark')
} else {
loadTheme('light')
}
} else {
loadTheme(theme)
}
}

setCurrentTheme(savedTheme)
Loading

0 comments on commit 6a9b965

Please sign in to comment.