diff --git a/astro.config.mjs b/astro.config.mjs
index 4585435..4204ccc 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -14,7 +14,7 @@ let target = process.env.VITE_API_URL || 'http://localhost:51015';
const apiProxy = { target: target, changeOrigin: true, ws: true, rewriteWsOrigin: true, secure: false, cookieDomainRewrite: 'localhost' };
let proxy = {
'/root/': {
- target: `${target}/root/`,
+ target: `${target}`,
},
'/api': apiProxy,
'/client': apiProxy,
diff --git a/package.json b/package.json
index 3d80c6c..e41664e 100644
--- a/package.json
+++ b/package.json
@@ -1,17 +1,18 @@
{
- "name": "@kevisual/astro-simplate-template",
+ "name": "@kevisual/hot-api",
"version": "0.0.2",
"description": "",
"main": "index.js",
- "basename": "/root/astro-simplate-template-docs",
+ "basename": "/root/hot-api",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
- "pub": "envision deploy ./dist -k astro-simplate-template-docs -v 0.0.2 -u",
+ "pub": "envision deploy ./dist -k hot-api -v 0.0.2 -u -y y",
+ "pub:docs": "envision deploy ./dist -k hot-api-docs -v 0.0.2 -u",
"slide:dev": "slidev --open slides/index.md",
- "slide:build": "slidev build slides/index.md --base /root/astro-simplate-template-slide/",
- "slide:pub": "envision deploy ./slides/dist -k astro-simplate-template-slide -v 0.0.2 -u",
+ "slide:build": "slidev build slides/index.md --base /root/hot-api-slide/",
+ "slide:pub": "envision deploy ./slides/dist -k hot-api-slide -v 0.0.2 -u",
"ui": "pnpm dlx shadcn@latest add "
},
"keywords": [],
diff --git a/src/apps/bg.tsx b/src/apps/bg.tsx
new file mode 100644
index 0000000..1a1f105
--- /dev/null
+++ b/src/apps/bg.tsx
@@ -0,0 +1,18 @@
+
+export const BG = (props: { children: React.ReactNode }) => {
+ return (
+
+ {props.children}
+
+ );
+}
\ No newline at end of file
diff --git a/src/apps/hotkeys/components/icon.tsx b/src/apps/hotkeys/components/icon.tsx
new file mode 100644
index 0000000..c0771cf
--- /dev/null
+++ b/src/apps/hotkeys/components/icon.tsx
@@ -0,0 +1,60 @@
+import { useStore } from "../store";
+export const RefreshButton = () => {
+ const { isLoading, fetchItems } = useStore();
+
+ return (
+
+ );
+};
+
+export const SettingsButton = () => {
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/src/apps/hotkeys/index.tsx b/src/apps/hotkeys/index.tsx
new file mode 100644
index 0000000..b110f2f
--- /dev/null
+++ b/src/apps/hotkeys/index.tsx
@@ -0,0 +1,187 @@
+/**
+ * title: Hotkeys App Component
+ * description: A React component displaying a grid of glassmorphism cards with icons or abbreviated titles, using Zustand for state management and Tailwind CSS for styling. Includes an advanced search feature with glassmorphism and hover effects.
+ * tags: react, zustand, tailwindcss, glassmorphism, component, search
+ * createdAt: 2025-12-05
+ */
+
+import { useEffect, useState } from 'react';
+import { SettingsButton, RefreshButton } from './components/icon';
+import { useStore, CardItem } from './store';
+const Card = ({ item }: { item: CardItem }) => {
+ const [isPressed, setIsPressed] = useState(false);
+ const { sendEvent } = useStore();
+ // 动效逻辑:点击后动一下恢复
+ const handleClick = () => {
+ setIsPressed(true);
+ setTimeout(() => setIsPressed(false), 150);
+ sendEvent(item);
+ };
+
+ return (
+
+ {/* Tech Glow Lines */}
+
+
+ {/* Shine effect on hover */}
+
+
+ {/* Content Container */}
+
+ {/* Icon or Title Placeholder */}
+
+ {item.iconUrl ? (
+

{
+ // Fallback if image fails to load: hide image and show text
+ e.currentTarget.style.display = 'none';
+ const parent = e.currentTarget.parentElement;
+ if (parent) {
+ const span = document.createElement('span');
+ span.innerText = item.title.slice(0, 2);
+ parent.appendChild(span);
+ }
+ }}
+ />
+ ) : (
+
{item.title.slice(0, 2)}
+ )}
+
+
+ {/* Full Title (Truncated if too long) */}
+
+
+
+ );
+};
+
+
+
+const AdvancedSearch = () => {
+ const [isFocused, setIsFocused] = useState(false);
+
+ const handleSearch = () => {
+ // 搜索功能预留
+ console.log("Search triggered");
+ };
+
+ return (
+ {
+ setIsFocused(true)
+ }}
+ >
+
setIsFocused(true)}
+ onBlur={() => setIsFocused(false)}
+ onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
+ />
+
+
+
+ );
+};
+
+export const App = () => {
+ const { items, isLoading, fetchItems } = useStore();
+
+ useEffect(() => {
+ fetchItems();
+ }, [fetchItems]);
+
+ return (
+
+ {/* Overlay for premium look and contrast */}
+
+
+
+
+
+
+ HotKeys
+
+ {/* 3D层次感背景文字 */}
+
+ HotKeys
+
+ {/* 发光边缘效果 */}
+
+
+
+
+
+ {isLoading ? (
+
+ ) : (
+
+ {items.map((item) => (
+
+ ))}
+
+ )}
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/apps/hotkeys/store.ts b/src/apps/hotkeys/store.ts
new file mode 100644
index 0000000..e2a9872
--- /dev/null
+++ b/src/apps/hotkeys/store.ts
@@ -0,0 +1,58 @@
+import { create } from 'zustand';
+import { query } from '../../modules/query'
+// --- Types ---
+export interface CardItem {
+ id: string;
+ title: string;
+ iconUrl?: string;
+ description?: string;
+ data?: any;
+}
+
+export interface StoreState {
+ items: CardItem[];
+ isLoading: boolean;
+ fetchItems: () => Promise;
+ sendEvent: (item: CardItem) => Promise;
+}
+
+// --- Store ---
+export const useStore = create((set) => ({
+ items: [],
+ isLoading: false,
+ fetchItems: async () => {
+ set({ isLoading: true });
+ // TODO: Replace with actual API call
+ // const response = await fetch('/api/hotkeys');
+ // const data = await response.json();
+
+ // Mock data for demonstration
+ const mockData: CardItem[] = Array.from({ length: 12 }).map((_, i) => ({
+ id: `item-${i}`,
+ title: i % 4 === 0 ? `工具 ${i + 1}` : `Application Long Name ${i + 1}`,
+ iconUrl: i % 3 === 0 ? `https://api.dicebear.com/7.x/icons/svg?seed=${i}` : undefined,
+ description: `Description for item ${i + 1}`
+ }));
+ mockData.unshift({
+ id: 'item-search',
+ title: 'win+d 显示桌面',
+ iconUrl: 'https://api.dicebear.com/7.x/icons/svg?seed=search',
+ description: '显示桌面'
+ })
+ // Simulate network delay
+ await new Promise(resolve => setTimeout(resolve, 800));
+
+ set({ items: mockData, isLoading: false });
+ },
+ sendEvent: async (item: CardItem) => {
+ // client/router?path=key-sender&keys=win+d
+ const res = await query.post({
+ path: 'key-sender',
+ keys: 'win+d'
+ });
+ console.log('Event sent for item:', item, 'Response:', res);
+ if (res.code !== 200) {
+ alert('Failed to send event');
+ }
+ }
+}));
diff --git a/src/modules/query.ts b/src/modules/query.ts
index 22b6bd1..4b7d90a 100644
--- a/src/modules/query.ts
+++ b/src/modules/query.ts
@@ -1,4 +1,4 @@
-import { Query } from '@kevisual/query'
+import { QueryClient } from '@kevisual/query'
const getUrl = () => {
const host = window.location.host
@@ -10,6 +10,6 @@ const getUrl = () => {
return '/client/router'
}
-export const query = new Query({
- url: getUrl()
+export const query = new QueryClient({
+ url: 'http://localhost:51015/client/router',
});
\ No newline at end of file
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 3e848df..a08c587 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -1,47 +1,10 @@
---
-// import { query } from '@/modules/query.ts';
-console.log('Hello from index.astro');
-import '../styles/global.css';
+import Html from '@/components/html.astro';
+import { App } from '../apps/hotkeys/index.tsx';
---
-
-
- My Homepage
-
-
- Welcome to my website!
-
-
-
-
-
-
+
+
+
+
+