refactor: improve code formatting and consistency across components

- Updated button and span elements in ThemeToggle.vue and TopActions.vue for better readability.
- Enhanced UninstallConfirmModal.vue and UpdateAppsModal.vue with consistent indentation and spacing.
- Refactored downloadStatus.ts and storeConfig.ts for improved code clarity.
- Standardized string quotes and spacing in typedefinition.ts and processInstall.ts.
- Ensured consistent use of arrow functions and improved variable declarations throughout the codebase.
This commit is contained in:
Elysia
2026-02-12 18:32:41 +08:00
parent e11740ad4c
commit 6622e70033
29 changed files with 1681 additions and 1042 deletions
+47 -27
View File
@@ -1,47 +1,67 @@
<template>
<div @click="openDetail"
class="group flex h-full cursor-pointer gap-4 rounded-2xl border border-slate-200/70 bg-white/90 p-4 shadow-sm transition hover:-translate-y-1 hover:border-brand/50 hover:shadow-lg dark:border-slate-800/60 dark:bg-slate-900/60">
<div
@click="openDetail"
class="group flex h-full cursor-pointer gap-4 rounded-2xl border border-slate-200/70 bg-white/90 p-4 shadow-sm transition hover:-translate-y-1 hover:border-brand/50 hover:shadow-lg dark:border-slate-800/60 dark:bg-slate-900/60"
>
<div
class="flex h-16 w-16 items-center justify-center overflow-hidden rounded-2xl bg-gradient-to-b from-slate-100 to-slate-200 shadow-inner dark:from-slate-800 dark:to-slate-700">
<img ref="iconImg" :src="loadedIcon" alt="icon"
:class="['h-full w-full object-cover transition-opacity duration-300', isLoaded ? 'opacity-100' : 'opacity-0']" />
class="flex h-16 w-16 items-center justify-center overflow-hidden rounded-2xl bg-gradient-to-b from-slate-100 to-slate-200 shadow-inner dark:from-slate-800 dark:to-slate-700"
>
<img
ref="iconImg"
:src="loadedIcon"
alt="icon"
:class="[
'h-full w-full object-cover transition-opacity duration-300',
isLoaded ? 'opacity-100' : 'opacity-0',
]"
/>
</div>
<div class="flex flex-1 flex-col gap-1 overflow-hidden">
<div class="truncate text-base font-semibold text-slate-900 dark:text-white">{{ app.name || '' }}</div>
<div class="text-sm text-slate-500 dark:text-slate-400">{{ app.pkgname || '' }} · {{ app.version || '' }}</div>
<div class="text-sm text-slate-500 dark:text-slate-400">{{ description }}</div>
<div
class="truncate text-base font-semibold text-slate-900 dark:text-white"
>
{{ app.name || "" }}
</div>
<div class="text-sm text-slate-500 dark:text-slate-400">
{{ app.pkgname || "" }} · {{ app.version || "" }}
</div>
<div class="text-sm text-slate-500 dark:text-slate-400">
{{ description }}
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, onBeforeUnmount, ref, watch } from 'vue';
import { APM_STORE_BASE_URL } from '../global/storeConfig';
import type { App } from '../global/typedefinition';
import { computed, onMounted, onBeforeUnmount, ref, watch } from "vue";
import { APM_STORE_BASE_URL } from "../global/storeConfig";
import type { App } from "../global/typedefinition";
const props = defineProps<{
app: App
const props = defineProps<{
app: App;
}>();
const emit = defineEmits<{
(e: 'open-detail', app: App): void
(e: "open-detail", app: App): void;
}>();
const iconImg = ref<HTMLImageElement | null>(null);
const isLoaded = ref(false);
const loadedIcon = ref('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"%3E%3Crect fill="%23f0f0f0" width="100" height="100"/%3E%3C/svg%3E');
const loadedIcon = ref(
'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"%3E%3Crect fill="%23f0f0f0" width="100" height="100"/%3E%3C/svg%3E',
);
const iconPath = computed(() => {
return `${APM_STORE_BASE_URL}/${window.apm_store.arch}/${props.app.category}/${props.app.pkgname}/icon.png`;
});
const description = computed(() => {
const more = props.app.more || '';
return more.substring(0, 80) + (more.length > 80 ? '...' : '');
const more = props.app.more || "";
return more.substring(0, 80) + (more.length > 80 ? "..." : "");
});
const openDetail = () => {
emit('open-detail', props.app);
emit("open-detail", props.app);
};
let observer: IntersectionObserver | null = null;
@@ -57,24 +77,23 @@ onMounted(() => {
img.onload = () => {
loadedIcon.value = iconPath.value;
isLoaded.value = true;
if (observer)
observer.unobserve(entry.target);
if (observer) observer.unobserve(entry.target);
};
img.onerror = () => {
// 加载失败时使用默认图标
loadedIcon.value = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"%3E%3Crect fill="%23e0e0e0" width="100" height="100"/%3E%3Ctext x="50" y="50" text-anchor="middle" dy=".3em" fill="%23999" font-size="14"%3ENo Icon%3C/text%3E%3C/svg%3E';
loadedIcon.value =
'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"%3E%3Crect fill="%23e0e0e0" width="100" height="100"/%3E%3Ctext x="50" y="50" text-anchor="middle" dy=".3em" fill="%23999" font-size="14"%3ENo Icon%3C/text%3E%3C/svg%3E';
isLoaded.value = true;
if (observer)
observer.unobserve(entry.target);
if (observer) observer.unobserve(entry.target);
};
img.src = iconPath.value;
}
});
},
{
rootMargin: '50px', // 提前50px开始加载
threshold: 0.01
}
rootMargin: "50px", // 提前50px开始加载
threshold: 0.01,
},
);
// 观察图标元素
@@ -85,7 +104,8 @@ onMounted(() => {
// 当 app 变更时重置懒加载状态并重新观察
watch(iconPath, () => {
loadedIcon.value = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"%3E%3Crect fill="%23f0f0f0" width="100" height="100"/%3E%3C/svg%3E';
loadedIcon.value =
'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"%3E%3Crect fill="%23f0f0f0" width="100" height="100"/%3E%3C/svg%3E';
isLoaded.value = false;
if (observer && iconImg.value) {
observer.unobserve(iconImg.value);