Skip to content

Commit d048e95

Browse files
committed
feat: enhance dialog and user profile components for improved styling and functionality
- Updated DialogContent.vue to simplify animation classes for fullscreen modals, enhancing visual consistency. - Added pre-render CSS in standalone-mount.ts to prevent FOUC by hiding components until they are fully mounted. - Refactored ServerStatus.vue to streamline class bindings for better readability. - Improved UptimeExpire.vue by adding dynamic styling based on props and optimizing computed properties for clarity.
1 parent 3c165b0 commit d048e95

4 files changed

Lines changed: 85 additions & 16 deletions

File tree

unraid-ui/src/components/ui/dialog/DialogContent.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ const { teleportTarget } = useTeleport();
4141
:class="
4242
cn(
4343
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 border-muted fixed top-1/2 left-1/2 z-50 flex w-full max-w-lg -translate-x-1/2 -translate-y-1/2 flex-col gap-4 rounded-lg border p-6 shadow-lg duration-200',
44-
// Only apply zoom and slide animations if not fullscreen
44+
// Only apply zoom animation if not fullscreen
4545
!props.class?.includes('min-h-screen') &&
46-
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
46+
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
4747
// Apply slide-up animation for fullscreen modals
4848
props.class?.includes('min-h-screen') &&
4949
'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',

web/components/UserProfile/ServerStatus.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import UpcServerState from './ServerState.vue';
88
<div
99
:class="
1010
cn(
11-
'text-header-text-secondary text-right font-semibold leading-tight',
11+
'text-header-text-secondary font-semibold leading-tight',
1212
'flex flex-col items-end gap-y-0.5 justify-end',
1313
'xs:flex-row xs:items-baseline xs:gap-x-2 xs:gap-y-0',
1414
'text-xs',

web/components/UserProfile/UptimeExpire.vue

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script setup lang="ts">
22
import { computed } from 'vue';
3-
import { storeToRefs } from 'pinia';
43
import { useI18n } from 'vue-i18n';
4+
import { storeToRefs } from 'pinia';
55
66
import useDateTimeHelper from '~/composables/dateTime';
77
import { useServerStore } from '~/store/server';
@@ -23,11 +23,22 @@ const { t } = useI18n();
2323
const serverStore = useServerStore();
2424
const { dateTimeFormat, uptime, expireTime, state } = storeToRefs(serverStore);
2525
26+
const style = computed(() => {
27+
if (props.as === 'span') {
28+
return {
29+
'text-align': 'right',
30+
};
31+
}
32+
return {};
33+
});
34+
2635
const time = computed(() => {
2736
if (props.forExpire && expireTime.value) {
2837
return expireTime.value;
2938
}
30-
return (state.value === 'TRIAL' || state.value === 'EEXPIRED') && expireTime.value && expireTime.value > 0
39+
return (state.value === 'TRIAL' || state.value === 'EEXPIRED') &&
40+
expireTime.value &&
41+
expireTime.value > 0
3142
? expireTime.value
3243
: uptime.value;
3344
});
@@ -39,20 +50,20 @@ const countUp = computed<boolean>(() => {
3950
return state.value !== 'TRIAL' && state.value !== 'ENOCONN';
4051
});
4152
42-
const {
43-
outputDateTimeReadableDiff: readableDiff,
44-
outputDateTimeFormatted: formatted,
45-
} = useDateTimeHelper(dateTimeFormat.value, t, false, time.value, countUp.value);
53+
const { outputDateTimeReadableDiff: readableDiff, outputDateTimeFormatted: formatted } =
54+
useDateTimeHelper(dateTimeFormat.value, t, false, time.value, countUp.value);
4655
4756
const output = computed(() => {
4857
if (!countUp.value || state.value === 'EEXPIRED') {
4958
return {
50-
title: state.value === 'EEXPIRED'
51-
? t(props.shortText ? 'Expired at {0}' : 'Trial Key Expired at {0}', [formatted.value])
52-
: t(props.shortText ? 'Expires at {0}' : 'Trial Key Expires at {0}', [formatted.value]),
53-
text: state.value === 'EEXPIRED'
54-
? t(props.shortText ? 'Expired {0}' : 'Trial Key Expired {0}', [readableDiff.value])
55-
: t(props.shortText ? 'Expires in {0}' : 'Trial Key Expires in {0}', [readableDiff.value]),
59+
title:
60+
state.value === 'EEXPIRED'
61+
? t(props.shortText ? 'Expired at {0}' : 'Trial Key Expired at {0}', [formatted.value])
62+
: t(props.shortText ? 'Expires at {0}' : 'Trial Key Expires at {0}', [formatted.value]),
63+
text:
64+
state.value === 'EEXPIRED'
65+
? t(props.shortText ? 'Expired {0}' : 'Trial Key Expired {0}', [readableDiff.value])
66+
: t(props.shortText ? 'Expires in {0}' : 'Trial Key Expires in {0}', [readableDiff.value]),
5667
};
5768
}
5869
return {
@@ -63,7 +74,7 @@ const output = computed(() => {
6374
</script>
6475

6576
<template>
66-
<component :is="as" :title="output.title">
77+
<component :is="as" :title="output.title" :style="style">
6778
{{ output.text }}
6879
</component>
6980
</template>

web/components/standalone-mount.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,66 @@ declare global {
3636
}
3737
}
3838

39+
// Add pre-render CSS to hide components until they're mounted
40+
function injectPreRenderCSS() {
41+
const style = document.createElement('style');
42+
style.id = 'unraid-prerender-css';
43+
style.textContent = `
44+
/* Hide unraid components during initial load to prevent FOUC */
45+
unraid-auth,
46+
unraid-connect-settings,
47+
unraid-download-api-logs,
48+
unraid-header-os-version,
49+
unraid-modals,
50+
unraid-user-profile,
51+
unraid-update-os,
52+
unraid-downgrade-os,
53+
unraid-registration,
54+
unraid-wan-ip-check,
55+
unraid-welcome-modal,
56+
unraid-sso-button,
57+
unraid-log-viewer,
58+
unraid-theme-switcher,
59+
unraid-api-key-manager,
60+
unraid-dev-modal-test,
61+
unraid-api-key-authorize {
62+
opacity: 0;
63+
transition: opacity 0.2s ease-in-out;
64+
}
65+
66+
/* Show components once they have the unapi class (mounted) */
67+
unraid-auth.unapi,
68+
unraid-connect-settings.unapi,
69+
unraid-download-api-logs.unapi,
70+
unraid-header-os-version.unapi,
71+
unraid-modals.unapi,
72+
unraid-user-profile.unapi,
73+
unraid-update-os.unapi,
74+
unraid-downgrade-os.unapi,
75+
unraid-registration.unapi,
76+
unraid-wan-ip-check.unapi,
77+
unraid-welcome-modal.unapi,
78+
unraid-sso-button.unapi,
79+
unraid-log-viewer.unapi,
80+
unraid-theme-switcher.unapi,
81+
unraid-api-key-manager.unapi,
82+
unraid-dev-modal-test.unapi,
83+
unraid-api-key-authorize.unapi {
84+
opacity: 1;
85+
}
86+
`;
87+
document.head.appendChild(style);
88+
}
89+
3990
// Initialize global Apollo client context
4091
if (typeof window !== 'undefined') {
92+
// Inject pre-render CSS as early as possible
93+
if (document.readyState === 'loading') {
94+
document.addEventListener('DOMContentLoaded', injectPreRenderCSS);
95+
} else {
96+
injectPreRenderCSS();
97+
}
98+
4199
// Make Apollo client globally available
42100
window.apolloClient = apolloClient;
43101

0 commit comments

Comments
 (0)