Skip to content

Commit f84c835

Browse files
authored
Redesign Settings Page & Add Tooltips (#19)
1 parent 6ac1cd3 commit f84c835

16 files changed

+462
-211
lines changed

.eslintrc.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module.exports = {
55
'no-console': 'off',
66
'vue/attribute-hyphenation': 'off',
77
'vue/v-on-event-hyphenation': 'off',
8+
'@typescript-eslint/no-unused-vars': 'error',
89
'vue/custom-event-name-casing': 'off',
910
'vue/max-attributes-per-line': ['error', {
1011
singleline: {

src/assets/main.scss

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@
1010
--white-faded: rgb(190, 190, 190);
1111
--white: rgb(255, 255, 255);
1212
--content-bg: rgba(30, 30, 30, .8);
13+
--page-header-bg: rgba(43, 43, 43, .6);
1314
--popover-bg: rgba(40, 40, 40, .6);
15+
--popover-bg-solid: rgba(40, 40, 40);
1416
--bottom-bar-bg: rgba(21, 21, 21, 0.2);
1517
--sidebar-bg: rgba(50, 50, 50, .75);
1618
--app-border: rgb(90, 90, 90);
1719
--item-bg: rgba(80, 80, 80, .3);
1820
--item-hover-bg: rgba(80, 80, 80, .75);
1921
--item-border-color: rgb(22, 22, 22, .3);
22+
--accent-color: rgb(60, 175, 252);
2023
}
2124

2225
* {
@@ -68,9 +71,3 @@ button, a {
6871
@include borderRadiusOverflowHidden(8px);
6972
}
7073

71-
.icon:not(.no-stroke) {
72-
stroke: black;
73-
stroke-width: 1px;
74-
stroke-linejoin: round;
75-
paint-order: stroke;
76-
}

src/assets/mixins.scss

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
mask-image: -webkit-radial-gradient(white, black);
55
}
66

7-
@mixin text-outline($size: 1px) {
8-
text-shadow: 0 0 $size black, 0 0 $size black, 0 0 $size black, 0 0 $size black;
9-
}
107

118
@keyframes outline-anim {
129
0% {

src/components/AppButton.vue

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ interface Props {
33
loading?: boolean
44
paddingless?: boolean
55
square?: boolean
6+
ghost?: boolean
67
}
78
interface Emits {
89
(name: 'click', event: MouseEvent): void
@@ -31,6 +32,7 @@ function handleClick(e: MouseEvent) {
3132
'button-loading': loading,
3233
'button-paddingless': paddingless,
3334
'button-square': square,
35+
'button-ghost': ghost,
3436
}"
3537
@click="handleClick"
3638
>
@@ -53,15 +55,26 @@ function handleClick(e: MouseEvent) {
5355
height: 35px;
5456
font-size: 14px;
5557
padding: 8px 12px;
56-
border: 1px solid var(--item-border-color);
57-
background-color: var(--item-bg);
5858
position: relative;
5959
overflow: hidden;
6060
color: var(--white);
6161
border-radius: 8px;
62-
@include text-outline();
6362
vertical-align: middle;
6463
64+
&-content {
65+
display: flex;
66+
flex-direction: row;
67+
white-space: nowrap;
68+
align-items: center;
69+
justify-content: center;
70+
width: 100%;
71+
height: 100%;
72+
}
73+
74+
&:not(.button-ghost) {
75+
background-color: var(--item-bg);
76+
}
77+
6578
&-paddingless, &-square {
6679
padding: 0px;
6780
}
@@ -83,13 +96,9 @@ function handleClick(e: MouseEvent) {
8396
&:not(.button-loading) {
8497
@include focus-visible;
8598
86-
&:active {
99+
&:active, &:hover {
87100
background-color: var(--item-hover-bg);
88101
}
89-
90-
&:hover {
91-
border-color: var(--item-hover-bg);;
92-
}
93102
}
94103
}
95104

src/components/AppSidebar.vue

Lines changed: 80 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { Icons } from './Icons'
1010
import SidebarButton from './SidebarButton.vue'
1111
import Popover from './Popover.vue'
1212
import MenuItems, { menuItem } from './MenuItems.vue'
13+
import Tooltip from './Tooltip.vue'
14+
import SlotRef from './SlotRef.vue'
1315
1416
const store = useStore()
1517
@@ -44,60 +46,91 @@ const moreItems = computed(() => [
4446
<template>
4547
<nav class="nav">
4648
<div class="upper">
47-
<button
48-
class="nav-logo"
49-
@click="open(REPO_LINK)"
50-
>
51-
<img
52-
title="Go to Gitification repository"
53-
draggable="false"
54-
src="/src/assets/img/icon.png"
55-
>
56-
</button>
49+
<SlotRef>
50+
<template #default>
51+
<button
52+
class="nav-logo"
53+
@click="open(REPO_LINK)"
54+
>
55+
<img
56+
title="Go to Gitification repository"
57+
draggable="false"
58+
src="/src/assets/img/icon.png"
59+
>
60+
</button>
61+
</template>
62+
63+
<template #ref="{ el }">
64+
<Tooltip
65+
:target="el"
66+
position="right"
67+
text="Navigate to repository"
68+
/>
69+
</template>
70+
</SlotRef>
5771
</div>
72+
5873
<div class="lower">
59-
<SidebarButton
60-
v-if="store.newRelease != null"
61-
highlight
62-
title="An update is available"
63-
@click="open(`${REPO_RELEASES_LINK}/tag/${store.newRelease!.tag_name}`)"
64-
>
65-
<Icons.Download16 />
66-
</SidebarButton>
67-
68-
<SidebarButton
69-
:disabled="store.currentPage !== Page.Home"
70-
title="Reload notifications"
71-
@click="store.fetchNotifications(true)"
72-
>
73-
<Icons.Sync16 />
74-
</SidebarButton>
75-
76-
<!-- <SidebarButton
77-
:disabled="store.currentPage === Page.Settings"
78-
title="Go to settings"
79-
@click="store.setPage(Page.Settings)"
80-
>
81-
<Icons.Gear16 />
82-
</SidebarButton> -->
83-
84-
<Popover
85-
:wowerlayOptions="{
86-
position: 'right-end',
87-
noBackground: true,
88-
style: 'display: flex; flex-direction: column: flex-wrap: nowrap: gap: 5px; padding: 5px;',
89-
}"
90-
>
74+
<SlotRef v-if="store.newRelease != null">
9175
<template #default>
92-
<SidebarButton title="More">
76+
<SidebarButton
77+
highlight
78+
@click="open(`${REPO_RELEASES_LINK}/tag/${store.newRelease!.tag_name}`)"
79+
>
80+
<Icons.Download16 />
81+
</SidebarButton>
82+
</template>
83+
84+
<template #ref="{ el }">
85+
<Tooltip
86+
:target="el"
87+
position="right"
88+
text="A new version is available"
89+
/>
90+
</template>
91+
</SlotRef>
92+
93+
<SlotRef>
94+
<template #default>
95+
<SidebarButton
96+
:disabled="store.currentPage !== Page.Home"
97+
@click="store.fetchNotifications(true)"
98+
>
99+
<Icons.Sync16 />
100+
</SidebarButton>
101+
</template>
102+
103+
<template #ref="{ el }">
104+
<Tooltip
105+
:target="el"
106+
position="right"
107+
text="Reload notifications"
108+
/>
109+
</template>
110+
</SlotRef>
111+
112+
<SlotRef>
113+
<template #default>
114+
<SidebarButton>
93115
<Icons.More />
94116
</SidebarButton>
95117
</template>
96118

97-
<template #content>
98-
<MenuItems :items="moreItems" />
119+
<template #ref="{ el }">
120+
<Tooltip
121+
position="right"
122+
:target="el"
123+
text="More"
124+
/>
125+
126+
<Popover
127+
:target="el"
128+
:wowerlayOptions="{ position: 'right-end' }"
129+
>
130+
<MenuItems :items="moreItems" />
131+
</Popover>
99132
</template>
100-
</Popover>
133+
</SlotRef>
101134
</div>
102135
</nav>
103136
</template>
@@ -134,10 +167,10 @@ const moreItems = computed(() => [
134167
.nav-logo {
135168
opacity: .8;
136169
@include focus-visible;
137-
border:1px solid black;
138170
border-radius: 50%;
139171
width: 30px;
140172
height: 30px;
173+
overflow: hidden;
141174
142175
img {
143176
border-radius: 50%;

src/components/Icons.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import GithubIcon from 'virtual:icons/octicon/mark-github-16'
1111
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'
14+
import CheckIcon16 from 'virtual:icons/octicon/check-16'
1415
import CheckFillIcon from 'virtual:icons/octicon/check-circle-fill-12'
1516
import XIcon from 'virtual:icons/octicon/x-16'
1617
import BellIcon from 'virtual:icons/octicon/bell-24'
@@ -61,4 +62,5 @@ export const Icons = {
6162
Command: markRaw(CommandIcon),
6263
BellSlash: markRaw(BellSlashIcon),
6364
Info16: markRaw(InfoIcon16),
65+
Check16: markRaw(CheckIcon16),
6466
}

src/components/MenuItems.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<script lang="ts">
2-
import { type Context, Item, type ItemRenderList, SelectableItems, createItemDefaults, item } from 'vue-selectable-items'
2+
import {
3+
type Context,
4+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
5+
type Item,
6+
type ItemRenderList, SelectableItems, createItemDefaults, item,
7+
} from 'vue-selectable-items'
38
import { useKey } from '../composables/useKey'
49
import { type Icons } from './Icons'
510
import { usePopoverContext } from './Popover.vue'
@@ -61,10 +66,7 @@ const setupHandle = (ctx: Context) => {
6166
>
6267
<template #render="{ meta }: Item<ItemMeta>">
6368
<div class="item-icon">
64-
<component
65-
:is="meta!.icon"
66-
class="no-stroke"
67-
/>
69+
<component :is="meta!.icon" />
6870
</div>
6971
<div class="item-text">
7072
{{ meta!.text }}

src/components/NotificationItem.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ function handleRepoClick(repo: MinimalRepository, event: MouseEvent | KeyboardEv
140140
141141
&-title {
142142
@include focus-visible;
143-
@include text-outline();
144143
border-radius: 8px;
145144
padding: 5px 10px 5px 16px;
146145
width: 100%;
@@ -191,7 +190,6 @@ function handleRepoClick(repo: MinimalRepository, event: MouseEvent | KeyboardEv
191190
text-align: left;
192191
line-height: 20px;
193192
@include focus-visible;
194-
@include text-outline($size: 1px);
195193
margin-top: 5px;
196194
197195
&-read {

src/components/Popover.vue

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import { type InjectionKey, type Ref, inject, provide, ref, watch } from 'vue'
33
import { Wowerlay, type WowerlayTransitionFn } from 'wowerlay'
4-
import { useSlotWithRef } from '../composables/useSlotWithRef'
4+
import { useEventListener } from '@vueuse/core'
55
import { useKey } from '../composables/useKey'
66
77
interface PopoverContext {
@@ -25,12 +25,12 @@ const props = withDefaults(defineProps<Props>(), {
2525
})
2626
2727
defineSlots<{
28-
content: (props: SlotProps) => any
2928
default: (props: SlotProps) => any
3029
}>()
3130
3231
interface Props {
3332
wowerlayOptions?: Partial<Omit<InstanceType<typeof Wowerlay>['$props'], 'visible' | 'target'>>
33+
target?: HTMLElement | null
3434
}
3535
3636
const visible = ref(false)
@@ -80,35 +80,37 @@ watch(visible, (value) => {
8080
}
8181
})
8282
83-
const { renderSlot, element: target } = useSlotWithRef('default', {
84-
slotPropsGetter: () => ({ visible: visible.value }),
85-
})
83+
useEventListener(
84+
() => props.target,
85+
'click',
86+
() => {
87+
visible.value = !visible.value
88+
},
89+
{ passive: true },
90+
)
8691
</script>
8792

8893
<template>
89-
<Component
90-
:is="renderSlot"
91-
@click="visible = !visible"
92-
/>
93-
9494
<Wowerlay
9595
v-model:visible="visible"
96+
class="popover"
9697
tabindex="-1"
9798
:target="target"
9899
v-bind="props.wowerlayOptions"
99100
:gap="2"
101+
noBackground
100102
:transition="handleTransition"
101103
@update:el="(el) => popoverEl = el"
102104
>
103105
<slot
104-
name="content"
106+
name="default"
105107
:visible="visible"
106108
/>
107109
</Wowerlay>
108110
</template>
109111

110112
<style lang="scss">
111-
.wowerlay {
113+
.popover {
112114
outline: none;
113115
background-color: var(--popover-bg);
114116
min-width: 150px;
@@ -119,6 +121,7 @@ const { renderSlot, element: target } = useSlotWithRef('default', {
119121
display: flex;
120122
flex-direction: column;
121123
padding: 4px;
124+
--wowerlay-z: 1500;
122125
123126
> * + * {
124127
margin-top: 2px;

0 commit comments

Comments
 (0)