Skip to content
Open
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
"@vue/apollo-composable": "^4.0.0-alpha.18",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.1.1",
"@vueuse/core": "^9.2.0",
"@vueuse/head": "^0.7.9",
"@vueuse/integrations": "^9.2.0",
"apollo-link-context": "^1.0.20",
"crypto-hash": "^2.0.1",
"date-fns": "^2.29.1",
"dompurify": "^2.3.12",
"focus-trap": "^7.0.0",
"graphql": "^16.5.0",
"marked": "^4.0.19",
"no-darkreader": "^1.0.3",
Expand Down
50 changes: 50 additions & 0 deletions src/components/base/UnstyledButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<template>
<button class="unstyled">
<slot />
</button>
</template>

<script lang="ts" setup></script>

<style lang="scss">
/* See https://github.com/necolas/normalize.css/blob/fc091cce1534909334c1911709a39c22d406977b/normalize.css#L155-L223 */
button.unstyled {
/* Change the font styles in all browsers. */
font-family: inherit;
font-size: 100%;
line-height: 1.15;

/* Remove the margin in Firefox and Safari. */
margin: 0;

/* Show the overflow in IE. */
overflow: visible;

/* Remove the inheritance of text transform in Edge, Firefox, and IE. */
text-transform: none;

/* Correct the inability to style clickable types in iOS and Safari. */
-webkit-appearance: button;

/* Remove border */
border: none;

/* Show pointer on hover */
cursor: pointer;

/* Use same color and text-align as parent */
color: inherit;
text-align: inherit;
}

button.unstyled::-moz-focus-inner {
/* Remove the inner border and padding in Firefox. */
border-style: none;
padding: 0;
}

