mirror of
https://github.com/YunoHost/yunohost-portal.git
synced 2024-09-03 20:06:23 +02:00
home: replace app list tiles with cards, logos and descriptions
This commit is contained in:
parent
4ece760ab6
commit
a5d83ce76b
4 changed files with 47 additions and 71 deletions
|
@ -43,6 +43,9 @@ defineProps<{
|
||||||
@apply mb-4;
|
@apply mb-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.intro h1 {
|
||||||
|
@apply text-6xl font-bold my-10 text-center;
|
||||||
|
}
|
||||||
.intro h2 {
|
.intro h2 {
|
||||||
@apply text-5xl font-bold my-10;
|
@apply text-5xl font-bold my-10;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
tag?: string
|
||||||
text?: string
|
text?: string
|
||||||
srOnly?: boolean
|
srOnly?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
|
tag: 'h1',
|
||||||
text: undefined,
|
text: undefined,
|
||||||
srOnly: false,
|
srOnly: false,
|
||||||
},
|
},
|
||||||
|
@ -12,7 +14,8 @@ withDefaults(
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1
|
<component
|
||||||
|
:tag="tag"
|
||||||
id="main-target"
|
id="main-target"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
class="inline-block text-4xl font-bold"
|
class="inline-block text-4xl font-bold"
|
||||||
|
@ -21,11 +24,11 @@ withDefaults(
|
||||||
<slot name="default">
|
<slot name="default">
|
||||||
{{ text }}
|
{{ text }}
|
||||||
</slot>
|
</slot>
|
||||||
</h1>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
h1 {
|
#main-target {
|
||||||
/* Need some override here because of `not-sr-only` styles */
|
/* Need some override here because of `not-sr-only` styles */
|
||||||
margin-top: 2rem !important;
|
margin-top: 2rem !important;
|
||||||
margin-bottom: 0.75rem !important;
|
margin-bottom: 0.75rem !important;
|
||||||
|
|
|
@ -81,13 +81,13 @@ export const useQueryMsg = () => useState<string | null>('queryMsg', () => null)
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
domain: string
|
domain: string
|
||||||
public: boolean
|
public: boolean
|
||||||
portal_logo: string
|
portal_logo?: string
|
||||||
portal_theme: string
|
portal_theme: string
|
||||||
portal_title: string
|
portal_title?: string
|
||||||
show_other_domains_apps: 0 | 1
|
show_other_domains_apps: 0 | 1
|
||||||
portal_user_intro: string
|
portal_user_intro: string
|
||||||
portal_public_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')
|
const useSettingsState = () => useState<Settings>('settings')
|
||||||
|
|
100
pages/index.vue
100
pages/index.vue
|
@ -21,60 +21,43 @@ const intro = computed(() => {
|
||||||
return isLoggedIn.value ? userIntro : isPublic ? publicIntro : null
|
return isLoggedIn.value ? userIntro : isPublic ? publicIntro : null
|
||||||
})
|
})
|
||||||
|
|
||||||
const apps = computed(() => {
|
const apps = Object.entries(appsData.value).map(([id, app]) => {
|
||||||
const appTileVariant = [
|
return {
|
||||||
'btn-primary',
|
...app,
|
||||||
'btn-secondary',
|
url: '//' + app.url,
|
||||||
'btn-accent',
|
description: app.description[locale.value] || app.description.en
|
||||||
'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],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<PageTitle :text="$t('app_list')" sr-only />
|
|
||||||
|
|
||||||
<CustomText v-if="intro" :content="intro" />
|
<CustomText v-if="intro" :content="intro" />
|
||||||
|
|
||||||
<section id="apps" class="my-10">
|
<section id="apps" class="my-16">
|
||||||
<div v-if="!apps.length" class="w-2/3">
|
<PageTitle :text="t('app_list')" tag="h2" sr-only class="mb-4" />
|
||||||
|
|
||||||
|
<div v-if="!apps.length">
|
||||||
<em>{{ t('no_apps') }}</em>
|
<em>{{ t('no_apps') }}</em>
|
||||||
</div>
|
</div>
|
||||||
|
<ul v-else class="grid md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||||
<ul v-else class="tile-container">
|
<li
|
||||||
<li v-for="app in apps" :key="app.id" class="tile relative">
|
v-for="app in apps"
|
||||||
<a :href="app.url" class="btn" :class="app.variant">
|
:key="app.label"
|
||||||
<span class="text-6xl font-extrabold" aria-hidden="true">
|
class="flex flex-auto border rounded p-4 relative hover:bg-neutral hover:text-neutral-content hover:border-neutral"
|
||||||
{{ app.label.substring(0, 2) }}
|
>
|
||||||
</span>
|
<img
|
||||||
<span class="leading-tight">{{ app.label }}</span>
|
v-if="app.logo"
|
||||||
</a>
|
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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
@ -82,25 +65,12 @@ const apps = computed(() => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.tile-container {
|
.grid li a::after {
|
||||||
display: grid;
|
content: '';
|
||||||
grid-template-columns: repeat(auto-fit, 9rem);
|
position: absolute;
|
||||||
grid-auto-rows: 9rem;
|
top: 0px;
|
||||||
grid-gap: 1.5rem;
|
left: 0px;
|
||||||
}
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue