refactor: modal styles & content scrollable

This commit is contained in:
Zack Spear
2024-01-29 18:12:35 -08:00
committed by Zack Spear
parent f36f4702a2
commit 3ab406e012
4 changed files with 75 additions and 36 deletions

View File

@@ -4,6 +4,7 @@ import { XMarkIcon } from '@heroicons/vue/24/outline';
import useFocusTrap from '~/composables/useFocusTrap';
export interface Props {
centerContent?: boolean;
description?: string;
error?: boolean;
maxWidth?: string;
@@ -11,15 +12,18 @@ export interface Props {
showCloseX?: boolean;
success?: boolean;
t: any;
tallContent?: boolean;
title?: string;
}
const props = withDefaults(defineProps<Props>(), {
centerContent: true,
description: '',
error: false,
maxWidth: 'sm:max-w-lg',
open: false,
showCloseX: false,
success: false,
tallContent: false,
title: '',
});
watchEffect(() => {
@@ -54,23 +58,29 @@ const ariaLablledById = computed((): string|undefined => props.title ? `ModalTit
tabindex="-1"
@keyup.esc="closeModal"
>
<TransitionChild
appear
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0"
enter-to="opacity-100"
leave="duration-200 ease-in"
leave-from="opacity-100"
leave-to="opacity-0"
<div
class="fixed inset-0 flex min-h-screen w-screen justify-center p-16px sm:p-0 overflow-y-auto"
:class="{
'items-start tall:items-center': tallContent,
'items-center': !tallContent,
}"
>
<div
class="fixed inset-0 z-0 bg-black bg-opacity-80 transition-opacity"
:title="t('Click to close modal')"
@click="closeModal"
/>
</TransitionChild>
<div class="text-center flex min-h-full items-center justify-center p-4 md:p-0">
<TransitionChild
appear
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0"
enter-to="opacity-100"
leave="duration-200 ease-in"
leave-from="opacity-100"
leave-to="opacity-0"
>
<div
class="fixed inset-0 z-0 bg-black bg-opacity-80 transition-opacity"
:title="t('Click to close modal')"
@click="closeModal"
/>
</TransitionChild>
<TransitionChild
appear
as="template"
@@ -88,33 +98,50 @@ const ariaLablledById = computed((): string|undefined => props.title ? `ModalTit
success ? 'shadow-green-600/30 border-green-600/10' : '',
!error && !success ? 'shadow-orange/10 border-white/10' : '',
]"
class="text-16px text-beta bg-alpha text-left relative flex flex-col justify-around p-16px my-24px sm:p-24px border-2 border-solid shadow-xl transform overflow-hidden rounded-lg transition-all sm:w-full"
class="text-16px text-beta bg-alpha text-left relative z-10 flex flex-col justify-around mx-8px md:mx-16px border-2 border-solid shadow-xl transform overflow-hidden rounded-lg transition-all sm:w-full"
>
<div v-if="showCloseX" class="absolute z-20 right-0 top-0 hidden pt-2 pr-2 sm:block">
<button type="button" class="rounded-md text-beta bg-alpha p-2 hover:text-white focus:text-white hover:bg-unraid-red focus:bg-unraid-red focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" @click="closeModal">
<div v-if="showCloseX" class="absolute z-20 right-0 top-0 hidden sm:block">
<button
class="rounded-md text-beta bg-transparent p-2 hover:text-white focus:text-white hover:bg-unraid-red focus:bg-unraid-red focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
type="button"
@click="closeModal"
>
<span class="sr-only">{{ t('Close') }}</span>
<XMarkIcon class="h-6 w-6" aria-hidden="true" />
</button>
</div>
<header
class="text-center"
class="relative z-0 grid items-start gap-2 p-16px sm:p-24px rounded-t"
:class="{
'mb-16px sm:mb-24px': !$slots['main']
'mb-16px sm:mb-24px': !$slots['main'],
'pr-40px': showCloseX,
'justify-between': $slots['header'],
'justify-center': !$slots['header'],
}"
>
<div class="absolute -z-10 inset-0 opacity-10 bg-beta" />
<template v-if="!$slots['header']">
<h1 v-if="title" :id="ariaLablledById" class="text-24px font-semibold flex flex-wrap justify-center gap-x-1">
<h1 v-if="title" :id="ariaLablledById" class="text-center text-24px font-semibold flex flex-wrap justify-center gap-x-4px">
{{ title }}
<slot name="headerTitle" />
</h1>
<h2 v-if="description" class="text-20px opacity-75" v-html="description" />
</template>
<slot name="header" />
</header>
<slot name="main" />
<footer v-if="$slots['footer']" class="text-14px relative -mx-16px -mb-16px sm:-mx-24px sm:-mb-24px p-4 sm:p-6">
<div
v-if="$slots['main'] || description"
class="relative max-h-[65vh] tall:max-h-[75vh] flex flex-col gap-y-16px sm:gap-y-24px p-16px sm:p-24px overflow-y-auto shadow-inner"
:class="centerContent && 'text-center'"
>
<h2 v-if="description" class="text-20px opacity-75" v-html="description" />
<div v-if="$slots['main']">
<slot name="main" />
</div>
</div>
<footer v-if="$slots['footer']" class="text-14px relative p-16px sm:p-24px">
<div class="absolute z-0 inset-0 opacity-10 bg-beta" />
<div class="relative z-10">
<slot name="footer" />

View File

@@ -1,5 +1,12 @@
<script setup lang="ts">
import { ArrowTopRightOnSquareIcon, ArrowSmallRightIcon, KeyIcon, ServerStackIcon, XMarkIcon } from '@heroicons/vue/24/solid';
import {
ArrowTopRightOnSquareIcon,
ArrowSmallRightIcon,
EyeIcon,
KeyIcon,
ServerStackIcon,
XMarkIcon,
} from '@heroicons/vue/24/solid';
import { storeToRefs } from 'pinia';
import { computed } from 'vue';
@@ -72,11 +79,14 @@ watchEffect(() => {
<template>
<Modal
:center-content="false"
:error="!!parseChangelogFailed"
:open="!!releaseForUpdate"
:title="parsedChangelogTitle ?? undefined"
max-width="max-w-800px"
:open="!!releaseForUpdate"
:show-close-x="true"
:t="t"
:tall-content="true"
:title="parsedChangelogTitle ?? undefined"
@close="updateOsChangelogStore.setReleaseForUpdate(null)"
>
<template #main>
@@ -120,19 +130,20 @@ watchEffect(() => {
</template>
<template #footer>
<div class="flex flex-col gap-3 sm:gap-4 sm:flex-row sm:justify-between">
<div class="flex flex-col-reverse gap-3 sm:gap-4 sm:flex-row sm:justify-between">
<div>
<BrandButton
v-if="showExternalChangelogLink"
:href="releaseForUpdate?.changelog"
btn-style="underline"
:external="true"
:href="releaseForUpdate?.changelog"
:icon="EyeIcon"
:icon-right="ArrowTopRightOnSquareIcon"
>
{{ props.t("View Docs") }}
</BrandButton>
</div>
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4 sm:justify-end">
<div class="flex flex-col-reverse sm:flex-row gap-3 sm:gap-4 sm:justify-end">
<BrandButton
btn-style="underline-hover-red"
:icon="XMarkIcon"

View File

@@ -176,15 +176,15 @@ onBeforeMount(() => {
:open="open"
:title="modalCopy?.title"
:description="modalCopy?.description"
:show-close-x="true"
:show-close-x="!checkForUpdatesLoading"
max-width="max-w-640px"
@close="close"
>
<template v-if="renderMainSlot" #main>
<BrandLoading v-if="checkForUpdatesLoading" class="w-[150px] mx-auto my-24px" />
<div v-else-if="available || availableWithRenewal" class="mx-auto my-24px">
<BrandLoading v-if="checkForUpdatesLoading" class="w-[150px] mx-auto" />
<div v-else-if="available || availableWithRenewal" class="mx-auto">
<SwitchGroup>
<div class="flex items-center gap-8px p-8px rounded">
<div class="flex justify-center items-center gap-8px p-8px rounded">
<Switch
v-model="ignoreThisRelease"
:class="ignoreThisRelease ? 'bg-gradient-to-r from-unraid-red to-orange' : 'bg-transparent'"
@@ -200,7 +200,7 @@ onBeforeMount(() => {
</div>
</SwitchGroup>
</div>
<div v-else-if="updateOsIgnoredReleases.length > 0" class="w-full flex flex-col gap-8px my-24px">
<div v-else-if="updateOsIgnoredReleases.length > 0" class="w-full flex flex-col gap-8px">
<h3 class="text-16px font-semibold italic">
{{ t('Ignored Releases') }}
</h3>

View File

@@ -103,6 +103,7 @@ export default <Partial<Config>>{
screens: {
'2xs': '470px',
xs: '530px',
tall: { raw: '(min-height: 700px)' },
},
/**
* @todo modify prose classes to use pixels for webgui…sadge https://tailwindcss.com/docs/typography-plugin#customizing-the-default-theme