feat: migrate styles to Tailwind CSS, remove unused files, and add new layout components
This commit is contained in:
parent
5b92932d82
commit
63941e41c3
94 changed files with 1051 additions and 2851 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -22,4 +22,6 @@ dist-ssr
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
output.sh
|
output.sh
|
||||||
|
.next
|
||||||
|
ui
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { UserAuthForm } from './components/user-auth-form';
|
import { UserAuthForm } from './components/user-auth-form';
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MessageList } from './message-list';
|
import { MessageList } from './message-list';
|
||||||
import { ChatInput } from './chat-input';
|
import { ChatInput } from './chat-input';
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { VideoPlayer } from './video-player';
|
import { VideoPlayer } from './video-player';
|
||||||
import { ImageViewer } from './image-viewer';
|
import { ImageViewer } from './image-viewer';
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useChat } from '../../providers/chat-provider';
|
import { useChat } from '../../providers/chat-provider';
|
||||||
import '../../styles/selector.css';
|
import '../../styles/selector.css';
|
|
@ -1,5 +1,6 @@
|
||||||
|
"use client";
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { soundAssets } from '../../../public/sounds/manifest';
|
import { soundAssets } from '../../../../public/sounds/manifest';
|
||||||
//import { cacheAssets } from '../lib/asset-loader';
|
//import { cacheAssets } from '../lib/asset-loader';
|
||||||
|
|
||||||
export function SoundInitializer({ children }: { children: React.ReactNode }) {
|
export function SoundInitializer({ children }: { children: React.ReactNode }) {
|
|
@ -4,7 +4,7 @@ import { ChatLayout } from './components/chat-layout';
|
||||||
import { SoundInitializer } from './components/sound-initializer';
|
import { SoundInitializer } from './components/sound-initializer';
|
||||||
import { SoundProvider } from './providers/sound-provider';
|
import { SoundProvider } from './providers/sound-provider';
|
||||||
|
|
||||||
export function Chat() {
|
export default function Chat() {
|
||||||
return (
|
return (
|
||||||
<SoundInitializer>
|
<SoundInitializer>
|
||||||
<SoundProvider>
|
<SoundProvider>
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||||
import { core } from '@tauri-apps/api';
|
import { core } from '@tauri-apps/api';
|
||||||
import { User, ChatInstance } from '../types';
|
import { User, ChatInstance } from '../types';
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import React, { createContext, useContext, useCallback } from 'react';
|
import React, { createContext, useContext, useCallback } from 'react';
|
||||||
import { core } from '@tauri-apps/api';
|
import { core } from '@tauri-apps/api';
|
||||||
|
|
36
app/client-nav.tsx
Normal file
36
app/client-nav.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { usePathname, useRouter } from 'next/navigation';
|
||||||
|
import { Button } from '../src/components/ui/button';
|
||||||
|
|
||||||
|
const examples = [
|
||||||
|
{ name: "Home", href: "/authentication" },
|
||||||
|
{ name: "Dashboard", href: "/dashboard" },
|
||||||
|
{ name: "Chat", href: "/chat" },
|
||||||
|
{ name: "Mail", href: "/mail" },
|
||||||
|
{ name: "Drive", href: "/drive" },
|
||||||
|
{ name: "Tasks", href: "/tasks" },
|
||||||
|
{ name: "Templates", href: "/templates" },
|
||||||
|
{ name: "Settings", href: "/sync" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export function Nav() {
|
||||||
|
const pathname = usePathname();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="examples-nav-container">
|
||||||
|
<div className="examples-nav-inner">
|
||||||
|
{examples.map((example) => (
|
||||||
|
<Button
|
||||||
|
key={example.href}
|
||||||
|
onClick={() => router.push(example.href)}
|
||||||
|
className={`example-button ${pathname === example.href ? 'active' : ''}`}
|
||||||
|
>
|
||||||
|
{example.name}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
const groups = [
|
const groups = [
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
export function UserNav() {
|
export function UserNav() {
|
|
@ -1,9 +1,10 @@
|
||||||
|
"use client";
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FileTree } from './components/FileTree';
|
import { FileTree } from './components/FileTree';
|
||||||
import { FileBrowser } from './components/FileBrowser';
|
import { FileBrowser } from './components/FileBrowser';
|
||||||
import { FileOperations } from './components/FileOperations';
|
import { FileOperations } from './components/FileOperations';
|
||||||
|
|
||||||
export function DriveScreen() {
|
export default function DriveScreen() {
|
||||||
const [currentPath, setCurrentPath] = useState('');
|
const [currentPath, setCurrentPath] = useState('');
|
||||||
const [refreshKey, setRefreshKey] = useState(0);
|
const [refreshKey, setRefreshKey] = useState(0);
|
||||||
|
|
17
app/layout.tsx
Normal file
17
app/layout.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { Nav } from './client-nav';
|
||||||
|
import './globals.css';
|
||||||
|
|
||||||
|
import './globals.css' // This path is correct if the file is in your src/app directory
|
||||||
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
|
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body>
|
||||||
|
<Nav />
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ import {
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip"
|
} from "@/components/ui/tooltip"
|
||||||
import { Mail } from "@/mail/data"
|
import { Mail } from "./data"
|
||||||
|
|
||||||
interface MailDisplayProps {
|
interface MailDisplayProps {
|
||||||
mail: Mail | null
|
mail: Mail | null
|
|
@ -4,8 +4,8 @@ import formatDistanceToNow from "date-fns/formatDistanceToNow"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area"
|
import { ScrollArea } from "@/components/ui/scroll-area"
|
||||||
import { Mail } from "@/mail/data"
|
import { Mail } from "../data"
|
||||||
import { useMail } from "@/mail/use-mail"
|
import { useMail } from "../use-mail"
|
||||||
|
|
||||||
interface MailListProps {
|
interface MailListProps {
|
||||||
items: Mail[]
|
items: Mail[]
|
|
@ -30,12 +30,12 @@ import {
|
||||||
TabsTrigger,
|
TabsTrigger,
|
||||||
} from "@/components/ui/tabs"
|
} from "@/components/ui/tabs"
|
||||||
import { TooltipProvider } from "@/components/ui/tooltip"
|
import { TooltipProvider } from "@/components/ui/tooltip"
|
||||||
import { AccountSwitcher } from "@/mail/components/account-switcher"
|
import { AccountSwitcher } from "./account-switcher"
|
||||||
import { MailDisplay } from "@/mail/components/mail-display"
|
import { MailDisplay } from "./mail-display"
|
||||||
import { MailList } from "@/mail/components/mail-list"
|
import { MailList } from "./mail-list"
|
||||||
import { Nav } from "@/mail/components/nav"
|
import { Nav } from "./nav"
|
||||||
import { type Mail } from "@/mail/data"
|
import { type Mail } from "../data"
|
||||||
import { useMail } from "@/mail/use-mail"
|
import { useMail } from "../use-mail"
|
||||||
|
|
||||||
interface MailProps {
|
interface MailProps {
|
||||||
accounts: {
|
accounts: {
|
|
@ -1,6 +1,7 @@
|
||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Link } from 'lucide-react';
|
import NextLink from 'next/link'; // Changed from lucide-react
|
||||||
|
import { Link as LinkIcon } from 'lucide-react'; // Renamed to avoid conflict
|
||||||
import { LucideIcon } from "lucide-react"
|
import { LucideIcon } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
@ -32,7 +33,7 @@ export function Nav({ links, isCollapsed }: NavProps) {
|
||||||
isCollapsed ? (
|
isCollapsed ? (
|
||||||
<Tooltip key={index} delayDuration={0}>
|
<Tooltip key={index} delayDuration={0}>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Link
|
<NextLink
|
||||||
href="#"
|
href="#"
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({ variant: link.variant, size: "icon" }),
|
buttonVariants({ variant: link.variant, size: "icon" }),
|
||||||
|
@ -43,7 +44,7 @@ export function Nav({ links, isCollapsed }: NavProps) {
|
||||||
>
|
>
|
||||||
<link.icon className="h-4 w-4" />
|
<link.icon className="h-4 w-4" />
|
||||||
<span className="sr-only">{link.title}</span>
|
<span className="sr-only">{link.title}</span>
|
||||||
</Link>
|
</NextLink>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="right" className="flex items-center gap-4">
|
<TooltipContent side="right" className="flex items-center gap-4">
|
||||||
{link.title}
|
{link.title}
|
||||||
|
@ -55,7 +56,7 @@ export function Nav({ links, isCollapsed }: NavProps) {
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<NextLink
|
||||||
key={index}
|
key={index}
|
||||||
href="#"
|
href="#"
|
||||||
className={cn(
|
className={cn(
|
||||||
|
@ -78,10 +79,10 @@ export function Nav({ links, isCollapsed }: NavProps) {
|
||||||
{link.label}
|
{link.label}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</NextLink>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
27
app/mail/page.tsx
Normal file
27
app/mail/page.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import Image from "next/image"
|
||||||
|
|
||||||
|
import { Mail } from "./components/mail"
|
||||||
|
import { accounts, mails } from "./data"
|
||||||
|
|
||||||
|
export default function MailPage() {
|
||||||
|
const layout = [20, 32, 48]; //cookies().get("react-resizable-panels:layout:mail")
|
||||||
|
const collapsed = false; //cookies().get("react-resizable-panels:collapsed")
|
||||||
|
|
||||||
|
const defaultLayout = layout// ? JSON.parse(layout.value) : undefined
|
||||||
|
const defaultCollapsed = collapsed //? JSON.parse(collapsed.value) : undefined
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex-col md:flex">
|
||||||
|
<Mail
|
||||||
|
accounts={accounts}
|
||||||
|
mails={mails}
|
||||||
|
defaultLayout={defaultLayout}
|
||||||
|
defaultCollapsed={defaultCollapsed}
|
||||||
|
navCollapsedSize={4}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { atom, useAtom } from "jotai"
|
import { atom, useAtom } from "jotai"
|
||||||
|
|
||||||
import { Mail, mails } from "@/mail/data"
|
import { Mail, mails } from "./data"
|
||||||
|
|
||||||
type Config = {
|
type Config = {
|
||||||
selected: Mail["id"] | null
|
selected: Mail["id"] | null
|
9
app/page.tsx
Normal file
9
app/page.tsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// app/page.tsx (your home page)
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen p-8">
|
||||||
|
<h1 className="text-3xl font-bold">Welcome to My Tauri App</h1>
|
||||||
|
<p className="mt-4">This is your home page</p>
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
"use client";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Task } from '../data/schema';
|
import { Task } from '../data/schema';
|
||||||
import { labels, priorities, statuses } from '../data/data';
|
import { labels, priorities, statuses } from '../data/data';
|
|
@ -1,7 +0,0 @@
|
||||||
module.exports = function (api) {
|
|
||||||
api.cache(true);
|
|
||||||
return {
|
|
||||||
|
|
||||||
plugins: ['nativewind/babel']
|
|
||||||
};
|
|
||||||
};
|
|
12
gbclient.code-workspace
Normal file
12
gbclient.code-workspace
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ui",
|
||||||
|
"path": "../../ui"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
5
next-env.d.ts
vendored
Normal file
5
next-env.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
7
next.config.js
Normal file
7
next.config.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
output: 'export',
|
||||||
|
images: { unoptimized: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = nextConfig
|
1023
package-lock.json
generated
1023
package-lock.json
generated
File diff suppressed because it is too large
Load diff
20
package.json
20
package.json
|
@ -2,16 +2,15 @@
|
||||||
"name": "gbclient",
|
"name": "gbclient",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npx tailwindcss -i ./src/styles/globals.css -o ./public/output.css;ESBUILD_RUNNER=true vite",
|
"dev": "npx tailwindcss -i ./src/styles/globals.css -o ./public/output.css;ESBUILD_RUNNER=true next dev",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && next build",
|
||||||
"preview": "vite preview",
|
"start": "next start",
|
||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.26.0",
|
|
||||||
"@hookform/resolvers": "^3.9.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
|
"@next/font": "^14.2.15",
|
||||||
"@radix-ui/react-accordion": "^1.2.3",
|
"@radix-ui/react-accordion": "^1.2.3",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-aspect-ratio": "^1.1.2",
|
"@radix-ui/react-aspect-ratio": "^1.1.2",
|
||||||
|
@ -52,6 +51,7 @@
|
||||||
"jotai": "^2.12.2",
|
"jotai": "^2.12.2",
|
||||||
"lucide-react": "0.454.0",
|
"lucide-react": "0.454.0",
|
||||||
"nativewind": "2.0.10",
|
"nativewind": "2.0.10",
|
||||||
|
"next": "^15.2.4",
|
||||||
"postcss": "8.4.35",
|
"postcss": "8.4.35",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
|
@ -59,21 +59,18 @@
|
||||||
"react-hook-form": "^7.53.2",
|
"react-hook-form": "^7.53.2",
|
||||||
"react-markdown": "10.1.0",
|
"react-markdown": "10.1.0",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
"react-router-dom": "7.4.1",
|
|
||||||
"tailwind-merge": "3.0.2",
|
"tailwind-merge": "3.0.2",
|
||||||
"tailwindcss-animate": "1.0.7",
|
"tailwindcss-animate": "1.0.7",
|
||||||
"uuid": "11.0.3",
|
"uuid": "11.0.3",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.18.6",
|
|
||||||
"@tauri-apps/cli": "2",
|
"@tauri-apps/cli": "2",
|
||||||
"@types/jest": "29.5.12",
|
"@types/jest": "29.5.12",
|
||||||
"@types/node": "22.13.14",
|
"@types/node": "22.13.14",
|
||||||
"@types/react": "18.3.1",
|
"@types/react": "^18.3.1",
|
||||||
"@types/react-dom": "18.3.1",
|
"@types/react-dom": "^18.3.1",
|
||||||
"@types/react-test-renderer": "18.0.7",
|
"@types/react-test-renderer": "18.0.7",
|
||||||
"@vitejs/plugin-react": "4.3.4",
|
|
||||||
"copy-webpack-plugin": "12.0.2",
|
"copy-webpack-plugin": "12.0.2",
|
||||||
"esbuild-runner": "2.2.2",
|
"esbuild-runner": "2.2.2",
|
||||||
"jest": "29.2.1",
|
"jest": "29.2.1",
|
||||||
|
@ -81,7 +78,6 @@
|
||||||
"postcss-load-config": "6.0.1",
|
"postcss-load-config": "6.0.1",
|
||||||
"react-test-renderer": "18.2.0",
|
"react-test-renderer": "18.2.0",
|
||||||
"tailwindcss": "3.1.8",
|
"tailwindcss": "3.1.8",
|
||||||
"typescript": "5.6.2",
|
"typescript": "5.6.2"
|
||||||
"vite": "6.0.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2296
public/output.css
2296
public/output.css
File diff suppressed because it is too large
Load diff
|
@ -4,11 +4,10 @@
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"identifier": "online.generalbots",
|
"identifier": "online.generalbots",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "pnpm dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
"devUrl": "http://localhost:1420",
|
"devUrl": "http://localhost:1420",
|
||||||
"beforeBuildCommand": "pnpm build",
|
"beforeBuildCommand": "npm run build",
|
||||||
"frontendDist": "../dist"
|
"frontendDist": "../out"
|
||||||
|
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"withGlobalTauri": true,
|
"withGlobalTauri": true,
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import '../../styles/ui.css';
|
|
||||||
|
|
||||||
const EMOJI_CATEGORIES = {
|
|
||||||
"😀 🎮": ["😀", "😎", "🤖", "👾", "🎮", "✨", "🚀", "💫"],
|
|
||||||
"🌟 💫": ["⭐", "🌟", "💫", "✨", "⚡", "💥", "🔥", "🌈"],
|
|
||||||
"🤖 🎯": ["🤖", "🎯", "🎲", "🎮", "🕹️", "👾", "💻", "⌨️"]
|
|
||||||
};
|
|
||||||
|
|
||||||
export function EmojiPicker({ visible, onClose, onEmojiSelect }: {
|
|
||||||
visible: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
onEmojiSelect: (emoji: string) => void;
|
|
||||||
}) {
|
|
||||||
if (!visible) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="emoji-picker-modal">
|
|
||||||
<div className="emoji-picker-header">
|
|
||||||
<h3>Select Emoji</h3>
|
|
||||||
<button onClick={onClose} className="close-button">
|
|
||||||
<svg viewBox="0 0 24 24">
|
|
||||||
<path d="M18 6L6 18M6 6l12 12"/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="emoji-picker-content">
|
|
||||||
{Object.entries(EMOJI_CATEGORIES).map(([category, emojis]) => (
|
|
||||||
<div key={category} className="emoji-category">
|
|
||||||
<h4 className="category-title">{category}</h4>
|
|
||||||
<div className="emoji-grid">
|
|
||||||
{emojis.map(emoji => (
|
|
||||||
<button
|
|
||||||
key={emoji}
|
|
||||||
className="emoji-button"
|
|
||||||
onClick={() => {
|
|
||||||
onEmojiSelect(emoji);
|
|
||||||
onClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{emoji}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { useSound } from '../../providers/sound-provider';
|
|
||||||
import '../../styles/ui.css';
|
|
||||||
|
|
||||||
export function SettingsPanel() {
|
|
||||||
const [theme, setTheme] = React.useState('dark');
|
|
||||||
const [sound, setSound] = React.useState(true);
|
|
||||||
const [powerMode, setPowerMode] = React.useState(false);
|
|
||||||
const { setEnabled, playSound } = useSound();
|
|
||||||
|
|
||||||
const handleSoundToggle = (value: boolean) => {
|
|
||||||
setSound(value);
|
|
||||||
setEnabled(value);
|
|
||||||
if (value) {
|
|
||||||
playSound('success');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleThemeChange = () => {
|
|
||||||
playSound('click');
|
|
||||||
setTheme(theme === 'dark' ? 'light' : 'dark');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePowerMode = (value: boolean) => {
|
|
||||||
playSound(value ? 'success' : 'click');
|
|
||||||
setPowerMode(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="settings-panel">
|
|
||||||
<div className="settings-option">
|
|
||||||
{sound ? (
|
|
||||||
<svg className="icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M3 15a1 1 0 011-1h2.83a1 1 0 00.8-.4l1.12-1.5a1 1 0 01.8-.4h3.55a1 1 0 00.8-.4l1.12-1.5a1 1 0 01.8-.4H19a1 1 0 011 1v6a1 1 0 01-1 1h-2.83a1 1 0 00-.8-.4l-1.12-1.5a1 1 0 00-.8-.4H9.72a1 1 0 01-.8-.4l-1.12-1.5a1 1 0 00-.8-.4H4a1 1 0 01-1-1v-2zM12 6a1 1 0 011-1h6a1 1 0 011 1v3"/>
|
|
||||||
</svg>
|
|
||||||
) : (
|
|
||||||
<svg className="icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M3 15a1 1 0 011-1h2.83a1 1 0 00.8-.4l1.12-1.5a1 1 0 01.8-.4h3.55a1 1 0 00.8-.4l1.12-1.5a1 1 0 01.8-.4H19a1 1 0 011 1v6a1 1 0 01-1 1h-2.83a1 1 0 00-.8-.4l-1.12-1.5a1 1 0 00-.8-.4H9.72a1 1 0 01-.8-.4l-1.12-1.5a1 1 0 00-.8-.4H4a1 1 0 01-1-1v-2zM12 6a1 1 0 011-1h6a1 1 0 011 1v3M3 3l18 18"/>
|
|
||||||
</svg>
|
|
||||||
)}
|
|
||||||
<span className="option-text">Sound Effects</span>
|
|
||||||
<label className="switch">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={sound}
|
|
||||||
onChange={(e) => handleSoundToggle(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<span className="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
|
||||||
import AuthenticationScreen from './authentication';
|
|
||||||
import { Chat } from './chat';
|
|
||||||
|
|
||||||
import DashboardPage from './dashboard';
|
|
||||||
import TaskPage from './tasks';
|
|
||||||
import TemplatesPage from './templates';
|
|
||||||
import { DriveScreen } from './drive';
|
|
||||||
import SyncPage from './sync/page';
|
|
||||||
import { Button } from './components/ui/button';
|
|
||||||
import MailPage from './mail';
|
|
||||||
|
|
||||||
const examples = [
|
|
||||||
{ name: "Home", href: "authentication" },
|
|
||||||
{ name: "Dashboard", href: "dashboard" },
|
|
||||||
{ name: "Chat", href: "chat" },
|
|
||||||
{ name: "Mail", href: "mail" },
|
|
||||||
{ name: "Drive", href: "drive" },
|
|
||||||
{ name: "Tasks", href: "tasks" },
|
|
||||||
{ name: "Meet", href: "meet" },
|
|
||||||
{ name: "Templates", href: "templates" },
|
|
||||||
{ name: "Settings", href: "sync" },
|
|
||||||
{ name: "Help", href: "help" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const ExamplesNav = () => {
|
|
||||||
const location = useLocation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="examples-nav-container">
|
|
||||||
<div className="examples-nav-inner">
|
|
||||||
{examples.map((example) => (
|
|
||||||
<Button
|
|
||||||
key={example.href}
|
|
||||||
onClick={() => navigate(example.href)}
|
|
||||||
className={`example-button ${location.pathname.includes(example.href) ? 'active' : ''
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{example.name}
|
|
||||||
</Button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export function RootLayout() {
|
|
||||||
return (
|
|
||||||
<div className="app-container">
|
|
||||||
<ExamplesNav />
|
|
||||||
<main className="app-main">
|
|
||||||
<Routes>
|
|
||||||
<Route path="authentication" element={
|
|
||||||
<>
|
|
||||||
<AuthenticationScreen />
|
|
||||||
</>
|
|
||||||
} />
|
|
||||||
<Route path="chat" element={
|
|
||||||
<>
|
|
||||||
<Chat />
|
|
||||||
|
|
||||||
</>
|
|
||||||
} />
|
|
||||||
<Route path="dashboard" element={
|
|
||||||
<>
|
|
||||||
<DashboardPage />
|
|
||||||
|
|
||||||
</>
|
|
||||||
} />
|
|
||||||
<Route path="mail" element={
|
|
||||||
<>
|
|
||||||
<MailPage />
|
|
||||||
|
|
||||||
</>
|
|
||||||
} />
|
|
||||||
<Route path="drive" element={<DriveScreen />} />
|
|
||||||
<Route path="tasks" element={
|
|
||||||
<>
|
|
||||||
<TaskPage />
|
|
||||||
|
|
||||||
</>
|
|
||||||
} />
|
|
||||||
<Route path="meet" element={<div>Meet Screen (Placeholder)</div>} />
|
|
||||||
<Route path="templates" element={
|
|
||||||
<>
|
|
||||||
<TemplatesPage />
|
|
||||||
|
|
||||||
</>
|
|
||||||
} />
|
|
||||||
<Route path="sync" element={<SyncPage />} />
|
|
||||||
</Routes>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RootLayout;
|
|
25
src/lib/client-cookies.ts
Normal file
25
src/lib/client-cookies.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
export function getClientCookie(key: string): string | null {
|
||||||
|
if (typeof document === 'undefined') return null;
|
||||||
|
|
||||||
|
const value = document.cookie
|
||||||
|
.split('; ')
|
||||||
|
.find(row => row.startsWith(`${key}=`))
|
||||||
|
?.split('=')[1];
|
||||||
|
|
||||||
|
return value ? decodeURIComponent(value) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setClientCookie(
|
||||||
|
key: string,
|
||||||
|
value: string,
|
||||||
|
options: { expires?: Date; path?: string } = {}
|
||||||
|
): void {
|
||||||
|
if (typeof document === 'undefined') return;
|
||||||
|
|
||||||
|
let cookie = `${key}=${encodeURIComponent(value)}`;
|
||||||
|
if (options.expires) cookie += `; expires=${options.expires.toUTCString()}`;
|
||||||
|
cookie += `; path=${options.path || '/'}`;
|
||||||
|
document.cookie = cookie;
|
||||||
|
}
|
11
src/lib/server-cookies.tsx
Normal file
11
src/lib/server-cookies.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
'use server';
|
||||||
|
|
||||||
|
import { cookies } from 'next/headers';
|
||||||
|
|
||||||
|
export async function getServerCookie(key: string): Promise<string | undefined> {
|
||||||
|
// This will only run during SSR, not during static export
|
||||||
|
if (process.env.NEXT_PHASE === 'phase-production-build') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return cookies().get(key)?.value;
|
||||||
|
}
|
|
@ -1,48 +0,0 @@
|
||||||
import { useState, useEffect } from "react";
|
|
||||||
|
|
||||||
import { Mail } from "@/mail/components/mail";
|
|
||||||
import { accounts, mails } from "@/mail/data";
|
|
||||||
|
|
||||||
export default function MailPage() {
|
|
||||||
const [defaultLayout, setDefaultLayout] = useState(undefined);
|
|
||||||
const [defaultCollapsed, setDefaultCollapsed] = useState(undefined);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// In Vite/React, we'll use localStorage instead of cookies
|
|
||||||
const layout = localStorage.getItem("react-resizable-panels:layout:mail");
|
|
||||||
const collapsed = localStorage.getItem("react-resizable-panels:collapsed:mail");
|
|
||||||
|
|
||||||
if (layout) setDefaultLayout(JSON.parse(layout));
|
|
||||||
if (collapsed) setDefaultCollapsed(JSON.parse(collapsed));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="md:hidden">
|
|
||||||
<img
|
|
||||||
src="/examples/mail-dark.png"
|
|
||||||
width={1280}
|
|
||||||
height={727}
|
|
||||||
alt="Mail"
|
|
||||||
className="dark:block"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
src="/examples/mail-light.png"
|
|
||||||
width={1280}
|
|
||||||
height={727}
|
|
||||||
alt="Mail"
|
|
||||||
className="block dark:hidden"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex-col md:flex">
|
|
||||||
<Mail
|
|
||||||
accounts={accounts}
|
|
||||||
mails={mails}
|
|
||||||
defaultLayout={defaultLayout}
|
|
||||||
defaultCollapsed={defaultCollapsed}
|
|
||||||
navCollapsedSize={4}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
13
src/main.tsx
13
src/main.tsx
|
@ -1,13 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import ReactDOM from 'react-dom/client'
|
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
|
||||||
import RootLayout from ".";
|
|
||||||
import './styles/globals.css' // or your CSS file path
|
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
|
||||||
<React.StrictMode>
|
|
||||||
<BrowserRouter>
|
|
||||||
<RootLayout />
|
|
||||||
</BrowserRouter>
|
|
||||||
</React.StrictMode>
|
|
||||||
)
|
|
1
src/vite-env.d.ts
vendored
1
src/vite-env.d.ts
vendored
|
@ -1 +0,0 @@
|
||||||
/// <reference types="vite/client" />
|
|
|
@ -2,9 +2,11 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
"ES2020",
|
"ES2020",
|
||||||
|
@ -19,19 +21,33 @@
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "preserve",
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"incremental": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src"
|
"src",
|
||||||
],
|
|
||||||
|
".next/types/**/*.ts"
|
||||||
|
, "app" ],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "./tsconfig.node.json"
|
"path": "./tsconfig.node.json"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"src-rust"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
import { defineConfig } from "vite";
|
|
||||||
import react from "@vitejs/plugin-react";
|
|
||||||
import path from "path";
|
|
||||||
import tailwindcss from "@tailwindcss/vite"
|
|
||||||
|
|
||||||
// @ts-expect-error process is a nodejs global
|
|
||||||
const host = process.env.TAURI_DEV_HOST;
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig(async () => ({
|
|
||||||
|
|
||||||
plugins: [react(),tailwindcss()],
|
|
||||||
css: {
|
|
||||||
postcss: {
|
|
||||||
config: false // Disable auto-loading of postcss.config.js
|
|
||||||
} as any
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
"@": path.resolve(__dirname, "./src"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
|
||||||
//
|
|
||||||
// 1. prevent vite from obscuring rust errors
|
|
||||||
clearScreen: false,
|
|
||||||
// 2. tauri expects a fixed port, fail if that port is not available
|
|
||||||
server: {
|
|
||||||
port: 1420,
|
|
||||||
strictPort: true,
|
|
||||||
host: host || false,
|
|
||||||
hmr: host
|
|
||||||
? {
|
|
||||||
protocol: "ws",
|
|
||||||
host,
|
|
||||||
port: 1421,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
watch: {
|
|
||||||
// 3. tell vite to ignore watching `src-rust`
|
|
||||||
ignored: ["**/src-rust/**"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
Loading…
Add table
Reference in a new issue