button.unstyled:-moz-focusring {
/* Restore the focus styles unset by the previous rule. */
outline: 1px dotted ButtonText;
}
</style>
3 changes: 2 additions & 1 deletion src/components/form/Checkbox.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<label ref="checkbox" class="checkbox" :class="{ disabled }">
<input type="checkbox" :checked="checked" @change="onInput" />
<input type="checkbox" :checked="checked" :tabindex="skipTab ? -1 : null" @change="onInput" />
<span class="checkmark">
<Icon class="check-icon" icon="check" />
</span>
Expand All @@ -16,6 +16,7 @@ const props = defineProps({
label: String,
checked: Boolean,
disabled: Boolean,
skipTab: Boolean,
scale: {
type: String,
default: "1.25em",
Expand Down
9 changes: 8 additions & 1 deletion src/components/form/Radio.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<template>
<label ref="radio" class="radio">
<input type="radio" :checked="itemID == modelValue" :value="itemID" @change="onInput" />
<input
type="radio"
:checked="itemID == modelValue"
:value="itemID"
:tabindex="skipTab ? -1 : null"
@change="onInput"
/>
<div class="circle"></div>
<span>{{ label }}</span>
</label>
Expand All @@ -16,6 +22,7 @@ const props = defineProps({
required: true,
},
modelValue: String,
skipTab: Boolean,
scale: {
type: String,
default: "1.25em",
Expand Down
10 changes: 8 additions & 2 deletions src/components/modal/ModalBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<div class="modal-heading">
<div />
<slot name="heading" />
<div class="modal-close" @click="close()">
<UnstyledButton class="modal-close" @click="close()">
<Icon icon="close" />
</div>
</UnstyledButton>
</div>

<div class="modal-content">
Expand All @@ -24,7 +24,9 @@
import { onMounted, ref } from "vue";
import { onClickOutside } from "@vueuse/core";
import { ModalEvent, useModal } from "@store/modal";
import UnstyledButton from "@base/UnstyledButton.vue";
import Icon from "../utility/Icon.vue";
import { useFocusTrap } from "@vueuse/integrations/useFocusTrap";

const props = withDefaults(
defineProps<{
Expand Down Expand Up @@ -142,6 +144,10 @@ const close = () => {
}
@include themify() {
background-color: themed("warning");

&:focus-visible {
background-color: darken(themed("warning"), 14);
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/components/modal/ModalViewport.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
:key="k"
:animate="{ scale: [0, 0.5, 1], transition: { duration: 0.15 } }"
class="modal-state"
role="dialog"
aria-modal="true"
:aria-labelledby="(m.name ?? 'dialog') + '-title'"
:modal-name="k"
>
<Transition appear name="zoom">
Expand Down
52 changes: 38 additions & 14 deletions src/components/modal/SelectEmoteSet/SelectEmoteSet.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
<template>
<ModalBase width="32em" @close="shouldClose">
<template #heading>
<h3>{{ t("emote_set.select") }}</h3>
<h3 id="emote-set-select-at-card-title">{{ t("emote_set.select") }}</h3>
</template>

<template #content>
<div class="emote-set-selector">
<div class="available-sets">
<div v-for="set of editableEmoteSets.values()" :key="set.id" class="card">
<!-- Set Details (name, owner) -->
<div
<UnstyledButton
v-wave="{ duration: 0.3 }"
:selected="selection.has(set.id)"
:error="notes.get(set.id)"
selector="card-details"
:title="t('emote.use')"
@contextmenu="defaultEmoteSetID = set.id"
@click="toggleSet(set.id, true)"
>
Expand Down Expand Up @@ -60,33 +61,44 @@
<Checkbox
v-if="!isAssignMode && emote && (selection.has(set.id) || !notes.get(set.id))"
:checked="selection.has(set.id)"
skip-tab
/>
<Radio
v-else-if="isAssignMode"
v-model="defaultEmoteSetID"
:item-i-d="set.id"
skip-tab
/>
<Radio v-else-if="isAssignMode" v-model="defaultEmoteSetID" :item-i-d="set.id" />
</div>
</div>
</UnstyledButton>

<!-- Rename emote Button -->
<div
<UnstyledButton
selector="card-actions"
:title="t('emote_set.modal.context_rename')"
@click="(ev) => [(contextMenu.mode = 'rename'), (contextMenu.set = set)]"
>
<Icon size="xl" icon="pen-field" />
</div>
</UnstyledButton>

<!-- Context Menu Button -->
<div selector="card-actions" @click="(ev) => openContext(ev, set)">
<UnstyledButton
:title="t('common.more')"
selector="card-actions"
@click="(ev) => openContext(ev, set)"
>
<Icon size="xl" icon="chevron-down" />
</div>
</UnstyledButton>
</div>

<!-- Create Set Card -->
<div class="card" @click="createSet">
<div selector="card-details">
<div class="card">
<UnstyledButton selector="card-details" @click="createSet">
<span selector="set-name">
<Icon size="lg" icon="hexagon-plus" :style="{ marginRight: '0.5em' }" />
<span> {{ t("emote_set.create") }} </span>
</span>
</div>
</UnstyledButton>
</div>
</div>
</div>
Expand Down Expand Up @@ -128,6 +140,7 @@ import ModalCreateEmoteSet from "@components/modal/ModalCreateEmoteSet.vue";
import SelectEmoteSetContext from "./SelectEmoteSetContext.vue";
import Icon from "@/components/utility/Icon.vue";
import Radio from "@/components/form/Radio.vue";
import UnstyledButton from "@base/UnstyledButton.vue";

const { t } = useI18n();

Expand Down Expand Up @@ -345,13 +358,14 @@ const onRename = (set: EmoteSet | null) => {

> .card {
display: flex;
cursor: pointer;
margin-top: 0.25em;
margin-bottom: 0.25em;

@include themify() {
> div[selector="card-details"] {
> button[selector="card-details"] {
background-color: darken(themed("backgroundColor"), 4);
transition: outline-color 100ms;
outline-color: transparent;

&[selected="true"] {
background-color: mix(themed("backgroundColor"), themed("primary"), 85%);
Expand All @@ -363,6 +377,10 @@ const onRename = (set: EmoteSet | null) => {
background-color: darken(themed("backgroundColor"), 8);
}

&:focus-visible {
outline: themed("primary") 2px solid;
}

> div > div[selector="set-name"] > div[selector="label-list"] {
> span[label] {
background-color: themed("backgroundColor");
Expand All @@ -381,11 +399,17 @@ const onRename = (set: EmoteSet | null) => {
}
}
}
> div[selector="card-actions"] {
> button[selector="card-actions"] {
display: flex;
align-items: center;
justify-content: center;
background-color: darken(themed("backgroundColor"), 4);
transition: outline-color 100ms;
outline-color: transparent;

&:focus-visible {
outline: themed("primary") 2px solid;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/components/utility/UserTag.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
class="user-tag unstyled-link"
:clickable="clickable"
:href="clickable && user?.id ? `/users/${user?.id}` : undefined"
:aria-disabled="!clickable"
@click.right="toggleCard"
@click="toggleCard"
>
Expand Down
49 changes: 35 additions & 14 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -651,30 +651,39 @@
dependencies:
vue-demi "^0.13.4"

"@vueuse/core@^9.1.1":
version "9.1.1"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.1.1.tgz#a5c09c33ccee58cfd53bc3ec2d5a0d304155529e"
integrity sha512-QfuaNWRDMQcCUwXylCyYhPC3ScS9Tiiz4J0chdwr3vOemBwRToSywq8MP+ZegKYFnbETzRY8G/5zC+ca30wrRQ==
"@vueuse/core@9.2.0", "@vueuse/core@^9.2.0":
version "9.2.0"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.2.0.tgz#58e3588b9bc5a69010aa9104b00056ee9ebff738"
integrity sha512-/MZ6qpz6uSyaXrtoeBWQzAKRG3N7CvfVWvQxiM3ei3Xe5ydOjjtVbo7lGl9p8dECV93j7W8s63A8H0kFLpLyxg==
dependencies:
"@types/web-bluetooth" "^0.0.15"
"@vueuse/metadata" "9.1.1"
"@vueuse/shared" "9.1.1"
"@vueuse/metadata" "9.2.0"
"@vueuse/shared" "9.2.0"
vue-demi "*"

"@vueuse/head@^0.7.9":
version "0.7.9"
resolved "https://registry.yarnpkg.com/@vueuse/head/-/head-0.7.9.tgz#888ab87667ab6dbe6edba10d176fa91c1b0ec021"
integrity sha512-5wnRiH2XIUSLLXJDLDDTcpvAg5QXgTIVZl46AU7to/T91KHsdBLHSE4WhRO7kP0jbkAhlxnx64E29cQtwBrMjg==

"@vueuse/metadata@9.1.1":
version "9.1.1"
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.1.1.tgz#b3fe4b97e62096f7566cd8eb107c503998b2c9a6"
integrity sha512-XZ2KtSW+85LLHB/IdGILPAtbIVHasPsAW7aqz3BRMzJdAQWRiM/FGa1OKBwLbXtUw/AmjKYFlZJo7eOFIBXRog==
"@vueuse/integrations@^9.2.0":
version "9.2.0"
resolved "https://registry.yarnpkg.com/@vueuse/integrations/-/integrations-9.2.0.tgz#fdc53f120ff124e173a9400e634cf5095646eba4"
integrity sha512-0NerkCPUUWnbEb0ZZaJyrO8YKPPClR9+aLLF8yBbG/XRsoEo7pcpVq8d+uMhfHrXABoUpKD+9FZ+Tz/aRb7yFg==
dependencies:
"@vueuse/core" "9.2.0"
"@vueuse/shared" "9.2.0"
vue-demi "*"

"@vueuse/shared@9.1.1":
version "9.1.1"
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.1.1.tgz#811f47629e281a19013ae6dcdf11ed3e1e91e023"
integrity sha512-c+IfcOYmHiHqoEa3ED1Tbpue5GHmoUmTp8PtO4YbczthtY155Rt6DmWhjxMLXBF1Bcidagxljmp/7xtAzEHXLw==
"@vueuse/metadata@9.2.0":
version "9.2.0"
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.2.0.tgz#6bf7c9c44b9f5ece405837226a0e04a997994458"
integrity sha512-exN4KE6iquxDCdt72BgEhb3tlOpECtD61AUdXnUqBTIUCl70x1Ar/QXo3bYcvxmdMS2/peQyfeTzBjRTpvL5xw==

"@vueuse/shared@9.2.0":
version "9.2.0"
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.2.0.tgz#7831051b2c1d01c3413c749468ee53a86024510e"
integrity sha512-NnRp/noSWuXW0dKhZK5D0YLrDi0nmZ18UeEgwXQq7Ul5TTP93lcNnKjrHtd68j2xFB/l59yPGFlCryL692bnrA==
dependencies:
vue-demi "*"

Expand Down Expand Up @@ -1558,6 +1567,13 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==

focus-trap@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-7.0.0.tgz#4e2cd9aab5b673e2cbad945c52bd232f6160c2cb"
integrity sha512-uT4Bl8TwU+5vVAx/DHil/1eVS54k9unqhK/vGy2KSh7esPmqgC0koAB9J2sJ+vtj8+vmiFyGk2unLkhNLQaxoA==
dependencies:
tabbable "^6.0.0"

fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
Expand Down Expand Up @@ -2939,6 +2955,11 @@ symbol-observable@^4.0.0:
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==

tabbable@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.0.0.tgz#7f95ea69134e9335979092ba63866fe67b521b01"
integrity sha512-SxhZErfHc3Yozz/HLAl/iPOxuIj8AtUw13NRewVOjFW7vbsqT1f3PuiHrPQbUkRcLNEgAedAv2DnjLtzynJXiw==

table@^6.8.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca"
Expand Down