Skip to content

Commit ed76ac2

Browse files
authored
Add light mode support & Redesign Settings (#33)
1 parent 0de4aa3 commit ed76ac2

18 files changed

+417
-147
lines changed

index.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
<body>
1010
<div id="app"></div>
11-
<!-- Using border on html or body does not look good because of vibrancy -->
12-
<div id="app-border"></div>
1311
<script type="module" src="/src/main.ts"></script>
1412
</body>
1513
</html>

src/App.vue

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<script setup lang="ts">
2+
import { watchEffect } from 'vue'
23
import AppContent from './components/AppContent.vue'
34
import AppSidebar from './components/AppSidebar.vue'
45
import HomePage from './pages/HomePage.vue'
56
import SettingsPage from './pages/SettingsPage.vue'
6-
import { FETCH_INTERVAL_DURATION, Page } from './constants'
7+
import { ColorPreference, FETCH_INTERVAL_DURATION, Page, prefersDark } from './constants'
78
import { useStore } from './stores/store'
89
import LandingPage from './pages/LandingPage.vue'
910
import { useInterval } from './composables/useInterval'
@@ -15,9 +16,31 @@ useInterval(() => {
1516
if (AppStorage.get('accessToken') && AppStorage.get('user'))
1617
store.fetchNotifications()
1718
}, FETCH_INTERVAL_DURATION)
19+
20+
watchEffect(() => {
21+
const preference = AppStorage.get('colorPreference')
22+
23+
let theme: ColorPreference.Dark | ColorPreference.Light
24+
25+
if (preference === ColorPreference.Dark)
26+
theme = ColorPreference.Dark
27+
else if (preference === ColorPreference.Light)
28+
theme = ColorPreference.Light
29+
else
30+
theme = prefersDark.value ? ColorPreference.Dark : ColorPreference.Light
31+
32+
if (theme === ColorPreference.Dark)
33+
document.documentElement.classList.remove('light-theme')
34+
else
35+
document.documentElement.classList.add('light-theme')
36+
})
1837
</script>
1938

2039
<template>
40+
<Teleport to="body">
41+
<div id="app-border" />
42+
</Teleport>
43+
2144
<AppSidebar />
2245

2346
<AppContent>

src/assets/main.scss

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,44 @@
77
-webkit-text-size-adjust: 100%;
88
line-height: 20px;
99

10-
--white-faded: rgb(190, 190, 190);
11-
--white: rgb(255, 255, 255);
10+
--text-faded: rgb(190, 190, 190);
11+
--text: rgb(255, 255, 255);
1212
--gray-bright: rgb(150, 150, 150);
13+
--switch-dot: rgb(200, 200, 200);
1314
--gray: rgb(95, 95, 95);
15+
--switch-bg: var(--gray);
1416
--content-bg: rgba(30, 30, 30, .8);
1517
--page-header-bg: rgba(43, 43, 43, .6);
16-
--popover-bg: rgba(40, 40, 40, .6);
18+
--popover-bg: rgba(20, 20, 20, .6);
1719
--popover-bg-solid: rgba(40, 40, 40);
1820
--bottom-bar-bg: rgba(21, 21, 21, 0.2);
1921
--sidebar-bg: rgba(50, 50, 50, .75);
2022
--app-border: rgb(90, 90, 90);
2123
--item-bg: rgba(80, 80, 80, .3);
2224
--item-hover-bg: rgba(80, 80, 80, .75);
2325
--item-border-color: rgb(22, 22, 22, .3);
24-
--accent-color: rgb(60, 175, 252);
26+
--accent-color: rgb(23, 115, 243);
27+
--header-border: rgb(50, 50, 50);
28+
29+
&.light-theme {
30+
--text-faded: rgb(20, 20, 20);
31+
--text: rgb(0, 0, 0);
32+
--gray-bright: rgb(105, 105, 105);
33+
--gray: rgb(160, 160, 160);
34+
--switch-bg: rgb(145, 145, 145);
35+
--switch-dot: rgb(60, 60, 60);
36+
--content-bg: rgba(220, 220, 220, .75);
37+
--page-header-bg: rgba(212, 212, 212, .6);
38+
--popover-bg: rgba(210, 210, 210, .8);
39+
--popover-bg-solid: rgba(215, 215, 215);
40+
--bottom-bar-bg: rgba(234, 234, 234, 0.2);
41+
--sidebar-bg: rgba(240, 240, 240, .6);
42+
--app-border: rgb(185, 185, 185);
43+
--item-bg: rgba(255, 255, 255, .3);
44+
--item-hover-bg: rgba(150, 150, 150, .7);
45+
--item-border-color: rgb(180, 180, 180, .7);
46+
--popover-border: rgb(167, 167, 167);
47+
}
2548
}
2649

