generated from tailored/app-template
	Initial commit
This commit is contained in:
		
							
								
								
									
										94
									
								
								snippets/no-react/h.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								snippets/no-react/h.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
// import { nanoid } from 'nanoid';
 | 
			
		||||
import { RefObject, SyntheticEvent } from 'react';
 | 
			
		||||
const randomId = () => {
 | 
			
		||||
  return crypto.getRandomValues(new Uint32Array(1))[0].toString(16);
 | 
			
		||||
};
 | 
			
		||||
const loadChidren = (element: any, children: any[]) => {
 | 
			
		||||
  children.forEach((child) => {
 | 
			
		||||
    if (typeof child === 'boolean') {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof child === 'function') {
 | 
			
		||||
      // console.log('child', child);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof child === 'undefined') {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    // console.log('child', child);
 | 
			
		||||
    element.appendChild(typeof child === 'string' ? document.createTextNode(child) : child);
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
// 在项目中定义 h 函数
 | 
			
		||||
export function h(type: string | Function, props: any, ...children: any[]): HTMLElement {
 | 
			
		||||
  if (typeof type === 'function') {
 | 
			
		||||
    const element = type(props);
 | 
			
		||||
    loadChidren(element, children);
 | 
			
		||||
    return element;
 | 
			
		||||
  }
 | 
			
		||||
  const element = document.createElement(type);
 | 
			
		||||
  const filterKeys = ['onLoad', 'onUnload', 'key'];
 | 
			
		||||
  const key = props?.key || randomId();
 | 
			
		||||
  Object.entries(props || {}).forEach(([key, value]) => {
 | 
			
		||||
    if (filterKeys.includes(key)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (key === 'className') {
 | 
			
		||||
      element.setAttribute('class', value as string);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (key.startsWith('on')) {
 | 
			
		||||
      element.addEventListener(key.slice(2).toLowerCase(), value as EventListener);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (key === 'ref' && value) {
 | 
			
		||||
      (value as any).current = element;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof value === 'object') {
 | 
			
		||||
      console.log('error', element, type, value);
 | 
			
		||||
    } else {
 | 
			
		||||
      element.setAttribute(key, value as string);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  const onLoad = props?.onLoad;
 | 
			
		||||
  const checkConnect = () => {
 | 
			
		||||
    if (element.isConnected) {
 | 
			
		||||
      onLoad?.({ el: element, key, _props: props });
 | 
			
		||||
      // console.log('onLoad', element, key);
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  };
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    const res = checkConnect();
 | 
			
		||||
    if (!res) {
 | 
			
		||||
      setTimeout(() => {}, 1000);
 | 
			
		||||
    }
 | 
			
		||||
  }, 20);
 | 
			
		||||
 | 
			
		||||
  loadChidren(element, children);
 | 
			
		||||
  return element;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
declare global {
 | 
			
		||||
  namespace JSX {
 | 
			
		||||
    // type Element = HTMLElement; // 将 JSX.Element 设置为 HTMLElement
 | 
			
		||||
    interface Element extends HTMLElement {
 | 
			
		||||
      class?: string;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  namespace React {
 | 
			
		||||
    interface FormEvent<T = Element> extends SyntheticEvent<T> {
 | 
			
		||||
      target: EventTarget & (T extends HTMLInputElement ? HTMLInputElement : T);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useRef = <T = HTMLDivElement>(initialValue: T | null = null): RefObject<T | null> => {
 | 
			
		||||
  return { current: initialValue };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const useEffect = (callback: () => void) => {
 | 
			
		||||
  setTimeout(callback, 0);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										6
									
								
								snippets/react/ReactApp.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								snippets/react/ReactApp.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import { createRoot } from 'react-dom/client';
 | 
			
		||||
 | 
			
		||||
export const ReactApp = () => {
 | 
			
		||||
  const root = createRoot(document.getElementById('app')!);
 | 
			
		||||
  root.render(<div>Hello, World!</div>);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										12
									
								
								snippets/routes-app/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								snippets/routes-app/app.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
import type { Page } from '@kevisual/store/page';
 | 
			
		||||
import type { QueryRouterServer } from '@kevisual/router';
 | 
			
		||||
export const page = useContextKey('page', () => {
 | 
			
		||||
  return new window.Page({
 | 
			
		||||
    basename: '',
 | 
			
		||||
  }) as unknown as Page;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const app = useContextKey('app', () => {
 | 
			
		||||
  console.error('app not found');
 | 
			
		||||
  return null as unknown as QueryRouterServer;
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										39
									
								
								snippets/routes-app/main.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								snippets/routes-app/main.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
import { page, app } from './app.ts';
 | 
			
		||||
export const render = ({ renderRoot }) => {
 | 
			
		||||
  renderRoot.innerHTML = `
 | 
			
		||||
    <h1>Hello, World!</h1>
 | 
			
		||||
  `;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
if (page) {
 | 
			
		||||
  page.addPage('/app-template', 'home');
 | 
			
		||||
  page.subscribe('home', () => {
 | 
			
		||||
    render({
 | 
			
		||||
      renderRoot: document.getElementById('ai-root'),
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (app) {
 | 
			
		||||
  app
 | 
			
		||||
    .route({
 | 
			
		||||
      path: 'app-template',
 | 
			
		||||
      key: 'render',
 | 
			
		||||
    })
 | 
			
		||||
    .define(async (ctx) => {
 | 
			
		||||
      let { renderRoot } = ctx.query;
 | 
			
		||||
      if (!renderRoot) {
 | 
			
		||||
        ctx.throw(404, 'renderRoot is required');
 | 
			
		||||
      }
 | 
			
		||||
      if (typeof renderRoot === 'string') {
 | 
			
		||||
        renderRoot = document.querySelector(renderRoot);
 | 
			
		||||
      }
 | 
			
		||||
      if (!renderRoot) {
 | 
			
		||||
        ctx.throw(404, 'renderRoot not found');
 | 
			
		||||
      }
 | 
			
		||||
      render({
 | 
			
		||||
        renderRoot,
 | 
			
		||||
      });
 | 
			
		||||
    })
 | 
			
		||||
    .addTo(app);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								snippets/store/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								snippets/store/app.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
import { create } from 'zustand';
 | 
			
		||||
import { query } from '@/modules/query';
 | 
			
		||||
type Store = {
 | 
			
		||||
  list: any[];
 | 
			
		||||
  setList: (list: any[]) => void;
 | 
			
		||||
  data: any;
 | 
			
		||||
  setData: (data: any) => void;
 | 
			
		||||
  loading: boolean;
 | 
			
		||||
  setLoading: (loading: boolean) => void;
 | 
			
		||||
  formData: any;
 | 
			
		||||
  setFormData: (data: any) => void;
 | 
			
		||||
  getList: () => Promise<any>;
 | 
			
		||||
  init: () => Promise<void>;
 | 
			
		||||
  getData: (id: number) => Promise<any>;
 | 
			
		||||
  updateData: (data: any, opts?: { refresh?: boolean }) => Promise<any>;
 | 
			
		||||
  deleteData: (id: number, opts?: { refresh?: boolean }) => Promise<any>;
 | 
			
		||||
};
 | 
			
		||||
export const useStore = create<Store>((set, get) => ({
 | 
			
		||||
  list: [],
 | 
			
		||||
  setList: (list) => set({ list }),
 | 
			
		||||
  data: null,
 | 
			
		||||
  setData: (data) => set({ data }),
 | 
			
		||||
  loading: false,
 | 
			
		||||
  setLoading: (loading) => set({ loading }),
 | 
			
		||||
  formData: null,
 | 
			
		||||
  setFormData: (formData) => set({ formData }),
 | 
			
		||||
  getList: async () => {
 | 
			
		||||
    set({ loading: true });
 | 
			
		||||
    const res = await query.post({ path: 'posts', key: 'list' });
 | 
			
		||||
    set({ loading: false });
 | 
			
		||||
    if (res.code === 200) {
 | 
			
		||||
      set({ list: res.data });
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
  },
 | 
			
		||||
  init: async () => {
 | 
			
		||||
    await get().getList();
 | 
			
		||||
  },
 | 
			
		||||
  getData: async (id) => {
 | 
			
		||||
    set({ loading: true });
 | 
			
		||||
    const res = await query.post({
 | 
			
		||||
      path: 'posts',
 | 
			
		||||
      key: 'get',
 | 
			
		||||
      id,
 | 
			
		||||
    });
 | 
			
		||||
    set({ loading: false });
 | 
			
		||||
    if (res.code === 200) {
 | 
			
		||||
      const data = res.data;
 | 
			
		||||
      set({ data });
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
  },
 | 
			
		||||
  updateData: async (data, opts = { refresh: true }) => {
 | 
			
		||||
    set({ loading: true });
 | 
			
		||||
    const res = await query.post({
 | 
			
		||||
      path: 'posts',
 | 
			
		||||
      key: 'update',
 | 
			
		||||
      data,
 | 
			
		||||
    });
 | 
			
		||||
    set({ loading: false });
 | 
			
		||||
    if (res.code === 200) {
 | 
			
		||||
      set({ data: res.data });
 | 
			
		||||
    }
 | 
			
		||||
    if (opts.refresh) {
 | 
			
		||||
      await get().getList();
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
  },
 | 
			
		||||
  deleteData: async (id, opts = { refresh: true }) => {
 | 
			
		||||
    set({ loading: true });
 | 
			
		||||
    const res = await query.post({
 | 
			
		||||
      path: 'posts',
 | 
			
		||||
      key: 'delete',
 | 
			
		||||
      id,
 | 
			
		||||
    });
 | 
			
		||||
    set({ loading: false });
 | 
			
		||||
    if (res.code === 200) {
 | 
			
		||||
      set({ data: null });
 | 
			
		||||
    }
 | 
			
		||||
    if (opts.refresh) {
 | 
			
		||||
      await get().getList();
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
  },
 | 
			
		||||
}));
 | 
			
		||||
		Reference in New Issue
	
	Block a user