🎉 chore(init): project initialization

This commit is contained in:
web@ppanel
2024-11-14 01:22:43 +07:00
commit 829edfa824
479 changed files with 61413 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
import { env } from 'next-runtime-env';
export const locales = ['en-US', 'zh-CN'];
export const NEXT_PUBLIC_DEFAULT_LANGUAGE = env('NEXT_PUBLIC_DEFAULT_LANGUAGE');
export const NEXT_PUBLIC_SITE_URL = env('NEXT_PUBLIC_SITE_URL');
export const NEXT_PUBLIC_API_URL = env('NEXT_PUBLIC_API_URL');
export const NEXT_PUBLIC_DEFAULT_USER_EMAIL = env('NEXT_PUBLIC_DEFAULT_USER_EMAIL');
export const NEXT_PUBLIC_DEFAULT_USER_PASSWORD = env('NEXT_PUBLIC_DEFAULT_USER_PASSWORD');
export const NEXT_PUBLIC_EMAIL = env('NEXT_PUBLIC_EMAIL');
export const NEXT_PUBLIC_TELEGRAM_LINK = env('NEXT_PUBLIC_TELEGRAM_LINK');
export const NEXT_PUBLIC_DISCORD_LINK = env('NEXT_PUBLIC_DISCORD_LINK');
export const NEXT_PUBLIC_GITHUB_LINK = env('NEXT_PUBLIC_GITHUB_LINK');
export const NEXT_PUBLIC_LINKEDIN_LINK = env('NEXT_PUBLIC_LINKEDIN_LINK');
export const NEXT_PUBLIC_TWITTER_LINK = env('NEXT_PUBLIC_TWITTER_LINK');
export const NEXT_PUBLIC_INSTAGRAM_LINK = env('NEXT_PUBLIC_INSTAGRAM_LINK');
Binary file not shown.
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
import localFont from 'next/font/local';
export const geistSans = localFont({
src: './GeistVF.woff',
variable: '--font-geist-sans',
weight: '100 900',
});
export const geistMono = localFont({
src: './GeistMonoVF.woff',
variable: '--font-geist-mono',
weight: '100 900',
});
+100
View File
@@ -0,0 +1,100 @@
export const navs = [
{
title: 'dashboard',
url: '/dashboard',
icon: 'uil:dashboard',
},
{
title: 'personal',
items: [
{
title: 'profile',
url: '/profile',
icon: 'uil:user',
},
],
},
{
title: 'server',
items: [
{
url: '/subscribe',
icon: 'uil:shop',
title: 'subscribe',
},
],
},
{
title: 'finance',
items: [
{
url: '/order',
icon: 'uil:notes',
title: 'order',
},
{
url: '/wallet',
icon: 'uil:wallet',
title: 'wallet',
},
],
},
{
title: 'help',
items: [
{
url: '/document',
icon: 'uil:book-alt',
title: 'document',
},
{
url: '/announcement',
icon: 'uil:megaphone',
title: 'announcement',
},
{
url: '/ticket',
icon: 'uil:message',
title: 'ticket',
},
],
},
];
export function findNavByUrl(url: string) {
for (const nav of navs) {
if (nav.url && nav.url === url) {
return [nav];
}
if (nav.items) {
const current = nav.items.find((item) => item.url === url);
if (current) {
return [nav, current];
}
}
}
return [];
}
export const navItems = [
{
url: '/profile',
icon: 'uil:user',
title: 'profile',
},
{
url: '/subscribe',
icon: 'uil:shop',
title: 'subscribe',
},
{
url: '/order',
icon: 'uil:notes',
title: 'order',
},
{
url: '/wallet',
icon: 'uil:wallet',
title: 'wallet',
},
];
+129
View File
@@ -0,0 +1,129 @@
import { NEXT_PUBLIC_API_URL, NEXT_PUBLIC_SITE_URL } from '@/config/constants';
import { queryUserInfo } from '@/services/user/user';
import { extractDomain } from '@repo/ui/utils';
import Base64 from 'crypto-js/enc-base64';
import UTF8 from 'crypto-js/enc-utf8';
import { create } from 'zustand';
interface ICommon extends API.GetGlobalConfigResponse {
background: string;
}
export interface GlobalStore {
common: ICommon;
user?: API.UserInfo;
setCommon: (common: Partial<ICommon>) => void;
setUser: (user?: API.UserInfo) => void;
getUserInfo: () => Promise<void>;
getUserSubscribe: (uuid: string, type?: string) => string[];
getAppSubLink: (type: string, url: string) => string;
}
export const useGlobalStore = create<GlobalStore>((set, get) => ({
common: {
background: '',
site: {
host: '',
site_name: '',
site_desc: '',
site_logo: '',
},
verify: {
enable_login_verify: false,
enable_register_verify: false,
enable_reset_password_verify: false,
turnstile_site_key: '',
},
register: {
stop_register: false,
enable_email_verify: false,
enable_email_domain_suffix: false,
email_domain_suffix_list: '',
},
invite: {
forced_invite: false,
},
currency: {
currency_unit: 'USD',
currency_symbol: '$',
},
subscribe: {
single_model: false,
subscribe_path: '',
subscribe_domain: '',
pan_domain: false,
},
},
user: undefined,
setCommon: (common) =>
set((state) => ({
common: {
...state.common,
...common,
},
})),
setUser: (user) => set({ user }),
getUserInfo: async () => {
try {
const { data } = await queryUserInfo();
set({ user: data.data });
} catch (error) {
console.error('Failed to refresh user:', error);
}
},
getUserSubscribe: (uuid: string, type?: string) => {
const { pan_domain, subscribe_domain, subscribe_path } = get().common.subscribe || {};
const domains = subscribe_domain
? subscribe_domain.split('\n')
: [extractDomain(NEXT_PUBLIC_API_URL || NEXT_PUBLIC_SITE_URL || '')];
return domains.map((domain) => {
const enc_type = type ? Base64.stringify(UTF8.parse(type)) : '';
const enc_uuid = Base64.stringify(UTF8.parse(uuid));
if (pan_domain) {
if (enc_type) return `https://${enc_type}.${enc_uuid}.${domain}`;
return `https://${enc_uuid}.${domain}`;
} else {
if (enc_type) return `https://${domain}${subscribe_path}?mark=${enc_uuid}&type=${enc_type}`;
return `https://${domain}${subscribe_path}?mark=${enc_uuid}`;
}
});
},
getAppSubLink: (type: string, url: string) => {
const name = get().common.site.site_name || '';
switch (type) {
// case 'Clash':
// return `clash://install-config?url=${url}&name=${name}`;
case 'Hiddify':
return `hiddify://import/${url}#${name}`;
case 'Loon':
return `loon://import?sub=${encodeURI(url)}${name}`;
case 'NekoBox':
return `sn://subscription?url=${url}&name=${name}`;
case 'NekoRay':
return `sn://subscription?url=${url}&name=${name}`;
// case 'Netch':
// return ``;
case 'Quantumult X':
return `quantumult-x://add-resource?remote-resource=${url}`;
case 'Shadowrocket':
return `shadowrocket://add/sub://${window.btoa(url)}?remark=${encodeURI(name)}`;
case 'Singbox':
return `sing-box://import-remote-profile?url=${encodeURI(url)}#${name}`;
case 'Surfboard':
return `surfboard:///install-config?url=${encodeURI(url)}`;
case 'Surge':
return `surge:///install-config?url=${encodeURI(url)}`;
case 'V2box':
return `v2box://install-sub?url=${encodeURI(url)}&name=${name}`;
case 'V2rayN':
return `v2rayn://install-sub?url=${encodeURI(url)}&name=${name}`;
case 'V2rayNg':
return `v2rayng://install-sub?url=${encodeURI(url)}&name=${name}`;
default:
return `clash://install-config?url=${encodeURI(url)}&name=${name}`;
}
},
}));
export default useGlobalStore;