refactor: DRY pass on frontend — shared palette, composable, and tab loader
- Extract milestoneColor to utils/palette.ts; remove duplicate in HomeView + ProjectListView - Create useBackgroundRefresh composable; wire into HomeView + BriefingView (removes manual setInterval/clearInterval boilerplate) - Extract _loadTabContent() in SettingsView so watch and onMounted share one tab→loader mapping - Move raw fetch() api-key calls to typed helpers in api/client.ts (listApiKeys, createApiKey, revokeApiKey) - Drop unused onUnmounted import from BriefingView Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||
import { apiGet, listEvents } from "@/api/client";
|
||||
import { useBackgroundRefresh } from "@/composables/useBackgroundRefresh";
|
||||
import { milestoneColor } from "@/utils/palette";
|
||||
import type { Note } from "@/types/note";
|
||||
import type { Task, TaskListResponse, TaskStatus } from "@/types/task";
|
||||
import type { ToolCallRecord, Message } from "@/types/chat";
|
||||
@@ -69,24 +71,8 @@ const upcomingEvents = ref<EventEntry[]>([]);
|
||||
const eventSlideOverOpen = ref(false);
|
||||
const editingEvent = ref<EventEntry | null>(null);
|
||||
|
||||
// ─── Milestone color palette ──────────────────────────────────────────────────
|
||||
|
||||
function milestoneColor(index: number): string {
|
||||
const palette = [
|
||||
"var(--color-primary)",
|
||||
"var(--color-success, #22c55e)",
|
||||
"#c98a00",
|
||||
"var(--color-danger, #e74c3c)",
|
||||
"#8b5cf6",
|
||||
];
|
||||
return palette[index % palette.length];
|
||||
}
|
||||
|
||||
// ─── Background refresh (no-flicker) ─────────────────────────────────────────
|
||||
// Runs on a timer while the page is visible. Never touches `loading` so
|
||||
// existing content stays on screen while the fetch is in flight.
|
||||
|
||||
let _refreshTimer: ReturnType<typeof setInterval> | null = null
|
||||
// Never touches `loading` so existing content stays on screen while fetching.
|
||||
|
||||
function _dateRange() {
|
||||
const today = new Date()
|
||||
@@ -173,9 +159,10 @@ onMounted(async () => {
|
||||
chatInputRef.value?.focus();
|
||||
loadProjects();
|
||||
|
||||
_refreshTimer = setInterval(_backgroundRefresh, 90_000)
|
||||
});
|
||||
|
||||
useBackgroundRefresh(_backgroundRefresh, 90_000, () => !loading.value);
|
||||
|
||||
async function loadProjects() {
|
||||
if (!heroProject.value) return;
|
||||
const hid = heroProject.value.id;
|
||||
@@ -239,7 +226,6 @@ onMounted(() => {
|
||||
});
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener("shortcut:focus-chat", onFocusChatShortcut);
|
||||
if (_refreshTimer !== null) clearInterval(_refreshTimer)
|
||||
});
|
||||
|
||||
const chatStore = useChatStore();
|
||||
|
||||
Reference in New Issue
Block a user