mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-04-26 09:20:18 +08:00
- 删除 AppSidebar.vue 中的 StoreModeSwitcher 引入并删除该组件。 - 强制设置当前商店模式为 'hybrid'。 - 修复了因为 `window.apm_store.arch` 包含 `-store` 或 `-apm` 后缀导致路径替换异常的问题,现在会通过动态添加后缀来构建资源请求路径,以兼容 Spark Store 和 APM Store 服务器不同的资源组织结构。
98 lines
2.7 KiB
Vue
98 lines
2.7 KiB
Vue
<template>
|
|
<div class="space-y-6">
|
|
<div v-if="loading" class="text-center text-slate-500">
|
|
正在加载首页内容…
|
|
</div>
|
|
<div v-else-if="error" class="text-center text-rose-600">{{ error }}</div>
|
|
<div v-else>
|
|
<div class="grid gap-4 auto-fit-grid">
|
|
<a
|
|
v-for="link in links"
|
|
:key="link.url + link.name"
|
|
:href="link.type === '_blank' ? undefined : link.url"
|
|
@click.prevent="onLinkClick(link)"
|
|
class="flex flex-col items-start gap-2 rounded-2xl border border-slate-200/70 bg-white/90 p-4 shadow-sm hover:shadow-lg transition"
|
|
:title="link.more as string"
|
|
>
|
|
<img
|
|
:src="computedImgUrl(link)"
|
|
class="h-20 w-full object-contain"
|
|
loading="lazy"
|
|
/>
|
|
<div class="text-base font-semibold text-slate-900">
|
|
{{ link.name }}
|
|
</div>
|
|
<div class="text-sm text-slate-500">{{ link.more }}</div>
|
|
</a>
|
|
</div>
|
|
|
|
<div class="space-y-6 mt-6">
|
|
<section v-for="section in lists" :key="section.title">
|
|
<div class="flex items-center justify-between">
|
|
<h3 class="text-lg font-semibold text-slate-900">
|
|
{{ section.title }}
|
|
</h3>
|
|
</div>
|
|
<div class="mt-3 grid gap-4 auto-fit-grid">
|
|
<AppCard
|
|
v-for="app in section.apps"
|
|
:key="app.pkgname"
|
|
:app="app"
|
|
@open-detail="$emit('open-detail', $event)"
|
|
/>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import AppCard from "./AppCard.vue";
|
|
import { APM_STORE_BASE_URL } from "../global/storeConfig";
|
|
import type { HomeLink, HomeList, App } from "../global/typedefinition";
|
|
|
|
defineProps<{
|
|
links: HomeLink[];
|
|
lists: HomeList[];
|
|
loading: boolean;
|
|
error: string;
|
|
}>();
|
|
|
|
defineEmits<{
|
|
(e: "open-detail", app: App | Record<string, unknown>): void;
|
|
}>();
|
|
|
|
const computedImgUrl = (link: HomeLink) => {
|
|
if (!link.imgUrl) return "";
|
|
const arch = window.apm_store.arch || "amd64";
|
|
const finalArch = link.origin === "spark" ? `${arch}-store` : `${arch}-apm`;
|
|
return `${APM_STORE_BASE_URL}/${finalArch}${link.imgUrl}`;
|
|
};
|
|
|
|
const onLinkClick = (link: HomeLink) => {
|
|
if (link.type === "_blank") {
|
|
window.open(link.url, "_blank");
|
|
} else {
|
|
// open in same page: navigate to url
|
|
window.location.href = link.url;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped></style>
|
|
|
|
<style scoped>
|
|
.auto-fit-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
}
|
|
|
|
/* slight gap tuning for small screens */
|
|
@media (max-width: 640px) {
|
|
.auto-fit-grid {
|
|
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
}
|
|
}
|
|
</style>
|