home: replace app list tiles with cards, logos and descriptions

This commit is contained in:
axolotle 2024-01-20 14:37:35 +01:00
parent 4ece760ab6
commit a5d83ce76b
4 changed files with 47 additions and 71 deletions

View file

@ -43,6 +43,9 @@ defineProps<{
@apply mb-4;
}
.intro h1 {
@apply text-6xl font-bold my-10 text-center;
}
.intro h2 {
@apply text-5xl font-bold my-10;
}

View file

@ -1,10 +1,12 @@
<script setup lang="ts">
withDefaults(
defineProps<{
tag?: string
text?: string
srOnly?: boolean
}>(),
{
tag: 'h1',
text: undefined,
srOnly: false,
},
@ -12,7 +14,8 @@ withDefaults(
</script>
<template>
<h1
<component
:tag="tag"
id="main-target"
tabindex="-1"
class="inline-block text-4xl font-bold"
@ -21,11 +24,11 @@ withDefaults(
<slot name="default">
{{ text }}
</slot>
</h1>
</component>
</template>
<style scoped>
h1 {
#main-target {
/* Need some override here because of `not-sr-only` styles */
margin-top: 2rem !important;
margin-bottom: 0.75rem !important;

View file

@ -81,13 +81,13 @@ export const useQueryMsg = () => useState<string | null>('queryMsg', () => null)
export interface Settings {
domain: string
public: boolean
portal_logo: string
portal_logo?: string
portal_theme: string
portal_title: string
portal_title?: string
show_other_domains_apps: 0 | 1
portal_user_intro: string
portal_public_intro: string
apps: Record<string, { label: string; url: string }>
apps: Record<string, { label: string; url: string, description?: Record<string, string>, logo?: string }>
}
const useSettingsState = () => useState<Settings>('settings')

View file

@ -21,60 +21,43 @@ const intro = computed(() => {
return isLoggedIn.value ? userIntro : isPublic ? publicIntro : null
})
const apps = computed(() => {
const appTileVariant = [
'btn-primary',
'btn-secondary',
'btn-accent',
'btn-neutral',
'btn-info',
'btn-success',
'btn-warning',
'btn-error',
// FIXME currently using daisyui btn colors to get focus/hover styles,
// if we want more colors we need to add btn variants based on daisyui colors.
// 'bg-red-500'
// 'bg-orange-500'
// 'bg-yellow-500'
// 'bg-lime-500'
// 'bg-green-500'
// 'bg-teal-500'
// 'bg-indigo-500'
// 'bg-primary',
// 'bg-purple-500'
// 'bg-rose-500'
]
return Object.entries(appsData.value).map(([id, app]) => {
return {
...app,
id,
url: '//' + app.url,
variant: appTileVariant[parseInt(app.label, 36) % appTileVariant.length],
}
})
const apps = Object.entries(appsData.value).map(([id, app]) => {
return {
...app,
url: '//' + app.url,
description: app.description[locale.value] || app.description.en
}
})
</script>
<template>
<div>
<PageTitle :text="$t('app_list')" sr-only />
<CustomText v-if="intro" :content="intro" />
<section id="apps" class="my-10">
<div v-if="!apps.length" class="w-2/3">
<section id="apps" class="my-16">
<PageTitle :text="t('app_list')" tag="h2" sr-only class="mb-4" />
<div v-if="!apps.length">
<em>{{ t('no_apps') }}</em>
</div>
<ul v-else class="tile-container">
<li v-for="app in apps" :key="app.id" class="tile relative">
<a :href="app.url" class="btn" :class="app.variant">
<span class="text-6xl font-extrabold" aria-hidden="true">
{{ app.label.substring(0, 2) }}
</span>
<span class="leading-tight">{{ app.label }}</span>
</a>
<ul v-else class="grid md:grid-cols-2 xl:grid-cols-3 gap-4">
<li
v-for="app in apps"
:key="app.label"
class="flex flex-auto border rounded p-4 relative hover:bg-neutral hover:text-neutral-content hover:border-neutral"
>
<img
v-if="app.logo"
aria-hidden="true"
:src="app.logo"
class="w-24 h-24 rounded me-4 bg-white"
/>
<div>
<h4 class="text-xl font-bold">
<a :href="app.url" class="">{{ app.label }}</a>
</h4>
<div v-if="app.description" v-html="app.description" />
</div>
</li>
</ul>
</section>
@ -82,25 +65,12 @@ const apps = computed(() => {
</template>
<style scoped>
.tile-container {
display: grid;
grid-template-columns: repeat(auto-fit, 9rem);
grid-auto-rows: 9rem;
grid-gap: 1.5rem;
}
.tile a {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
align-items: center;
justify-content: center;
gap: 0;
}
.tile:hover a,
.tile a:focus {
transform: scale(1.05);
.grid li a::after {
content: '';
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
}
</style>