2023-07-19 18:42:05 +02:00
|
|
|
<script setup lang="ts">
|
2023-09-07 18:13:09 +02:00
|
|
|
definePageMeta({
|
|
|
|
public: true,
|
|
|
|
})
|
|
|
|
|
2024-01-20 14:38:38 +01:00
|
|
|
const { t, locale } = useI18n()
|
2023-11-23 17:07:54 +01:00
|
|
|
const isLoggedIn = await useIsLoggedIn()
|
|
|
|
const settings = await useSettings()
|
2023-09-04 16:45:16 +02:00
|
|
|
const appsData = await useApps()
|
2023-07-19 18:42:05 +02:00
|
|
|
|
2023-09-07 18:13:09 +02:00
|
|
|
useHead({
|
2023-11-11 15:07:40 +01:00
|
|
|
title: t('app_list'),
|
2023-09-04 16:49:13 +02:00
|
|
|
})
|
|
|
|
|
2023-11-23 16:01:49 +01:00
|
|
|
const intro = computed(() => {
|
|
|
|
const {
|
|
|
|
portal_user_intro: userIntro,
|
|
|
|
portal_public_intro: publicIntro,
|
|
|
|
public: isPublic,
|
|
|
|
} = settings.value
|
|
|
|
return isLoggedIn.value ? userIntro : isPublic ? publicIntro : null
|
|
|
|
})
|
|
|
|
|
2024-02-09 15:28:40 +01:00
|
|
|
const apps = Object.values(appsData.value).map((app) => {
|
2024-01-20 14:37:35 +01:00
|
|
|
return {
|
|
|
|
...app,
|
|
|
|
url: '//' + app.url,
|
2024-02-09 15:28:40 +01:00
|
|
|
description: app.description?.[locale.value] || app.description?.en,
|
2024-01-20 14:37:35 +01:00
|
|
|
}
|
2023-07-20 17:36:08 +02:00
|
|
|
})
|
2024-01-20 14:38:38 +01:00
|
|
|
|
|
|
|
const search = ref('')
|
|
|
|
|
|
|
|
async function onSearchSubmit() {
|
2024-02-09 15:28:40 +01:00
|
|
|
await navigateTo(settings.value.search_engine + search.value, {
|
|
|
|
open: {
|
|
|
|
target: '_blank',
|
|
|
|
},
|
|
|
|
})
|
2024-01-20 14:38:38 +01:00
|
|
|
}
|
2023-07-19 18:42:05 +02:00
|
|
|
</script>
|
2023-07-12 04:52:58 +02:00
|
|
|
|
2023-07-19 18:42:05 +02:00
|
|
|
<template>
|
2023-08-06 16:27:24 +02:00
|
|
|
<div>
|
2023-11-23 16:01:49 +01:00
|
|
|
<CustomText v-if="intro" :content="intro" />
|
|
|
|
|
2024-01-28 15:39:48 +01:00
|
|
|
<form v-if="settings.search_engine" class="flex my-16" @submit.prevent>
|
2024-01-20 14:38:38 +01:00
|
|
|
<div class="join w-full max-w-xl mx-auto">
|
2024-02-09 15:28:40 +01:00
|
|
|
<!-- eslint-disable-next-line vuejs-accessibility/label-has-for -->
|
|
|
|
<label for="search" class="sr-only">
|
|
|
|
{{
|
|
|
|
t('search_engine_placeholder', {
|
|
|
|
engine: settings.search_engine_name,
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
</label>
|
2024-01-20 14:38:38 +01:00
|
|
|
<input
|
2024-02-09 15:28:40 +01:00
|
|
|
id="search"
|
2024-01-20 14:38:38 +01:00
|
|
|
v-model="search"
|
|
|
|
type="search"
|
|
|
|
class="input input-bordered join-item w-full"
|
|
|
|
name="search"
|
2024-02-09 15:28:40 +01:00
|
|
|
:placeholder="
|
|
|
|
t('search_engine_placeholder', {
|
|
|
|
engine: settings.search_engine_name,
|
|
|
|
})
|
|
|
|
"
|
|
|
|
/>
|
|
|
|
<button
|
|
|
|
type="submit"
|
|
|
|
class="btn btn-primary join-item px-2"
|
|
|
|
@click="onSearchSubmit"
|
2024-01-20 14:38:38 +01:00
|
|
|
>
|
|
|
|
<YIcon name="magnify" aria-hidden="true" class="m-0" />
|
|
|
|
<span class="sr-only">{{ t('search') }}</span>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
|
2024-01-20 14:37:35 +01:00
|
|
|
<section id="apps" class="my-16">
|
|
|
|
<PageTitle :text="t('app_list')" tag="h2" sr-only class="mb-4" />
|
|
|
|
|
|
|
|
<div v-if="!apps.length">
|
2023-07-26 01:25:42 +02:00
|
|
|
<em>{{ t('no_apps') }}</em>
|
2023-07-19 18:42:05 +02:00
|
|
|
</div>
|
2024-01-20 14:37:35 +01:00
|
|
|
<ul v-else class="grid md:grid-cols-2 xl:grid-cols-3 gap-4">
|
|
|
|
<li
|
|
|
|
v-for="app in apps"
|
|
|
|
:key="app.label"
|
2024-01-28 15:56:30 +01:00
|
|
|
class="flex flex-auto border border-neutral rounded p-4 relative hover:bg-neutral hover:text-neutral-content"
|
2024-01-20 14:37:35 +01:00
|
|
|
>
|
|
|
|
<img
|
|
|
|
v-if="app.logo"
|
2024-02-09 15:28:40 +01:00
|
|
|
aria-hidden
|
2024-01-20 14:37:35 +01:00
|
|
|
:src="app.logo"
|
|
|
|
class="w-24 h-24 rounded me-4 bg-white"
|
2024-02-09 15:28:40 +01:00
|
|
|
alt=""
|
2024-01-20 14:37:35 +01:00
|
|
|
/>
|
|
|
|
<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>
|
2023-07-19 18:42:05 +02:00
|
|
|
</li>
|
|
|
|
</ul>
|
2023-11-23 16:01:49 +01:00
|
|
|
</section>
|
2023-07-19 18:42:05 +02:00
|
|
|
</div>
|
2023-07-12 04:52:58 +02:00
|
|
|
</template>
|
2023-07-26 01:25:42 +02:00
|
|
|
|
2023-11-23 16:01:49 +01:00
|
|
|
<style scoped>
|
2024-01-20 14:37:35 +01:00
|
|
|
.grid li a::after {
|
|
|
|
content: '';
|
|
|
|
position: absolute;
|
|
|
|
top: 0px;
|
|
|
|
left: 0px;
|
|
|
|
right: 0px;
|
|
|
|
bottom: 0px;
|
2023-07-26 01:25:42 +02:00
|
|
|
}
|
|
|
|
</style>
|