Spaces:
Runtime error
Runtime error
starsnatched
commited on
Commit
·
c4aea9f
1
Parent(s):
95aeb25
Remove frontend codebase including components, styles, and configuration files
Browse files- frontend/.gitignore +0 -24
- frontend/README.md +0 -12
- frontend/eslint.config.js +0 -33
- frontend/index.html +0 -19
- frontend/package-lock.json +0 -0
- frontend/package.json +0 -28
- frontend/public/vite.svg +0 -1
- frontend/src/App.css +0 -42
- frontend/src/App.jsx +0 -8
- frontend/src/api.js +0 -23
- frontend/src/assets/react.svg +0 -1
- frontend/src/components/ChatWindow.jsx +0 -63
- frontend/src/components/InputBar.jsx +0 -31
- frontend/src/components/MessageBubble.jsx +0 -13
- frontend/src/components/MessageList.jsx +0 -23
- frontend/src/components/SessionList.jsx +0 -24
- frontend/src/components/UsernameForm.jsx +0 -32
- frontend/src/index.css +0 -47
- frontend/src/main.jsx +0 -10
- frontend/src/styles/chat.css +0 -167
- frontend/vite.config.js +0 -7
frontend/.gitignore
DELETED
@@ -1,24 +0,0 @@
|
|
1 |
-
# Logs
|
2 |
-
logs
|
3 |
-
*.log
|
4 |
-
npm-debug.log*
|
5 |
-
yarn-debug.log*
|
6 |
-
yarn-error.log*
|
7 |
-
pnpm-debug.log*
|
8 |
-
lerna-debug.log*
|
9 |
-
|
10 |
-
node_modules
|
11 |
-
dist
|
12 |
-
dist-ssr
|
13 |
-
*.local
|
14 |
-
|
15 |
-
# Editor directories and files
|
16 |
-
.vscode/*
|
17 |
-
!.vscode/extensions.json
|
18 |
-
.idea
|
19 |
-
.DS_Store
|
20 |
-
*.suo
|
21 |
-
*.ntvs*
|
22 |
-
*.njsproj
|
23 |
-
*.sln
|
24 |
-
*.sw?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/README.md
DELETED
@@ -1,12 +0,0 @@
|
|
1 |
-
# React + Vite
|
2 |
-
|
3 |
-
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
4 |
-
|
5 |
-
Currently, two official plugins are available:
|
6 |
-
|
7 |
-
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
8 |
-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
9 |
-
|
10 |
-
## Expanding the ESLint configuration
|
11 |
-
|
12 |
-
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/eslint.config.js
DELETED
@@ -1,33 +0,0 @@
|
|
1 |
-
import js from '@eslint/js'
|
2 |
-
import globals from 'globals'
|
3 |
-
import reactHooks from 'eslint-plugin-react-hooks'
|
4 |
-
import reactRefresh from 'eslint-plugin-react-refresh'
|
5 |
-
|
6 |
-
export default [
|
7 |
-
{ ignores: ['dist'] },
|
8 |
-
{
|
9 |
-
files: ['**/*.{js,jsx}'],
|
10 |
-
languageOptions: {
|
11 |
-
ecmaVersion: 2020,
|
12 |
-
globals: globals.browser,
|
13 |
-
parserOptions: {
|
14 |
-
ecmaVersion: 'latest',
|
15 |
-
ecmaFeatures: { jsx: true },
|
16 |
-
sourceType: 'module',
|
17 |
-
},
|
18 |
-
},
|
19 |
-
plugins: {
|
20 |
-
'react-hooks': reactHooks,
|
21 |
-
'react-refresh': reactRefresh,
|
22 |
-
},
|
23 |
-
rules: {
|
24 |
-
...js.configs.recommended.rules,
|
25 |
-
...reactHooks.configs.recommended.rules,
|
26 |
-
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
27 |
-
'react-refresh/only-export-components': [
|
28 |
-
'warn',
|
29 |
-
{ allowConstantExport: true },
|
30 |
-
],
|
31 |
-
},
|
32 |
-
},
|
33 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/index.html
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
<!doctype html>
|
2 |
-
<html lang="en">
|
3 |
-
<head>
|
4 |
-
<meta charset="UTF-8" />
|
5 |
-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6 |
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
7 |
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
8 |
-
<link
|
9 |
-
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap"
|
10 |
-
rel="stylesheet"
|
11 |
-
/>
|
12 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
13 |
-
<title>LLM Chat</title>
|
14 |
-
</head>
|
15 |
-
<body>
|
16 |
-
<div id="root"></div>
|
17 |
-
<script type="module" src="/src/main.jsx"></script>
|
18 |
-
</body>
|
19 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/package-lock.json
DELETED
The diff for this file is too large to render.
See raw diff
|
|
frontend/package.json
DELETED
@@ -1,28 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"name": "frontend",
|
3 |
-
"private": true,
|
4 |
-
"version": "0.0.0",
|
5 |
-
"type": "module",
|
6 |
-
"scripts": {
|
7 |
-
"dev": "vite",
|
8 |
-
"build": "vite build",
|
9 |
-
"lint": "eslint .",
|
10 |
-
"preview": "vite preview"
|
11 |
-
},
|
12 |
-
"dependencies": {
|
13 |
-
"prop-types": "^15.8.1",
|
14 |
-
"react": "^19.1.0",
|
15 |
-
"react-dom": "^19.1.0"
|
16 |
-
},
|
17 |
-
"devDependencies": {
|
18 |
-
"@eslint/js": "^9.25.0",
|
19 |
-
"@types/react": "^19.1.2",
|
20 |
-
"@types/react-dom": "^19.1.2",
|
21 |
-
"@vitejs/plugin-react": "^4.4.1",
|
22 |
-
"eslint": "^9.25.0",
|
23 |
-
"eslint-plugin-react-hooks": "^5.2.0",
|
24 |
-
"eslint-plugin-react-refresh": "^0.4.19",
|
25 |
-
"globals": "^16.0.0",
|
26 |
-
"vite": "^6.3.5"
|
27 |
-
}
|
28 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/public/vite.svg
DELETED
frontend/src/App.css
DELETED
@@ -1,42 +0,0 @@
|
|
1 |
-
#root {
|
2 |
-
max-width: 1280px;
|
3 |
-
margin: 0 auto;
|
4 |
-
padding: 2rem;
|
5 |
-
text-align: center;
|
6 |
-
}
|
7 |
-
|
8 |
-
.logo {
|
9 |
-
height: 6em;
|
10 |
-
padding: 1.5em;
|
11 |
-
will-change: filter;
|
12 |
-
transition: filter 300ms;
|
13 |
-
}
|
14 |
-
.logo:hover {
|
15 |
-
filter: drop-shadow(0 0 2em #646cffaa);
|
16 |
-
}
|
17 |
-
.logo.react:hover {
|
18 |
-
filter: drop-shadow(0 0 2em #61dafbaa);
|
19 |
-
}
|
20 |
-
|
21 |
-
@keyframes logo-spin {
|
22 |
-
from {
|
23 |
-
transform: rotate(0deg);
|
24 |
-
}
|
25 |
-
to {
|
26 |
-
transform: rotate(360deg);
|
27 |
-
}
|
28 |
-
}
|
29 |
-
|
30 |
-
@media (prefers-reduced-motion: no-preference) {
|
31 |
-
a:nth-of-type(2) .logo {
|
32 |
-
animation: logo-spin infinite 20s linear;
|
33 |
-
}
|
34 |
-
}
|
35 |
-
|
36 |
-
.card {
|
37 |
-
padding: 2em;
|
38 |
-
}
|
39 |
-
|
40 |
-
.read-the-docs {
|
41 |
-
color: #888;
|
42 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/App.jsx
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
import ChatWindow from './components/ChatWindow'
|
2 |
-
import './index.css'
|
3 |
-
|
4 |
-
function App() {
|
5 |
-
return <ChatWindow />
|
6 |
-
}
|
7 |
-
|
8 |
-
export default App
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/api.js
DELETED
@@ -1,23 +0,0 @@
|
|
1 |
-
const API_BASE = import.meta.env.VITE_API_BASE || 'http://localhost:8000';
|
2 |
-
|
3 |
-
export async function fetchStream(user, session, prompt, onChunk) {
|
4 |
-
const res = await fetch(`${API_BASE}/chat/stream`, {
|
5 |
-
method: 'POST',
|
6 |
-
headers: { 'Content-Type': 'application/json' },
|
7 |
-
body: JSON.stringify({ user, session, prompt }),
|
8 |
-
});
|
9 |
-
const reader = res.body.getReader();
|
10 |
-
const decoder = new TextDecoder();
|
11 |
-
while (true) {
|
12 |
-
const { value, done } = await reader.read();
|
13 |
-
if (done) break;
|
14 |
-
onChunk(decoder.decode(value));
|
15 |
-
}
|
16 |
-
}
|
17 |
-
|
18 |
-
export async function fetchSessions(user) {
|
19 |
-
const res = await fetch(`${API_BASE}/sessions/${encodeURIComponent(user)}`);
|
20 |
-
if (!res.ok) return [];
|
21 |
-
const data = await res.json();
|
22 |
-
return data.sessions ?? [];
|
23 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/assets/react.svg
DELETED
frontend/src/components/ChatWindow.jsx
DELETED
@@ -1,63 +0,0 @@
|
|
1 |
-
import { useEffect, useState } from 'react'
|
2 |
-
import MessageList from './MessageList'
|
3 |
-
import InputBar from './InputBar'
|
4 |
-
import SessionList from './SessionList'
|
5 |
-
import UsernameForm from './UsernameForm'
|
6 |
-
import '../styles/chat.css'
|
7 |
-
import { fetchStream, fetchSessions } from '../api'
|
8 |
-
|
9 |
-
function ChatWindow() {
|
10 |
-
const [messages, setMessages] = useState([])
|
11 |
-
const [sessionName] = useState(() => crypto.randomUUID())
|
12 |
-
const [sessions, setSessions] = useState([])
|
13 |
-
const [username, setUsername] = useState(() =>
|
14 |
-
localStorage.getItem('username') || ''
|
15 |
-
)
|
16 |
-
|
17 |
-
useEffect(() => {
|
18 |
-
if (username) {
|
19 |
-
fetchSessions(username).then(setSessions)
|
20 |
-
}
|
21 |
-
}, [username])
|
22 |
-
|
23 |
-
const refreshSessions = () => {
|
24 |
-
if (username) {
|
25 |
-
fetchSessions(username).then(setSessions)
|
26 |
-
}
|
27 |
-
}
|
28 |
-
|
29 |
-
const sendMessage = async (text) => {
|
30 |
-
const userMsg = { role: 'user', content: text }
|
31 |
-
setMessages((prev) => [...prev, userMsg, { role: 'assistant', content: '' }])
|
32 |
-
const index = messages.length + 1
|
33 |
-
await fetchStream(username, sessionName, text, (chunk) => {
|
34 |
-
setMessages((prev) => {
|
35 |
-
const copy = [...prev]
|
36 |
-
copy[index] = { ...copy[index], content: copy[index].content + chunk }
|
37 |
-
return copy
|
38 |
-
})
|
39 |
-
})
|
40 |
-
refreshSessions()
|
41 |
-
}
|
42 |
-
|
43 |
-
const handleUsernameSet = (name) => {
|
44 |
-
localStorage.setItem('username', name)
|
45 |
-
setUsername(name)
|
46 |
-
}
|
47 |
-
|
48 |
-
return (
|
49 |
-
<div className="chat-container">
|
50 |
-
{!username ? (
|
51 |
-
<UsernameForm onSet={handleUsernameSet} />
|
52 |
-
) : (
|
53 |
-
<>
|
54 |
-
<SessionList sessions={sessions} current={sessionName} />
|
55 |
-
<MessageList messages={messages} />
|
56 |
-
<InputBar onSend={sendMessage} />
|
57 |
-
</>
|
58 |
-
)}
|
59 |
-
</div>
|
60 |
-
)
|
61 |
-
}
|
62 |
-
|
63 |
-
export default ChatWindow
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/InputBar.jsx
DELETED
@@ -1,31 +0,0 @@
|
|
1 |
-
import { useState } from 'react'
|
2 |
-
import PropTypes from 'prop-types'
|
3 |
-
|
4 |
-
function InputBar({ onSend }) {
|
5 |
-
const [text, setText] = useState('')
|
6 |
-
|
7 |
-
const handleSubmit = (e) => {
|
8 |
-
e.preventDefault()
|
9 |
-
if (!text.trim()) return
|
10 |
-
onSend(text)
|
11 |
-
setText('')
|
12 |
-
}
|
13 |
-
|
14 |
-
return (
|
15 |
-
<form className="input-bar" onSubmit={handleSubmit}>
|
16 |
-
<input
|
17 |
-
type="text"
|
18 |
-
value={text}
|
19 |
-
onChange={(e) => setText(e.target.value)}
|
20 |
-
placeholder="Type a message..."
|
21 |
-
/>
|
22 |
-
<button type="submit">Send</button>
|
23 |
-
</form>
|
24 |
-
)
|
25 |
-
}
|
26 |
-
|
27 |
-
InputBar.propTypes = {
|
28 |
-
onSend: PropTypes.func.isRequired,
|
29 |
-
}
|
30 |
-
|
31 |
-
export default InputBar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/MessageBubble.jsx
DELETED
@@ -1,13 +0,0 @@
|
|
1 |
-
import PropTypes from 'prop-types'
|
2 |
-
import '../styles/chat.css'
|
3 |
-
|
4 |
-
function MessageBubble({ role, content }) {
|
5 |
-
return <div className={`message ${role}`}>{content}</div>
|
6 |
-
}
|
7 |
-
|
8 |
-
MessageBubble.propTypes = {
|
9 |
-
role: PropTypes.string.isRequired,
|
10 |
-
content: PropTypes.string.isRequired,
|
11 |
-
}
|
12 |
-
|
13 |
-
export default MessageBubble
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/MessageList.jsx
DELETED
@@ -1,23 +0,0 @@
|
|
1 |
-
import PropTypes from 'prop-types'
|
2 |
-
import MessageBubble from './MessageBubble'
|
3 |
-
|
4 |
-
function MessageList({ messages }) {
|
5 |
-
return (
|
6 |
-
<div className="message-list">
|
7 |
-
{messages.map((m, i) => (
|
8 |
-
<MessageBubble key={i} role={m.role} content={m.content} />
|
9 |
-
))}
|
10 |
-
</div>
|
11 |
-
)
|
12 |
-
}
|
13 |
-
|
14 |
-
MessageList.propTypes = {
|
15 |
-
messages: PropTypes.arrayOf(
|
16 |
-
PropTypes.shape({
|
17 |
-
role: PropTypes.string.isRequired,
|
18 |
-
content: PropTypes.string.isRequired,
|
19 |
-
})
|
20 |
-
).isRequired,
|
21 |
-
}
|
22 |
-
|
23 |
-
export default MessageList
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/SessionList.jsx
DELETED
@@ -1,24 +0,0 @@
|
|
1 |
-
import PropTypes from 'prop-types'
|
2 |
-
import '../styles/chat.css'
|
3 |
-
|
4 |
-
function SessionList({ sessions, current }) {
|
5 |
-
return (
|
6 |
-
<div className="session-list">
|
7 |
-
{sessions.map((name) => (
|
8 |
-
<span
|
9 |
-
key={name}
|
10 |
-
className={`session-item ${name === current ? 'active' : ''}`}
|
11 |
-
>
|
12 |
-
{name}
|
13 |
-
</span>
|
14 |
-
))}
|
15 |
-
</div>
|
16 |
-
)
|
17 |
-
}
|
18 |
-
|
19 |
-
SessionList.propTypes = {
|
20 |
-
sessions: PropTypes.arrayOf(PropTypes.string).isRequired,
|
21 |
-
current: PropTypes.string.isRequired,
|
22 |
-
}
|
23 |
-
|
24 |
-
export default SessionList
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/components/UsernameForm.jsx
DELETED
@@ -1,32 +0,0 @@
|
|
1 |
-
import { useState } from 'react'
|
2 |
-
import PropTypes from 'prop-types'
|
3 |
-
import '../styles/chat.css'
|
4 |
-
|
5 |
-
function UsernameForm({ onSet }) {
|
6 |
-
const [name, setName] = useState('')
|
7 |
-
|
8 |
-
const handleSubmit = (e) => {
|
9 |
-
e.preventDefault()
|
10 |
-
const trimmed = name.trim()
|
11 |
-
if (!trimmed) return
|
12 |
-
onSet(trimmed)
|
13 |
-
}
|
14 |
-
|
15 |
-
return (
|
16 |
-
<form className="username-form" onSubmit={handleSubmit}>
|
17 |
-
<input
|
18 |
-
type="text"
|
19 |
-
value={name}
|
20 |
-
onChange={(e) => setName(e.target.value)}
|
21 |
-
placeholder="Enter your name..."
|
22 |
-
/>
|
23 |
-
<button type="submit">Start Chatting</button>
|
24 |
-
</form>
|
25 |
-
)
|
26 |
-
}
|
27 |
-
|
28 |
-
UsernameForm.propTypes = {
|
29 |
-
onSet: PropTypes.func.isRequired,
|
30 |
-
}
|
31 |
-
|
32 |
-
export default UsernameForm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/index.css
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
:root {
|
2 |
-
--glass-bg: rgba(255, 255, 255, 0.15);
|
3 |
-
--glass-border: rgba(255, 255, 255, 0.35);
|
4 |
-
--blur: 16px;
|
5 |
-
--radius: 20px;
|
6 |
-
--glare: radial-gradient(circle at top left, rgba(255, 255, 255, 0.6), transparent);
|
7 |
-
}
|
8 |
-
|
9 |
-
* {
|
10 |
-
box-sizing: border-box;
|
11 |
-
}
|
12 |
-
|
13 |
-
body {
|
14 |
-
margin: 0;
|
15 |
-
padding: 0;
|
16 |
-
font-family: 'Inter', system-ui, Avenir, Helvetica, Arial, sans-serif;
|
17 |
-
background: linear-gradient(120deg, #89f7fe 0%, #66a6ff 100%);
|
18 |
-
display: flex;
|
19 |
-
justify-content: center;
|
20 |
-
align-items: center;
|
21 |
-
min-height: 100vh;
|
22 |
-
position: relative;
|
23 |
-
overflow: hidden;
|
24 |
-
}
|
25 |
-
|
26 |
-
body::before,
|
27 |
-
body::after {
|
28 |
-
content: '';
|
29 |
-
position: absolute;
|
30 |
-
width: 300px;
|
31 |
-
height: 300px;
|
32 |
-
background: radial-gradient(circle at center, rgba(255, 255, 255, 0.5), transparent);
|
33 |
-
filter: blur(100px);
|
34 |
-
z-index: 0;
|
35 |
-
mix-blend-mode: overlay;
|
36 |
-
opacity: 0.6;
|
37 |
-
}
|
38 |
-
|
39 |
-
body::before {
|
40 |
-
top: -80px;
|
41 |
-
left: -80px;
|
42 |
-
}
|
43 |
-
|
44 |
-
body::after {
|
45 |
-
bottom: -80px;
|
46 |
-
right: -80px;
|
47 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/main.jsx
DELETED
@@ -1,10 +0,0 @@
|
|
1 |
-
import { StrictMode } from 'react'
|
2 |
-
import { createRoot } from 'react-dom/client'
|
3 |
-
import './index.css'
|
4 |
-
import App from './App.jsx'
|
5 |
-
|
6 |
-
createRoot(document.getElementById('root')).render(
|
7 |
-
<StrictMode>
|
8 |
-
<App />
|
9 |
-
</StrictMode>,
|
10 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/styles/chat.css
DELETED
@@ -1,167 +0,0 @@
|
|
1 |
-
.chat-container {
|
2 |
-
width: 420px;
|
3 |
-
max-width: 90vw;
|
4 |
-
height: 600px;
|
5 |
-
display: flex;
|
6 |
-
flex-direction: column;
|
7 |
-
background: var(--glass-bg);
|
8 |
-
border: 1px solid var(--glass-border);
|
9 |
-
backdrop-filter: blur(var(--blur)) saturate(180%);
|
10 |
-
-webkit-backdrop-filter: blur(var(--blur)) saturate(180%);
|
11 |
-
border-radius: var(--radius);
|
12 |
-
padding: 1rem;
|
13 |
-
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
14 |
-
position: relative;
|
15 |
-
overflow: hidden;
|
16 |
-
}
|
17 |
-
|
18 |
-
.chat-container::before {
|
19 |
-
content: '';
|
20 |
-
position: absolute;
|
21 |
-
inset: 0;
|
22 |
-
background: var(--glare);
|
23 |
-
mix-blend-mode: overlay;
|
24 |
-
pointer-events: none;
|
25 |
-
}
|
26 |
-
|
27 |
-
.message-list {
|
28 |
-
flex: 1;
|
29 |
-
overflow-y: auto;
|
30 |
-
display: flex;
|
31 |
-
flex-direction: column;
|
32 |
-
gap: 0.5rem;
|
33 |
-
padding-right: 4px;
|
34 |
-
scroll-behavior: smooth;
|
35 |
-
}
|
36 |
-
|
37 |
-
.session-list {
|
38 |
-
display: flex;
|
39 |
-
gap: 0.5rem;
|
40 |
-
flex-wrap: wrap;
|
41 |
-
margin-bottom: 0.5rem;
|
42 |
-
z-index: 1;
|
43 |
-
}
|
44 |
-
|
45 |
-
.session-item {
|
46 |
-
padding: 0.25rem 0.5rem;
|
47 |
-
background: var(--glass-bg);
|
48 |
-
border: 1px solid var(--glass-border);
|
49 |
-
border-radius: var(--radius);
|
50 |
-
backdrop-filter: blur(var(--blur));
|
51 |
-
-webkit-backdrop-filter: blur(var(--blur));
|
52 |
-
font-size: 0.75rem;
|
53 |
-
transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
|
54 |
-
}
|
55 |
-
|
56 |
-
.session-item.active {
|
57 |
-
background: rgba(255, 255, 255, 0.4);
|
58 |
-
font-weight: bold;
|
59 |
-
}
|
60 |
-
|
61 |
-
.message {
|
62 |
-
width: fit-content;
|
63 |
-
max-width: 80%;
|
64 |
-
padding: 0.5rem 1rem;
|
65 |
-
background: var(--glass-bg);
|
66 |
-
border: 1px solid var(--glass-border);
|
67 |
-
border-radius: var(--radius);
|
68 |
-
backdrop-filter: blur(var(--blur));
|
69 |
-
-webkit-backdrop-filter: blur(var(--blur));
|
70 |
-
animation: jelly 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
71 |
-
}
|
72 |
-
|
73 |
-
.message.user {
|
74 |
-
align-self: flex-end;
|
75 |
-
}
|
76 |
-
|
77 |
-
.input-bar {
|
78 |
-
display: flex;
|
79 |
-
gap: 0.5rem;
|
80 |
-
margin-top: 0.5rem;
|
81 |
-
}
|
82 |
-
|
83 |
-
.input-bar input {
|
84 |
-
flex: 1;
|
85 |
-
padding: 0.5rem 1rem;
|
86 |
-
border: 1px solid var(--glass-border);
|
87 |
-
background: var(--glass-bg);
|
88 |
-
border-radius: var(--radius);
|
89 |
-
backdrop-filter: blur(var(--blur));
|
90 |
-
-webkit-backdrop-filter: blur(var(--blur));
|
91 |
-
color: #000;
|
92 |
-
outline: none;
|
93 |
-
}
|
94 |
-
|
95 |
-
.input-bar button {
|
96 |
-
padding: 0.5rem 1rem;
|
97 |
-
border: none;
|
98 |
-
border-radius: var(--radius);
|
99 |
-
background: rgba(255, 255, 255, 0.6);
|
100 |
-
color: #000;
|
101 |
-
font-weight: bold;
|
102 |
-
cursor: pointer;
|
103 |
-
transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
|
104 |
-
}
|
105 |
-
|
106 |
-
.username-form {
|
107 |
-
display: flex;
|
108 |
-
flex-direction: column;
|
109 |
-
gap: 0.5rem;
|
110 |
-
flex: 1;
|
111 |
-
justify-content: center;
|
112 |
-
align-items: center;
|
113 |
-
}
|
114 |
-
|
115 |
-
.username-form input {
|
116 |
-
padding: 0.75rem 1rem;
|
117 |
-
border: 1px solid var(--glass-border);
|
118 |
-
background: var(--glass-bg);
|
119 |
-
border-radius: var(--radius);
|
120 |
-
backdrop-filter: blur(var(--blur));
|
121 |
-
-webkit-backdrop-filter: blur(var(--blur));
|
122 |
-
width: 100%;
|
123 |
-
max-width: 200px;
|
124 |
-
text-align: center;
|
125 |
-
outline: none;
|
126 |
-
}
|
127 |
-
|
128 |
-
.username-form button {
|
129 |
-
padding: 0.5rem 1.5rem;
|
130 |
-
border: none;
|
131 |
-
border-radius: var(--radius);
|
132 |
-
background: rgba(255, 255, 255, 0.7);
|
133 |
-
font-weight: bold;
|
134 |
-
cursor: pointer;
|
135 |
-
transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
|
136 |
-
}
|
137 |
-
|
138 |
-
.username-form button:hover {
|
139 |
-
transform: scale(1.05);
|
140 |
-
}
|
141 |
-
|
142 |
-
.username-form button:active {
|
143 |
-
transform: scale(0.95);
|
144 |
-
}
|
145 |
-
|
146 |
-
.input-bar button:hover {
|
147 |
-
transform: scale(1.05);
|
148 |
-
}
|
149 |
-
|
150 |
-
.input-bar button:active {
|
151 |
-
transform: scale(0.95);
|
152 |
-
}
|
153 |
-
|
154 |
-
@keyframes jelly {
|
155 |
-
0% {
|
156 |
-
transform: scale(0.9);
|
157 |
-
}
|
158 |
-
40% {
|
159 |
-
transform: scale(1.05);
|
160 |
-
}
|
161 |
-
60% {
|
162 |
-
transform: scale(0.97);
|
163 |
-
}
|
164 |
-
100% {
|
165 |
-
transform: scale(1);
|
166 |
-
}
|
167 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/vite.config.js
DELETED
@@ -1,7 +0,0 @@
|
|
1 |
-
import { defineConfig } from 'vite'
|
2 |
-
import react from '@vitejs/plugin-react'
|
3 |
-
|
4 |
-
// https://vite.dev/config/
|
5 |
-
export default defineConfig({
|
6 |
-
plugins: [react()],
|
7 |
-
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|