<script lang="ts">
|
import { Call } from '@wailsio/runtime'
|
import { t } from '../../lib/i18n'
|
import AppIcon from '../shared/AppIcon.svelte'
|
|
let version = $state('2.1.30 (build 20260613.2201)')
|
const currentYear = new Date().getFullYear().toString()
|
const aboutLinks = [
|
{ labelKey: 'about.sourceProjectLabel', urlKey: 'about.sourceUrl' },
|
{ labelKey: 'about.licenseLabel', urlKey: 'about.licenseUrl' },
|
{ labelKey: 'about.privacyLabel', urlKey: 'about.privacyUrl' },
|
{ labelKey: 'about.feedbackLabel', urlKey: 'about.feedbackUrl' },
|
]
|
|
async function loadVersion() {
|
try {
|
const v: any = await Call.ByName('voicesnap/services.AppService.GetVersion')
|
if (v) version = v
|
} catch {}
|
}
|
loadVersion()
|
|
function openUrl(url: string) {
|
Call.ByName('voicesnap/services.AppService.OpenURL', url)
|
}
|
</script>
|
|
<div class="about">
|
<div class="center-content">
|
<AppIcon size={72} elevated />
|
<h2 class="app-name">{t('about.displayName')}</h2>
|
<p class="app-version">v{version}</p>
|
<p class="app-tagline">{t('about.tagline')}</p>
|
<p class="app-slogan">{t('about.slogan')}</p>
|
|
<div class="legal">
|
<p>{t('about.offlineText')}</p>
|
<p>{t('about.noDataText')}</p>
|
<p>{t('about.legalText')}</p>
|
<p>{t('about.legalDetails')}</p>
|
|
<div class="link-list">
|
{#each aboutLinks as item}
|
<div class="link-row">
|
<span class="link-label">{t(item.labelKey)}</span>
|
<button type="button" class="support-link" onclick={() => openUrl(t(item.urlKey))}>
|
{t(item.urlKey)}
|
</button>
|
</div>
|
{/each}
|
</div>
|
</div>
|
|
<button type="button" class="support-btn" onclick={() => openUrl(t('about.feedbackUrl'))}>
|
{t('about.openSupport')}
|
</button>
|
</div>
|
|
<div class="bottom">
|
<div class="divider"></div>
|
<p class="copyright">{t('about.copyright', { year: currentYear })}</p>
|
</div>
|
</div>
|
|
<style>
|
.about {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: flex-start;
|
min-height: calc(100vh - 40px);
|
padding: 28px 24px 18px;
|
background: var(--color-bg-grouped-secondary);
|
border-radius: var(--radius-md);
|
}
|
|
.center-content {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
width: min(560px, 100%);
|
}
|
|
.app-name {
|
font-size: 22px;
|
font-weight: 700;
|
margin-top: 16px;
|
text-align: center;
|
}
|
|
.app-version {
|
font-size: var(--font-size-sm);
|
color: var(--color-secondary-label);
|
margin-top: 8px;
|
}
|
|
.app-tagline {
|
margin-top: 18px;
|
font-size: var(--font-size-base);
|
font-weight: 600;
|
color: var(--color-label);
|
}
|
|
.app-slogan {
|
margin-top: 4px;
|
font-size: var(--font-size-sm);
|
color: var(--color-tertiary-label);
|
}
|
|
.legal {
|
width: 100%;
|
margin-top: 22px;
|
color: var(--color-secondary-label);
|
font-size: var(--font-size-sm);
|
line-height: 1.65;
|
text-align: left;
|
}
|
|
.legal p + p {
|
margin-top: 10px;
|
}
|
|
.link-list {
|
display: flex;
|
flex-direction: column;
|
gap: 8px;
|
margin-top: 12px;
|
}
|
|
.link-row {
|
display: grid;
|
grid-template-columns: 96px minmax(0, 1fr);
|
gap: 10px;
|
align-items: baseline;
|
}
|
|
.link-label {
|
color: var(--color-tertiary-label);
|
white-space: nowrap;
|
}
|
|
.support-link {
|
display: inline-block;
|
padding: 0;
|
border: none;
|
background: transparent;
|
color: var(--color-blue);
|
font: inherit;
|
cursor: pointer;
|
word-break: break-all;
|
text-align: left;
|
}
|
|
.support-btn {
|
margin-top: 20px;
|
padding: 8px 22px;
|
background: transparent;
|
border: 1.5px solid var(--color-separator);
|
border-radius: var(--radius-md);
|
font-size: var(--font-size-sm);
|
font-weight: 500;
|
color: var(--color-label);
|
cursor: pointer;
|
transition: all var(--transition-fast);
|
}
|
|
.support-btn:hover {
|
border-color: var(--color-blue);
|
color: var(--color-blue);
|
}
|
|
.bottom {
|
width: min(560px, 100%);
|
margin-top: auto;
|
padding-top: 22px;
|
text-align: center;
|
}
|
|
.divider {
|
height: 1px;
|
background: var(--color-separator);
|
margin-bottom: 12px;
|
}
|
|
.copyright {
|
font-size: var(--font-size-xs);
|
color: var(--color-tertiary-label);
|
}
|
|
@media (max-width: 520px) {
|
.link-row {
|
grid-template-columns: 1fr;
|
gap: 2px;
|
}
|
}
|
</style>
|