2750
* {
@@ -63,6 +86,7 @@ button, a {
6386
}
6487

6588
#app-border {
89+
z-index: 9999;
6690
pointer-events: none;
6791
position: fixed;
6892
left: 0;

src/components/AppButton.vue

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ const props = withDefaults(defineProps<Props>(), {
1616
})
1717
const emit = defineEmits<Emits>()
1818
19+
defineSlots<{
20+
default: (props: {}) => any
21+
icon: (props: {}) => any
22+
}>()
23+
1924
function handleClick(e: MouseEvent) {
2025
if (props.loading)
2126
return
@@ -45,7 +50,11 @@ function handleClick(e: MouseEvent) {
4550
</div>
4651

4752
<div class="button-content">
48-
<slot />
53+
<slot name="default" />
54+
</div>
55+
56+
<div class="button-icon">
57+
<slot name="icon" />
4958
</div>
5059
</button>
5160
</template>
@@ -57,9 +66,20 @@ function handleClick(e: MouseEvent) {
5766
padding: 8px 12px;
5867
position: relative;
5968
overflow: hidden;
60-
color: var(--white);
69+
color: var(--text);
6170
border-radius: 8px;
62-
vertical-align: middle;
71+
72+
&,
73+
&-icon {
74+
vertical-align: middle;
75+
display: flex;
76+
align-items: center;
77+
}
78+
79+
&-icon :deep(.icon) {
80+
color: currentColor;
81+
margin-left: 5px;
82+
}
6383
6484
&-content {
6585
display: flex;
@@ -119,7 +139,7 @@ function handleClick(e: MouseEvent) {
119139
width: 10px;
120140
height: 10px;
121141
border-radius: 50%;
122-
background-color: var(--white);
142+
background-color: var(--text);
123143
position: relative;
124144
}
125145

src/components/EmptyState.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ withDefaults(defineProps<Props>(), {
6464
6565
&-icon {
6666
font-size: 30px;
67-
color: var(--white);
67+
color: var(--text);
6868
6969
&-wrapper {
7070
margin-bottom: 15px

src/components/Icons.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import UnmuteIcon from 'virtual:icons/octicon/unmute-24'
1212
import PullRequestIcon from 'virtual:icons/octicon/git-pull-request-24'
1313
import CheckIcon from 'virtual:icons/octicon/check-24'
1414
import CheckIcon16 from 'virtual:icons/octicon/check-16'
15-
import CheckFillIcon from 'virtual:icons/octicon/check-circle-fill-12'
15+
import CheckFillIcon from 'virtual:icons/octicon/check-circle-16'
1616
import XIcon from 'virtual:icons/octicon/x-16'
1717
import BellIcon from 'virtual:icons/octicon/bell-24'
1818
import BellIcon16 from 'virtual:icons/octicon/bell-16'
@@ -25,7 +25,8 @@ import QuestionIcon from 'virtual:icons/octicon/question-24'
2525
import InfoIcon16 from 'virtual:icons/octicon/info-16'
2626
import MailIcon from 'virtual:icons/octicon/mail-24'
2727
import SignOutIcon16 from 'virtual:icons/octicon/sign-out-16'
28-
import ChevronLeftIcon from 'virtual:icons/octicon/chevron-left'
28+
import ChevronLeftIcon from 'virtual:icons/octicon/chevron-left-24'
29+
import ChevronDownIcon from 'virtual:icons/octicon/chevron-down-24'
2930
import DownloadIcon16 from 'virtual:icons/octicon/download-16'
3031
import BellSlashIcon from 'virtual:icons/octicon/bell-slash-24'
3132
import BellSlashIcon16 from 'virtual:icons/octicon/bell-slash-16'
@@ -73,4 +74,5 @@ export const Icons = {
7374
LinkExternal16: markRaw(LinkExternalIcon16),
7475
Square16: markRaw(SquareIcon16),
7576
Circle: markRaw(CircleIcon24),
77+
ChevronDown: markRaw(ChevronDownIcon),
7678
}

src/components/MenuItems.vue

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,35 @@
22
import {
33
type Context,
44
type Item,
5-
type ItemRenderList, SelectableItems, createItemDefaults, item,
5+
type ItemRenderList, SelectableItems, createItemDefaults, filterSelectableItems, item,
66
} from 'vue-selectable-items'
7+
import { onMounted } from 'vue'
78
import { useKey } from '../composables/useKey'
89
import { type Icons } from './Icons'
910
import { usePopoverContext } from './Popover.vue'
1011
1112
export interface ItemMeta {
1213
text: string
13-
icon: typeof Icons[keyof typeof Icons]
14+
icon?: typeof Icons[keyof typeof Icons]
1415
key?: string
16+
selected?: boolean
1517
}
1618
1719
export const menuItem = item<ItemMeta>
1820
19-
const itemDefaults = createItemDefaults<ItemMeta>(({ disabled }) => ({
21+
const itemDefaults = createItemDefaults<ItemMeta>(({ disabled, meta }) => ({
2022
elementTag: 'button',
2123
elementAttrs: {
2224
tabindex: disabled ? -1 : 0,
2325
role: 'button',
2426
disabled: disabled || null,
27+
style: meta?.selected ? 'color: var(--accent-color); font-weight: bold;' : undefined,
2528
},
2629
}))
2730
</script>
2831

2932
<script lang="ts" setup>
30-
withDefaults(defineProps<{ items: ItemRenderList<ItemMeta> }>(), {
33+
const props = withDefaults(defineProps<{ items: ItemRenderList<ItemMeta> }>(), {
3134
items: () => [],
3235
})
3336
@@ -54,6 +57,17 @@ function setupHandle(ctx: Context) {
5457
ctx.onSelect((meta, item) => {
5558
popoverContext.visible.value = false
5659
})
60+
61+
onMounted(() => {
62+
const items = filterSelectableItems(props.items)
63+
64+
for (const item of items) {
65+
if (item.meta?.selected) {
66+
ctx.setFocusByKey(item.key)
67+
break
68+
}
69+
}
70+
})
5771
}
5872
</script>
5973

@@ -65,7 +79,10 @@ function setupHandle(ctx: Context) {
6579
noWrapperElement
6680
>
6781
<template #render="{ meta }: Item<ItemMeta>">
68-
<div class="item-icon">
82+
<div
83+
v-if="meta!.icon"
84+
class="item-icon"
85+
>
6986
<component :is="meta!.icon" />
7087
</div>
7188
<div class="item-text">
@@ -90,7 +107,7 @@ function setupHandle(ctx: Context) {
90107
outline: none;
91108
height: 32px;
92109
border-radius: 4px; // 8px parent border radius - 4px parent padding
93-
color: var(--white-faded);
110+
color: var(--text-faded);
94111
95112
&,
96113
.item-text,
@@ -102,7 +119,7 @@ function setupHandle(ctx: Context) {
102119
103120
&-focused {
104121
background-color: var(--item-bg);
105-
color: var(--white);
122+
color: var(--text);
106123
}
107124
108125
&-disabled {

src/components/NotificationItem.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ function handleRepoClick(repo: MinimalRepository, event: MouseEvent | KeyboardEv
176176
font-weight: bold;
177177
font-size: 14px;
178178
display: inline-block;
179-
color: var(--white);
179+
color: var(--text);
180180
white-space: nowrap;
181181
overflow: hidden;
182182
text-overflow: ellipsis;
@@ -194,7 +194,7 @@ function handleRepoClick(repo: MinimalRepository, event: MouseEvent | KeyboardEv
194194
padding: 8px 10px 8px 8px;
195195
align-items: center;
196196
border-radius: 8px;
197-
color: var(--white);
197+
color: var(--text);
198198
border: 1px solid var(--item-border-color);
199199
text-align: left;
200200
line-height: 20px;
@@ -207,7 +207,7 @@ function handleRepoClick(repo: MinimalRepository, event: MouseEvent | KeyboardEv
207207
}
208208
209209
&-read {
210-
color: var(--white-faded) !important;
210+
color: var(--gray-bright) !important;
211211
}
212212
213213
&:hover {
@@ -250,7 +250,7 @@ function handleRepoClick(repo: MinimalRepository, event: MouseEvent | KeyboardEv
250250
width: 16px;
251251
height: 16px;
252252
border-radius: 6px;
253-
border: 1px solid var(--white-faded);
253+
border: 1px solid var(--text-faded);
254254
flex-shrink: 0;
255255
padding: 3px;
256256
display: inline-flex;
@@ -286,10 +286,10 @@ function handleRepoClick(repo: MinimalRepository, event: MouseEvent | KeyboardEv
286286
287287
&:hover {
288288
.notification-checkbox:not(.notification-checkbox-checked) {
289-
border-color: var(--white-faded);
289+
border-color: var(--text-faded);
290290
291291
.notification-checkbox-dot {
292-
background-color: var(--white-faded);
292+
background-color: var(--text-faded);
293293
}
294294
}
295295
}

src/components/PageHeader.vue

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts" setup>
22
interface Props {
33
inline?: boolean
4+
dot?: boolean
45
}
56
67
withDefaults(defineProps<Props>(), {
@@ -13,14 +14,31 @@ withDefaults(defineProps<Props>(), {
1314
class="header"
1415
:class="{ 'header-inline': inline }"
1516
>
17+
<div
18+
v-if="dot"
19+
class="header-dot"
20+
/>
21+
1622
<slot />
1723
</header>
1824
</template>
1925

2026
<style lang="scss" scoped>
2127
.header {
2228
font-size: 16px;
23-
color: var(--white);
29+
color: var(--text);
30+
white-space: nowrap;
31+
display: flex;
32+
align-items: center;
33+
font-weight: bold;
34+
35+
&-dot {
36+
width: 6px;
37+
height: 6px;
38+
border-radius: 50%;
39+
background-color: currentColor;
40+
margin-right: 8px;
41+
}
2442
2543
&-inline {
2644
display: inline-block;

src/components/Popover.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,12 @@ useEventListener(
182182
.popover {
183183
outline: none;
184184
background-color: var(--popover-bg);
185-
min-width: 150px;
185+
min-width: 135px;
186186
border-radius: 8px;
187-
border: 1px solid #323232;
187+
border: 1px solid var(--popover-border);
188188
backdrop-filter: blur(20px) saturate(180%) contrast(90%) brightness(50%);
189189
-webkit-backdrop-filter: blur(20px) saturate(180%) contrast(90%) brightness(50%);
190+
box-shadow: 0px 0px 7px -3px rgba(0, 0, 0, 0.2);
190191
display: flex;
191192
flex-direction: column;
192193
padding: 4px;

0 commit comments

Comments
 (0)