WIP: feat: route modals everywhere #2735

Closed
dpschen wants to merge 15 commits from dpschen/frontend:feature/route-modals-everywhere into main
3 changed files with 120 additions and 9 deletions
Showing only changes of commit 7b59f14465 - Show all commits

View File

@ -31,6 +31,7 @@
"@types/lodash.clonedeep": "4.5.7",
"@types/sortablejs": "1.15.0",
"@vueuse/core": "9.6.0",
"@vueuse/integrations": "9.6.0",
"@vueuse/router": "9.6.0",
"axios": "0.27.2",
"blurhash": "2.0.4",
@ -45,6 +46,7 @@
"flatpickr": "4.6.13",
"flexsearch": "0.7.21",
"floating-vue": "2.0.0-beta.20",
"focus-trap": "^7.1.0",
"highlight.js": "11.6.0",
"is-touch-device": "1.0.1",
"lodash.clonedeep": "4.5.0",

View File

@ -33,6 +33,7 @@ specifiers:
'@vue/test-utils': 2.2.4
'@vue/tsconfig': 0.1.3
'@vueuse/core': 9.6.0
'@vueuse/integrations': 9.6.0
'@vueuse/router': 9.6.0
autoprefixer: 10.4.13
axios: 0.27.2
@ -56,6 +57,7 @@ specifiers:
flatpickr: 4.6.13
flexsearch: 0.7.21
floating-vue: 2.0.0-beta.20
focus-trap: ^7.1.0
happy-dom: 7.7.0
highlight.js: 11.6.0
is-touch-device: 1.0.1
@ -104,6 +106,7 @@ dependencies:
'@types/lodash.clonedeep': 4.5.7
'@types/sortablejs': 1.15.0
'@vueuse/core': 9.6.0_vue@3.2.45
'@vueuse/integrations': 9.6.0_v6so3rexzmt44vm4rsvyznwkka
'@vueuse/router': 9.6.0_xsxatmlnmmg5bcuv3xdnj6fj7y
axios: 0.27.2
blurhash: 2.0.4
@ -118,6 +121,7 @@ dependencies:
flatpickr: 4.6.13
flexsearch: 0.7.21
floating-vue: 2.0.0-beta.20_vue@3.2.45
focus-trap: 7.1.0
highlight.js: 11.6.0
is-touch-device: 1.0.1
lodash.clonedeep: 4.5.0
@ -3236,13 +3240,18 @@ packages:
- supports-color
dev: true
/@typescript-eslint/types/5.43.0:
resolution: {integrity: sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@typescript-eslint/types/5.44.0:
resolution: {integrity: sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@typescript-eslint/typescript-estree/5.44.0_mmt6grxdx77rvjuvebzbfquz6y:
resolution: {integrity: sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==}
/@typescript-eslint/typescript-estree/5.43.0_mmt6grxdx77rvjuvebzbfquz6y:
resolution: {integrity: sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
@ -3250,8 +3259,8 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 5.44.0
'@typescript-eslint/visitor-keys': 5.44.0
'@typescript-eslint/types': 5.43.0
'@typescript-eslint/visitor-keys': 5.43.0
debug: 4.3.4_supports-color@9.2.1
globby: 11.1.0
is-glob: 4.0.3
@ -3262,6 +3271,27 @@ packages:
- supports-color
dev: true
/@typescript-eslint/typescript-estree/5.43.0_typescript@4.9.3:
resolution: {integrity: sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 5.43.0
'@typescript-eslint/visitor-keys': 5.43.0
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.7
tsutils: 3.21.0_typescript@4.9.3
typescript: 4.9.3
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/typescript-estree/5.44.0_typescript@4.9.3:
resolution: {integrity: sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -3303,6 +3333,14 @@ packages:
- typescript
dev: true
/@typescript-eslint/visitor-keys/5.43.0:
resolution: {integrity: sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.43.0
eslint-visitor-keys: 3.3.0
dev: true
/@typescript-eslint/visitor-keys/5.44.0:
resolution: {integrity: sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -3661,6 +3699,54 @@ packages:
- vue
dev: false
/@vueuse/integrations/9.6.0_v6so3rexzmt44vm4rsvyznwkka:
resolution: {integrity: sha512-+rs2OWY/3spxoAGQMnlHQpxf8ErAYf4D1bT0aXaPnxphmtYgexm6KIjTFpBbcQnHwVi1g2ET1SJoQL16yDrgWA==}
peerDependencies:
async-validator: '*'
axios: '*'
change-case: '*'
drauu: '*'
focus-trap: '*'
fuse.js: '*'
idb-keyval: '*'
jwt-decode: '*'
nprogress: '*'
qrcode: '*'
universal-cookie: '*'
peerDependenciesMeta:
async-validator:
optional: true
axios:
optional: true
change-case:
optional: true
drauu:
optional: true
focus-trap:
optional: true
fuse.js:
optional: true
idb-keyval:
optional: true
jwt-decode:
optional: true
nprogress:
optional: true
qrcode:
optional: true
universal-cookie:
optional: true
dependencies:
'@vueuse/core': 9.6.0_vue@3.2.45
'@vueuse/shared': 9.6.0_vue@3.2.45
axios: 0.27.2
focus-trap: 7.1.0
vue-demi: 0.12.1_vue@3.2.45
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: false
/@vueuse/metadata/9.6.0:
resolution: {integrity: sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w==}
dev: false
@ -5775,7 +5861,7 @@ packages:
resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==}
engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0}
dependencies:
'@typescript-eslint/typescript-estree': 5.44.0_typescript@4.9.3
'@typescript-eslint/typescript-estree': 5.43.0_typescript@4.9.3
ast-module-types: 3.0.0
node-source-walk: 5.0.0
typescript: 4.9.3
@ -5787,7 +5873,7 @@ packages:
resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==}
engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0}
dependencies:
'@typescript-eslint/typescript-estree': 5.44.0_mmt6grxdx77rvjuvebzbfquz6y
'@typescript-eslint/typescript-estree': 5.43.0_mmt6grxdx77rvjuvebzbfquz6y
ast-module-types: 3.0.0
node-source-walk: 5.0.0
typescript: 4.9.3
@ -7008,6 +7094,12 @@ packages:
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
dev: true
/focus-trap/7.1.0:
resolution: {integrity: sha512-CuJvwUBfJCWcU6fc4xr3UwMF5vWnox4isXAixCwrPzCsPKOQjP9T+nTlYT2t+vOmQL8MOQ16eim99XhjQHAuiQ==}
dependencies:
tabbable: 6.0.1
dev: false
/folder-walker/3.2.0:
resolution: {integrity: sha512-VjAQdSLsl6AkpZNyrQJfO7BXLo4chnStqb055bumZMbRUPpVuPN3a4ktsnRCmrFZjtMlYLkyXiR5rAs4WOpC4Q==}
dependencies:
@ -12255,6 +12347,10 @@ packages:
resolution: {integrity: sha512-P3cgh2bpaPvAO2NE3uRp/n6hmk4xPX4DQf+UzTlCAycssKdqhp6hjw+ENWe+aUS7TogKRFtptMosTSFeC6R55g==}
dev: true
/tabbable/6.0.1:
resolution: {integrity: sha512-SYJSIgeyXW7EuX1ytdneO5e8jip42oHWg9xl/o3oTYhmXusZVgiA+VlPvjIN+kHii9v90AmzTZEBcsEvuAY+TA==}
dev: false
/tabtab/3.0.2:
resolution: {integrity: sha512-jANKmUe0sIQc/zTALTBy186PoM/k6aPrh3A7p6AaAfF6WPSbTx1JYeGIGH162btpH+mmVEXln+UxwViZHO2Jhg==}
dependencies:
@ -12968,7 +13064,7 @@ packages:
dev: true
/verror/1.10.0:
resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
resolution: {integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=}
engines: {'0': node >=0.6.0}
dependencies:
assert-plus: 1.0.0

View File

@ -9,6 +9,7 @@
{ 'has-overflow': overflow },
variant,
]"
ref="modal"
v-bind="$attrs"
>
<div
@ -69,8 +70,10 @@ export default {
</script>
<script lang="ts" setup>
import {watchEffect} from 'vue'
import {ref, watchEffect} from 'vue'
import {useScrollLock} from '@vueuse/core'
import {useFocusTrap} from '@vueuse/integrations/useFocusTrap'
import type {RouteLocationRaw} from 'vue-router'
import CustomTransition from '@/components/misc/CustomTransition.vue'
import BaseButton from '@/components/base/BaseButton.vue'
@ -81,6 +84,7 @@ const props = withDefaults(defineProps<{
wide?: boolean,
transitionName?: 'modal' | 'fade',
variant?: 'default' | 'hint-modal' | 'scrolling',
closeRoute?: RouteLocationRaw,
}>(), {
enabled: true,
transitionName: 'modal',
@ -90,11 +94,20 @@ const props = withDefaults(defineProps<{
const emit = defineEmits(['close', 'submit'])
const scrollLock = useScrollLock(document.body)
watchEffect(() => {
scrollLock.value = props.enabled
})

FIXME: either we use an implicit attrs.onClose or we explicit define a close emit. Both should not be mixed.

FIXME: either we use an implicit `attrs.onClose` or we explicit define a `close` emit. Both should not be mixed.
const modal = ref(null)
const {activate, deactivate} = useFocusTrap(modal)
watchEffect(() => {
if (props.enabled) {
activate()
} else {
deactivate()
}
})
function onClose() {
emit('close')
}