Files
cloudron-box/dashboard/src/components/AppInstallDialog.vue
T

137 lines
3.0 KiB
Vue
Raw Normal View History

2025-01-05 22:47:50 +01:00
<template>
<Dialog ref="dialogHandle" :show-x="true" @close="step = 0">
2025-01-05 23:35:01 +01:00
<div class="content">
2025-01-05 22:47:50 +01:00
<div class="header">
2025-01-05 23:35:01 +01:00
<div class="summary">
2025-01-05 22:47:50 +01:00
<div class="title">{{ manifest.title }}</div>
<div class="lastUpdated">{{ $t('appstore.installDialog.lastUpdated', { date: prettyDate(app.creationDate) }) }}</div>
<div class="memoryRequirement">{{ $t('appstore.installDialog.memoryRequirement', { size: prettyFileSize(manifest.memoryLimit) }) }}</div>
<div class="author"><a :href="manifest.website" target="_blank">Website</a></div>
</div>
2025-01-05 23:35:01 +01:00
<img class="icon" :src="app.iconUrl" />
2025-01-05 22:47:50 +01:00
</div>
2025-01-05 23:35:01 +01:00
<Transition name="slide-left" mode="out-in">
<div v-if="step === STEP.DETAILS">
<Button @click="step = STEP.INSTALL" icon="fa-solid fa-circle-down">Install {{ manifest.title }}</Button>
2025-01-05 23:35:01 +01:00
<div class="screenshots">
<img class="screenshot" v-for="image in manifest.mediaLinks" :key="image" :src="image"/>
</div>
<div class="description" v-html="description"></div>
</div>
<div v-else-if="step === STEP.INSTALL">
2025-01-05 23:35:01 +01:00
<div>Now install {{ manifest.title }}</div>
<br/>
<br/>
<Button @click="step = STEP.DETAILS" icon="fa-solid fa-circle-down">TODO Submit</Button>
2025-01-05 23:35:01 +01:00
</div>
</Transition>
2025-01-05 22:47:50 +01:00
</div>
</Dialog>
</template>
<script setup>
2025-01-05 22:47:50 +01:00
import { ref, computed, useTemplateRef } from 'vue';
2025-01-05 23:35:01 +01:00
import { Button, Dialog } from 'pankow';
2025-01-05 22:47:50 +01:00
import { prettyDate, prettyFileSize } from 'pankow/utils';
import { marked } from 'marked';
const STEP = Object.freeze({
DETAILS: Symbol('details'),
INSTALL: Symbol('install'),
});
// reactive
const app = ref({});
const manifest = ref({});
const step = ref(STEP.DETAILS);
const dialog = useTemplateRef('dialogHandle');
const description = computed(() => marked.parse(manifest.value.description || ''));
defineExpose({
open(a) {
step.value = STEP.DETAILS;
app.value = a;
manifest.value = a.manifest;
dialog.value.open();
}
});
2025-01-05 22:47:50 +01:00
</script>
<style scoped>
2025-01-05 23:35:01 +01:00
.slide-left-enter-active,
.slide-left-leave-active {
transition: all 0.25s ease-out;
}
.slide-left-enter-from {
opacity: 0;
transform: translateX(30px);
}
.slide-left-leave-to {
opacity: 0;
transform: translateX(-30px);
}
.content {
width: 1024px;
max-width: 100%;
height: 1024px;
max-height: 100%;
}
2025-01-05 22:47:50 +01:00
.header {
display: flex;
align-items: center;
2025-01-05 23:35:01 +01:00
justify-content: space-between;
margin: 4px;
2025-01-05 22:47:50 +01:00
}
2025-01-05 23:35:01 +01:00
.summary {
2025-01-05 22:47:50 +01:00
display: flex;
flex-direction: column;
2025-01-05 23:35:01 +01:00
font-size: 14px;
2025-01-05 22:47:50 +01:00
}
.title {
2025-01-05 23:35:01 +01:00
font-size: 32px;
2025-01-05 22:47:50 +01:00
margin-bottom: 10px;
}
.icon {
2025-01-05 23:35:01 +01:00
width: 128px;
height: 128px;
object-fit: contain;
2025-01-05 22:47:50 +01:00
margin-right: 20px;
}
.description {
2025-01-05 23:35:01 +01:00
margin: 0 4px;
}
.screenshots {
margin: 10px 4px;
2025-01-05 22:47:50 +01:00
display: flex;
2025-01-05 23:35:01 +01:00
gap: 20px;
width: 100%;
padding: 10px 0;
scroll-snap-type: x mandatory;
2025-01-05 23:35:01 +01:00
overflow: auto;
}
.screenshot {
display: inline-block;
border-radius: var(--pankow-border-radius);
height: 300px;
object-size: contain;
scroll-snap-align: center;
scroll-snap-stop: always;
2025-01-05 22:47:50 +01:00
}
</style>