<script setup lang="ts">
import { computed } from "vue";
import { useI18n } from "vue-i18n";
import { GnCard } from "gnexus-ui-kit/vue";
import AppShell from "../components/AppShell.vue";
const { t, tm, rt } = useI18n();
// stable archive names, rebuilt by `npm run package -w @ltt/extension`
const zips = {
chrome: "/ext/bugtrail-chrome.zip",
firefox: "/ext/bugtrail-firefox.zip",
};
/** the panel's own origin is what the extension should be pointed at */
const serverUrl = computed(() => window.location.origin);
/** tm() returns the raw message array; rt() resolves each entry to a string */
function steps(key: string): string[] {
const messages = tm(key);
if (!Array.isArray(messages)) return [];
return messages.map((message) => rt(message as never));
}
</script>
<template>
<AppShell>
<div class="download-page">
<h1 class="download-title">{{ t("download.title") }}</h1>
<p class="download-subtitle">{{ t("download.subtitle") }}</p>
<div class="download-grid">
<GnCard class="download-card">
<div class="download-card-head">
<i class="ph ph-browsers" />
<h2>{{ t("download.chrome") }}</h2>
</div>
<a :href="zips.chrome" class="download-btn" download>
<i class="ph ph-download-simple" /> {{ t("download.downloadZip") }}
</a>
<p class="download-hint">{{ t("download.downloadHint") }}</p>
<ol class="download-steps">
<li v-for="(step, index) in steps('download.chromeSteps')" :key="index">{{ step }}</li>
</ol>
</GnCard>
<GnCard class="download-card">
<div class="download-card-head">
<i class="ph ph-firefox-logo" />
<h2>{{ t("download.firefox") }}</h2>
</div>
<a :href="zips.firefox" class="download-btn" download>
<i class="ph ph-download-simple" /> {{ t("download.downloadZip") }}
</a>
<p class="download-hint">{{ t("download.downloadHint") }}</p>
<ol class="download-steps">
<li v-for="(step, index) in steps('download.firefoxSteps')" :key="index">{{ step }}</li>
</ol>
</GnCard>
</div>
<GnCard class="download-card download-wide">
<h2 class="download-section-title">{{ t("download.setupTitle") }}</h2>
<ol class="download-steps">
<li>{{ t("download.setupOpen") }}</li>
<li>
{{ t("download.setupServer") }}
<code class="download-server">{{ serverUrl }}</code>
</li>
<li>{{ t("download.setupSignIn") }}</li>
</ol>
</GnCard>
<GnCard class="download-card download-wide">
<h2 class="download-section-title">{{ t("download.usageTitle") }}</h2>
<p class="download-usage">{{ t("download.usageNote") }}</p>
</GnCard>
</div>
</AppShell>
</template>
<style scoped>
.download-page {
display: flex;
flex-direction: column;
gap: 16px;
max-width: 900px;
}
.download-title {
margin: 0;
font-size: 22px;
}
.download-subtitle {
margin: 0;
opacity: 0.7;
}
.download-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 16px;
align-items: start;
}
.download-card {
width: 100%;
max-width: none;
padding: 0;
display: flex;
flex-direction: column;
gap: 10px;
min-width: 0;
}
.download-card :deep(.card-content) {
padding: 18px;
}
.download-card-head {
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
}
.download-card-head .ph {
font-size: 20px;
color: var(--ltt-accent, #7aa2f7);
}
.download-card-head h2 {
margin: 0;
font-size: 16px;
}
.download-section-title {
margin: 0;
font-size: 16px;
}
.download-btn {
display: inline-flex;
align-items: center;
gap: 8px;
align-self: flex-start;
padding: 8px 16px;
border: 2px solid var(--ltt-accent, #7aa2f7);
background: var(--ltt-accent, #7aa2f7);
color: var(--ltt-bg, #10121c);
font-weight: 700;
font-size: 13px;
text-decoration: none;
}
.download-btn:hover {
filter: brightness(1.1);
}
.download-hint {
margin: 0;
font-size: 12px;
opacity: 0.6;
}
.download-steps {
margin: 0;
padding-left: 20px;
display: flex;
flex-direction: column;
gap: 6px;
font-size: 13px;
}
.download-usage {
margin: 0;
font-size: 13px;
white-space: pre-wrap;
}
.download-server {
padding: 2px 8px;
border: 1px solid var(--ltt-border, rgba(192, 202, 245, 0.24));
background: var(--ltt-surface-sunken, #10121c);
font-family: var(--font-mono, ui-monospace, monospace);
font-size: 12px;
user-select: all;
}
</style>