feat: production-harden app and finalize merge-ready UX/theme baseline

- complete tokenized theme preset system and admin style guide visibility
- refine dashboard layout/scroll behavior and shared async/request UI states
- add user nav-visibility settings across API, migration, and frontend stores
- harden security headers/CSP handling and related test coverage
- enforce CI repository hygiene + frontend contract/theme/build quality gates
- update docs/env references and make migration smoke test head-aware
This commit is contained in:
Justin Visser 2026-02-19 15:43:20 +01:00
parent ab1d29b203
commit ae2ca8f149
66 changed files with 5655 additions and 853 deletions

View file

@ -0,0 +1,67 @@
<script setup lang="ts">
import { computed, ref, watch } from "vue";
const props = withDefaults(
defineProps<{
label?: string | null;
scholarId: string;
imageUrl?: string | null;
size?: "sm" | "md";
}>(),
{
label: null,
imageUrl: null,
size: "md",
},
);
const imageFailed = ref(false);
watch(
() => props.imageUrl,
() => {
imageFailed.value = false;
},
);
const initials = computed(() => {
const source = (props.label || "").trim();
if (!source) {
return props.scholarId.slice(0, 2).toUpperCase();
}
const tokens = source.split(/\s+/).filter(Boolean);
if (tokens.length === 1) {
return tokens[0].slice(0, 2).toUpperCase();
}
return `${tokens[0].charAt(0)}${tokens[1].charAt(0)}`.toUpperCase();
});
const containerClass = computed(() =>
props.size === "sm" ? "h-10 w-10 text-[11px]" : "h-12 w-12 text-xs",
);
const canRenderImage = computed(() => Boolean(props.imageUrl) && !imageFailed.value);
function onImageError(): void {
imageFailed.value = true;
}
</script>
<template>
<div
class="flex shrink-0 items-center justify-center overflow-hidden rounded-full border border-stroke-default bg-surface-card-muted font-semibold text-ink-secondary"
:class="containerClass"
>
<img
v-if="canRenderImage"
:src="props.imageUrl || ''"
:alt="`${props.label || props.scholarId} profile image`"
class="h-full w-full object-cover"
loading="lazy"
referrerpolicy="no-referrer"
@error="onImageError"
/>
<span v-else>{{ initials }}</span>
</div>
</template>