Compare commits
14 Commits
async-rein
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70799ffb7d | ||
|
|
7f1d4fbdda | ||
|
|
5ebdd60ea0 | ||
|
|
289045e7d0 | ||
|
|
ceea83cb54 | ||
|
|
1b60aab97c | ||
|
|
210bfc1476 | ||
|
|
454fb1b52c | ||
|
|
c3f2501585 | ||
|
|
1da21fabee | ||
|
|
dd5690ee53 | ||
|
|
5e7ac28b6f | ||
|
|
29f8894e4a | ||
|
|
19d1df2f68 |
28
.env.example
Normal file
28
.env.example
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Database Configuration
|
||||||
|
# Use DATABASE_PATH for simple relative/absolute paths (e.g., "database/raggr.db" or "dev.db")
|
||||||
|
# Or use DATABASE_URL for full connection strings (e.g., "sqlite://database/raggr.db")
|
||||||
|
DATABASE_PATH=database/raggr.db
|
||||||
|
# DATABASE_URL=sqlite://database/raggr.db
|
||||||
|
|
||||||
|
# JWT Configuration
|
||||||
|
JWT_SECRET_KEY=your-secret-key-here
|
||||||
|
|
||||||
|
# Paperless Configuration
|
||||||
|
PAPERLESS_TOKEN=your-paperless-token
|
||||||
|
BASE_URL=192.168.1.5:8000
|
||||||
|
|
||||||
|
# Ollama Configuration
|
||||||
|
OLLAMA_URL=http://192.168.1.14:11434
|
||||||
|
OLLAMA_HOST=http://192.168.1.14:11434
|
||||||
|
|
||||||
|
# ChromaDB Configuration
|
||||||
|
CHROMADB_PATH=/path/to/chromadb
|
||||||
|
|
||||||
|
# OpenAI Configuration
|
||||||
|
OPENAI_API_KEY=your-openai-api-key
|
||||||
|
|
||||||
|
# Immich Configuration
|
||||||
|
IMMICH_URL=http://192.168.1.5:2283
|
||||||
|
IMMICH_API_KEY=your-immich-api-key
|
||||||
|
SEARCH_QUERY=simba cat
|
||||||
|
DOWNLOAD_DIR=./simba_photos
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -9,5 +9,10 @@ wheels/
|
|||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv
|
.venv
|
||||||
|
|
||||||
|
# Environment files
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# Database files
|
||||||
|
chromadb/
|
||||||
|
database/
|
||||||
|
*.db
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
TORTOISE_ORM = {
|
|
||||||
"connections": {"default": os.getenv("DATABASE_URL", "sqlite:///app/database/raggr.db")},
|
|
||||||
"apps": {
|
|
||||||
"models": {
|
|
||||||
"models": [
|
|
||||||
"blueprints.conversation.models",
|
|
||||||
"blueprints.users.models",
|
|
||||||
"aerich.models",
|
|
||||||
],
|
|
||||||
"default_connection": "default",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,9 @@ version: "3.8"
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
raggr:
|
raggr:
|
||||||
|
build:
|
||||||
|
context: ./services/raggr
|
||||||
|
dockerfile: Dockerfile
|
||||||
image: torrtle/simbarag:latest
|
image: torrtle/simbarag:latest
|
||||||
network_mode: host
|
network_mode: host
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
type QuestionBubbleProps = {
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const QuestionBubble = ({ text }: QuestionBubbleProps) => {
|
|
||||||
return <div className="rounded-md bg-stone-200 p-3">🤦: {text}</div>;
|
|
||||||
};
|
|
||||||
@@ -1,16 +1,27 @@
|
|||||||
# GENERATED BY CLAUDE
|
# GENERATED BY CLAUDE
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
import asyncio
|
import asyncio
|
||||||
from tortoise import Tortoise
|
from tortoise import Tortoise
|
||||||
from blueprints.users.models import User
|
from blueprints.users.models import User
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Database configuration with environment variable support
|
||||||
|
DATABASE_PATH = os.getenv("DATABASE_PATH", "database/raggr.db")
|
||||||
|
DATABASE_URL = os.getenv("DATABASE_URL", f"sqlite://{DATABASE_PATH}")
|
||||||
|
|
||||||
|
print(DATABASE_URL)
|
||||||
|
|
||||||
|
|
||||||
async def add_user(username: str, email: str, password: str):
|
async def add_user(username: str, email: str, password: str):
|
||||||
"""Add a new user to the database"""
|
"""Add a new user to the database"""
|
||||||
await Tortoise.init(
|
await Tortoise.init(
|
||||||
db_url="sqlite://database/raggr.db",
|
db_url=DATABASE_URL,
|
||||||
modules={
|
modules={
|
||||||
"models": [
|
"models": [
|
||||||
"blueprints.users.models",
|
"blueprints.users.models",
|
||||||
@@ -56,7 +67,7 @@ async def add_user(username: str, email: str, password: str):
|
|||||||
async def list_users():
|
async def list_users():
|
||||||
"""List all users in the database"""
|
"""List all users in the database"""
|
||||||
await Tortoise.init(
|
await Tortoise.init(
|
||||||
db_url="sqlite://database/raggr.db",
|
db_url=DATABASE_URL,
|
||||||
modules={
|
modules={
|
||||||
"models": [
|
"models": [
|
||||||
"blueprints.users.models",
|
"blueprints.users.models",
|
||||||
@@ -94,6 +105,11 @@ def print_usage():
|
|||||||
print("\nExamples:")
|
print("\nExamples:")
|
||||||
print(" python add_user.py add ryan ryan@example.com mypassword123")
|
print(" python add_user.py add ryan ryan@example.com mypassword123")
|
||||||
print(" python add_user.py list")
|
print(" python add_user.py list")
|
||||||
|
print("\nEnvironment Variables:")
|
||||||
|
print(" DATABASE_PATH - Path to database file (default: database/raggr.db)")
|
||||||
|
print(" DATABASE_URL - Full database URL (overrides DATABASE_PATH)")
|
||||||
|
print("\n Example with custom database:")
|
||||||
|
print(" DATABASE_PATH=dev.db python add_user.py list")
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
20
services/raggr/aerich_config.py
Normal file
20
services/raggr/aerich_config.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
# Database configuration with environment variable support
|
||||||
|
# Use DATABASE_PATH for relative paths or DATABASE_URL for full connection strings
|
||||||
|
DATABASE_PATH = os.getenv("DATABASE_PATH", "database/raggr.db")
|
||||||
|
DATABASE_URL = os.getenv("DATABASE_URL", f"sqlite://{DATABASE_PATH}")
|
||||||
|
|
||||||
|
TORTOISE_ORM = {
|
||||||
|
"connections": {"default": DATABASE_URL},
|
||||||
|
"apps": {
|
||||||
|
"models": {
|
||||||
|
"models": [
|
||||||
|
"blueprints.conversation.models",
|
||||||
|
"blueprints.users.models",
|
||||||
|
"aerich.models",
|
||||||
|
],
|
||||||
|
"default_connection": "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from quart import Quart, request, jsonify, render_template, send_from_directory
|
from quart import Quart, jsonify, render_template, request, send_from_directory
|
||||||
|
from quart_jwt_extended import JWTManager, get_jwt_identity, jwt_refresh_token_required
|
||||||
from tortoise.contrib.quart import register_tortoise
|
from tortoise.contrib.quart import register_tortoise
|
||||||
|
|
||||||
from quart_jwt_extended import JWTManager, jwt_refresh_token_required, get_jwt_identity
|
|
||||||
|
|
||||||
from main import consult_simba_oracle
|
|
||||||
|
|
||||||
import blueprints.users
|
|
||||||
import blueprints.conversation
|
import blueprints.conversation
|
||||||
import blueprints.conversation.logic
|
import blueprints.conversation.logic
|
||||||
|
import blueprints.users
|
||||||
import blueprints.users.models
|
import blueprints.users.models
|
||||||
|
from main import consult_simba_oracle
|
||||||
|
|
||||||
app = Quart(
|
app = Quart(
|
||||||
__name__,
|
__name__,
|
||||||
@@ -26,8 +24,11 @@ app.register_blueprint(blueprints.users.user_blueprint)
|
|||||||
app.register_blueprint(blueprints.conversation.conversation_blueprint)
|
app.register_blueprint(blueprints.conversation.conversation_blueprint)
|
||||||
|
|
||||||
|
|
||||||
|
# Database configuration with environment variable support
|
||||||
|
DATABASE_PATH = os.getenv("DATABASE_PATH", "database/raggr.db")
|
||||||
|
|
||||||
TORTOISE_CONFIG = {
|
TORTOISE_CONFIG = {
|
||||||
"connections": {"default": "sqlite://database/raggr.db"},
|
"connections": {"default": f"sqlite://{DATABASE_PATH}"},
|
||||||
"apps": {
|
"apps": {
|
||||||
"models": {
|
"models": {
|
||||||
"models": [
|
"models": [
|
||||||
@@ -186,7 +186,7 @@ def consult_oracle(
|
|||||||
def llm_chat(input: str, transcript: str = "") -> str:
|
def llm_chat(input: str, transcript: str = "") -> str:
|
||||||
system_prompt = "You are a helpful assistant that understands veterinary terms."
|
system_prompt = "You are a helpful assistant that understands veterinary terms."
|
||||||
transcript_prompt = f"Here is the message transcript thus far {transcript}."
|
transcript_prompt = f"Here is the message transcript thus far {transcript}."
|
||||||
prompt = f"""Answer the user in a humorous way as if you were a cat named Simba. Be very coy.
|
prompt = f"""Answer the user in as if you were a cat named Simba. Don't act too catlike. Be assertive.
|
||||||
{transcript_prompt if len(transcript) > 0 else ""}
|
{transcript_prompt if len(transcript) > 0 else ""}
|
||||||
Respond to this prompt: {input}"""
|
Respond to this prompt: {input}"""
|
||||||
output = llm_client.chat(prompt=prompt, system_prompt=system_prompt)
|
output = llm_client.chat(prompt=prompt, system_prompt=system_prompt)
|
||||||
@@ -24,7 +24,7 @@ const AppContainer = () => {
|
|||||||
|
|
||||||
// Try to verify token by making a request
|
// Try to verify token by making a request
|
||||||
try {
|
try {
|
||||||
await conversationService.getMessages();
|
await conversationService.getAllConversations();
|
||||||
// If successful, user is authenticated
|
// If successful, user is authenticated
|
||||||
setAuthenticated(true);
|
setAuthenticated(true);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -55,6 +55,21 @@ class UserService {
|
|||||||
return data.access_token;
|
return data.access_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async validateToken(): Promise<boolean> {
|
||||||
|
const refreshToken = localStorage.getItem("refresh_token");
|
||||||
|
|
||||||
|
if (!refreshToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.refreshToken();
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fetchWithAuth(
|
async fetchWithAuth(
|
||||||
url: string,
|
url: string,
|
||||||
options: RequestInit = {},
|
options: RequestInit = {},
|
||||||
|
Before Width: | Height: | Size: 163 B After Width: | Height: | Size: 163 B |
@@ -7,7 +7,7 @@ type AnswerBubbleProps = {
|
|||||||
|
|
||||||
export const AnswerBubble = ({ text, loading }: AnswerBubbleProps) => {
|
export const AnswerBubble = ({ text, loading }: AnswerBubbleProps) => {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md bg-orange-100 p-3">
|
<div className="rounded-md bg-orange-100 p-3 sm:p-4">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex flex-col w-full animate-pulse gap-2">
|
<div className="flex flex-col w-full animate-pulse gap-2">
|
||||||
<div className="flex flex-row gap-2 w-full">
|
<div className="flex flex-row gap-2 w-full">
|
||||||
@@ -20,8 +20,10 @@ export const AnswerBubble = ({ text, loading }: AnswerBubbleProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col break-words overflow-wrap-anywhere">
|
||||||
<ReactMarkdown>{"🐈: " + text}</ReactMarkdown>
|
<ReactMarkdown className="text-sm sm:text-base [&>*]:break-words">
|
||||||
|
{"🐈: " + text}
|
||||||
|
</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, useRef } from "react";
|
||||||
import { conversationService } from "../api/conversationService";
|
import { conversationService } from "../api/conversationService";
|
||||||
import { QuestionBubble } from "./QuestionBubble";
|
import { QuestionBubble } from "./QuestionBubble";
|
||||||
import { AnswerBubble } from "./AnswerBubble";
|
import { AnswerBubble } from "./AnswerBubble";
|
||||||
@@ -39,8 +39,13 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
|||||||
const [selectedConversation, setSelectedConversation] =
|
const [selectedConversation, setSelectedConversation] =
|
||||||
useState<Conversation | null>(null);
|
useState<Conversation | null>(null);
|
||||||
|
|
||||||
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
const simbaAnswers = ["meow.", "hiss...", "purrrrrr", "yowOWROWWowowr"];
|
const simbaAnswers = ["meow.", "hiss...", "purrrrrr", "yowOWROWWowowr"];
|
||||||
|
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
|
};
|
||||||
|
|
||||||
const handleSelectConversation = (conversation: Conversation) => {
|
const handleSelectConversation = (conversation: Conversation) => {
|
||||||
setShowConversations(false);
|
setShowConversations(false);
|
||||||
setSelectedConversation(conversation);
|
setSelectedConversation(conversation);
|
||||||
@@ -91,6 +96,10 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
|||||||
loadConversations();
|
loadConversations();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollToBottom();
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadMessages = async () => {
|
const loadMessages = async () => {
|
||||||
if (selectedConversation == null) return;
|
if (selectedConversation == null) return;
|
||||||
@@ -112,8 +121,11 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
|||||||
}, [selectedConversation]);
|
}, [selectedConversation]);
|
||||||
|
|
||||||
const handleQuestionSubmit = async () => {
|
const handleQuestionSubmit = async () => {
|
||||||
|
if (!query.trim()) return; // Don't submit empty messages
|
||||||
|
|
||||||
const currMessages = messages.concat([{ text: query, speaker: "user" }]);
|
const currMessages = messages.concat([{ text: query, speaker: "user" }]);
|
||||||
setMessages(currMessages);
|
setMessages(currMessages);
|
||||||
|
setQuery(""); // Clear input immediately after submission
|
||||||
|
|
||||||
if (simbaMode) {
|
if (simbaMode) {
|
||||||
console.log("simba mode activated");
|
console.log("simba mode activated");
|
||||||
@@ -142,7 +154,6 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
|||||||
setMessages(
|
setMessages(
|
||||||
currMessages.concat([{ text: result.response, speaker: "simba" }]),
|
currMessages.concat([{ text: result.response, speaker: "simba" }]),
|
||||||
);
|
);
|
||||||
setQuery(""); // Clear input after successful send
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to send query:", error);
|
console.error("Failed to send query:", error);
|
||||||
// If session expired, redirect to login
|
// If session expired, redirect to login
|
||||||
@@ -156,18 +167,26 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
|||||||
setQuery(event.target.value);
|
setQuery(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||||
|
// Submit on Enter, but allow Shift+Enter for new line
|
||||||
|
if (event.key === "Enter" && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
handleQuestionSubmit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen bg-opacity-20">
|
<div className="h-screen bg-opacity-20">
|
||||||
<div className="bg-white/85 h-screen">
|
<div className="bg-white/85 h-screen">
|
||||||
<div className="flex flex-row justify-center py-4">
|
<div className="flex flex-row justify-center py-4">
|
||||||
<div className="flex flex-col gap-4 min-w-xl max-w-xl">
|
<div className="flex flex-col gap-4 w-full px-4 sm:w-11/12 sm:max-w-2xl lg:max-w-4xl sm:px-0">
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-col sm:flex-row gap-3 sm:gap-0 sm:justify-between">
|
||||||
<header className="flex flex-row justify-center gap-2 sticky top-0 z-10 bg-white">
|
<header className="flex flex-row justify-center gap-2 sticky top-0 z-10 bg-white">
|
||||||
<h1 className="text-3xl">ask simba!</h1>
|
<h1 className="text-2xl sm:text-3xl">ask simba!</h1>
|
||||||
</header>
|
</header>
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2 justify-center sm:justify-end">
|
||||||
<button
|
<button
|
||||||
className="p-2 border border-green-400 bg-green-200 hover:bg-green-400 cursor-pointer rounded-md"
|
className="p-2 h-11 border border-green-400 bg-green-200 hover:bg-green-400 cursor-pointer rounded-md text-sm sm:text-base"
|
||||||
onClick={() => setShowConversations(!showConversations)}
|
onClick={() => setShowConversations(!showConversations)}
|
||||||
>
|
>
|
||||||
{showConversations
|
{showConversations
|
||||||
@@ -175,7 +194,7 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
|||||||
: "show conversations"}
|
: "show conversations"}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="p-2 border border-red-400 bg-red-200 hover:bg-red-400 cursor-pointer rounded-md"
|
className="p-2 h-11 border border-red-400 bg-red-200 hover:bg-red-400 cursor-pointer rounded-md text-sm sm:text-base"
|
||||||
onClick={() => setAuthenticated(false)}
|
onClick={() => setAuthenticated(false)}
|
||||||
>
|
>
|
||||||
logout
|
logout
|
||||||
@@ -195,29 +214,34 @@ export const ChatScreen = ({ setAuthenticated }: ChatScreenProps) => {
|
|||||||
}
|
}
|
||||||
return <QuestionBubble key={index} text={msg.text} />;
|
return <QuestionBubble key={index} text={msg.text} />;
|
||||||
})}
|
})}
|
||||||
|
<div ref={messagesEndRef} />
|
||||||
<footer className="flex flex-col gap-2 sticky bottom-0">
|
<footer className="flex flex-col gap-2 sticky bottom-0">
|
||||||
<div className="flex flex-row justify-between gap-2 grow">
|
<div className="flex flex-row justify-between gap-2 grow">
|
||||||
<textarea
|
<textarea
|
||||||
className="p-4 border border-blue-200 rounded-md grow bg-white"
|
className="p-3 sm:p-4 border border-blue-200 rounded-md grow bg-white min-h-[44px] resize-y"
|
||||||
onChange={handleQueryChange}
|
onChange={handleQueryChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
value={query}
|
value={query}
|
||||||
|
rows={2}
|
||||||
|
placeholder="Type your message... (Press Enter to send, Shift+Enter for new line)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-between gap-2 grow">
|
<div className="flex flex-row justify-between gap-2 grow">
|
||||||
<button
|
<button
|
||||||
className="p-4 border border-blue-400 bg-blue-200 hover:bg-blue-400 cursor-pointer rounded-md flex-grow"
|
className="p-3 sm:p-4 min-h-[44px] border border-blue-400 bg-blue-200 hover:bg-blue-400 cursor-pointer rounded-md flex-grow text-sm sm:text-base"
|
||||||
onClick={() => handleQuestionSubmit()}
|
onClick={() => handleQuestionSubmit()}
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-center gap-2 grow">
|
<div className="flex flex-row justify-center gap-2 grow items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
onChange={(event) => setSimbaMode(event.target.checked)}
|
onChange={(event) => setSimbaMode(event.target.checked)}
|
||||||
|
className="w-5 h-5 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
<p>simba mode?</p>
|
<p className="text-sm sm:text-base">simba mode?</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,8 +22,14 @@ export const ConversationList = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadConversations = async () => {
|
const loadConversations = async () => {
|
||||||
try {
|
try {
|
||||||
const fetchedConversations =
|
let fetchedConversations =
|
||||||
await conversationService.getAllConversations();
|
await conversationService.getAllConversations();
|
||||||
|
|
||||||
|
if (conversations.length == 0) {
|
||||||
|
await conversationService.createConversation();
|
||||||
|
fetchedConversations =
|
||||||
|
await conversationService.getAllConversations();
|
||||||
|
}
|
||||||
setConversations(
|
setConversations(
|
||||||
fetchedConversations.map((conversation) => ({
|
fetchedConversations.map((conversation) => ({
|
||||||
id: conversation.id,
|
id: conversation.id,
|
||||||
@@ -38,22 +44,25 @@ export const ConversationList = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-indigo-300 rounded-md p-3 flex flex-col">
|
<div className="bg-indigo-300 rounded-md p-3 sm:p-4 flex flex-col gap-1">
|
||||||
{conservations.map((conversation) => {
|
{conservations.map((conversation) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="border-blue-400 bg-indigo-300 hover:bg-indigo-200 cursor-pointer rounded-md p-2"
|
key={conversation.id}
|
||||||
|
className="border-blue-400 bg-indigo-300 hover:bg-indigo-200 cursor-pointer rounded-md p-3 min-h-[44px] flex items-center"
|
||||||
onClick={() => onSelectConversation(conversation)}
|
onClick={() => onSelectConversation(conversation)}
|
||||||
>
|
>
|
||||||
<p>{conversation.title}</p>
|
<p className="text-sm sm:text-base break-words">
|
||||||
|
{conversation.title}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<div
|
<div
|
||||||
className="border-blue-400 bg-indigo-300 hover:bg-indigo-200 cursor-pointer rounded-md p-2"
|
className="border-blue-400 bg-indigo-300 hover:bg-indigo-200 cursor-pointer rounded-md p-3 min-h-[44px] flex items-center"
|
||||||
onClick={() => onCreateNewConversation()}
|
onClick={() => onCreateNewConversation()}
|
||||||
>
|
>
|
||||||
<p> + Start a new thread</p>
|
<p className="text-sm sm:text-base"> + Start a new thread</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { userService } from "../api/userService";
|
import { userService } from "../api/userService";
|
||||||
|
|
||||||
type LoginScreenProps = {
|
type LoginScreenProps = {
|
||||||
@@ -9,8 +9,23 @@ export const LoginScreen = ({ setAuthenticated }: LoginScreenProps) => {
|
|||||||
const [username, setUsername] = useState<string>("");
|
const [username, setUsername] = useState<string>("");
|
||||||
const [password, setPassword] = useState<string>("");
|
const [password, setPassword] = useState<string>("");
|
||||||
const [error, setError] = useState<string>("");
|
const [error, setError] = useState<string>("");
|
||||||
|
const [isChecking, setIsChecking] = useState<boolean>(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Check if user is already authenticated
|
||||||
|
const checkAuth = async () => {
|
||||||
|
const isValid = await userService.validateToken();
|
||||||
|
if (isValid) {
|
||||||
|
setAuthenticated(true);
|
||||||
|
}
|
||||||
|
setIsChecking(false);
|
||||||
|
};
|
||||||
|
checkAuth();
|
||||||
|
}, [setAuthenticated]);
|
||||||
|
|
||||||
|
const handleLogin = async (e?: React.FormEvent) => {
|
||||||
|
e?.preventDefault();
|
||||||
|
|
||||||
const handleLogin = async () => {
|
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
setError("Please enter username and password");
|
setError("Please enter username and password");
|
||||||
return;
|
return;
|
||||||
@@ -28,46 +43,73 @@ export const LoginScreen = ({ setAuthenticated }: LoginScreenProps) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleKeyPress = (e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
handleLogin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show loading state while checking authentication
|
||||||
|
if (isChecking) {
|
||||||
|
return (
|
||||||
|
<div className="h-screen bg-opacity-20">
|
||||||
|
<div className="bg-white/85 h-screen flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-lg sm:text-xl">Checking authentication...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen bg-opacity-20">
|
<div className="h-screen bg-opacity-20">
|
||||||
<div className="bg-white/85 h-screen">
|
<div className="bg-white/85 h-screen">
|
||||||
<div className="flex flex-row justify-center py-4">
|
<div className="flex flex-row justify-center py-4">
|
||||||
<div className="flex flex-col gap-4 min-w-xl max-w-xl">
|
<div className="flex flex-col gap-4 w-full px-4 sm:w-11/12 sm:max-w-2xl lg:max-w-4xl sm:px-0">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex flex-grow justify-center w-full bg-amber-400">
|
<div className="flex flex-grow justify-center w-full bg-amber-400 p-2">
|
||||||
<h1 className="text-xl font-bold">
|
<h1 className="text-base sm:text-xl font-bold text-center">
|
||||||
I AM LOOKING FOR A DESIGNER. THIS APP WILL REMAIN UGLY UNTIL A
|
I AM LOOKING FOR A DESIGNER. THIS APP WILL REMAIN UGLY UNTIL A
|
||||||
DESIGNER COMES.
|
DESIGNER COMES.
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<header className="flex flex-row justify-center gap-2 grow sticky top-0 z-10 bg-white">
|
<header className="flex flex-row justify-center gap-2 grow sticky top-0 z-10 bg-white">
|
||||||
<h1 className="text-3xl">ask simba!</h1>
|
<h1 className="text-2xl sm:text-3xl">ask simba!</h1>
|
||||||
</header>
|
</header>
|
||||||
<label htmlFor="username">username</label>
|
<label htmlFor="username" className="text-sm sm:text-base">
|
||||||
|
username
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="username"
|
id="username"
|
||||||
name="username"
|
name="username"
|
||||||
value={username}
|
value={username}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
className="border border-s-slate-950 p-3 rounded-md"
|
onKeyPress={handleKeyPress}
|
||||||
|
className="border border-s-slate-950 p-3 rounded-md min-h-[44px]"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="password">password</label>
|
<label htmlFor="password" className="text-sm sm:text-base">
|
||||||
|
password
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
id="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
className="border border-s-slate-950 p-3 rounded-md"
|
onKeyPress={handleKeyPress}
|
||||||
|
className="border border-s-slate-950 p-3 rounded-md min-h-[44px]"
|
||||||
/>
|
/>
|
||||||
{error && (
|
{error && (
|
||||||
<div className="text-red-600 font-semibold">{error}</div>
|
<div className="text-red-600 font-semibold text-sm sm:text-base">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className="p-4 border border-blue-400 bg-blue-200 hover:bg-blue-400 cursor-pointer rounded-md flex-grow"
|
className="p-3 sm:p-4 min-h-[44px] border border-blue-400 bg-blue-200 hover:bg-blue-400 cursor-pointer rounded-md flex-grow text-sm sm:text-base"
|
||||||
onClick={handleLogin}
|
onClick={handleLogin}
|
||||||
>
|
>
|
||||||
login
|
login
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
type QuestionBubbleProps = {
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const QuestionBubble = ({ text }: QuestionBubbleProps) => {
|
||||||
|
return (
|
||||||
|
<div className="rounded-md bg-stone-200 p-3 sm:p-4 break-words overflow-wrap-anywhere text-sm sm:text-base">
|
||||||
|
🤦: {text}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Before Width: | Height: | Size: 3.4 MiB After Width: | Height: | Size: 3.4 MiB |
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
@@ -7,6 +7,28 @@
|
|||||||
resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
|
resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
|
||||||
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
|
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
|
||||||
|
|
||||||
|
"@emnapi/core@^1.5.0":
|
||||||
|
version "1.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.6.0.tgz#517f65d1c8270d5d5aa1aad660d5acb897430dca"
|
||||||
|
integrity sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg==
|
||||||
|
dependencies:
|
||||||
|
"@emnapi/wasi-threads" "1.1.0"
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
"@emnapi/runtime@^1.5.0":
|
||||||
|
version "1.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.6.0.tgz#8fe297e0090f6e89a57a1f31f1c440bdbc3c01d8"
|
||||||
|
integrity sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
"@emnapi/wasi-threads@1.1.0", "@emnapi/wasi-threads@^1.1.0":
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf"
|
||||||
|
integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
"@isaacs/fs-minipass@^4.0.0":
|
"@isaacs/fs-minipass@^4.0.0":
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz"
|
resolved "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz"
|
||||||
@@ -91,7 +113,16 @@
|
|||||||
"@module-federation/runtime" "0.18.0"
|
"@module-federation/runtime" "0.18.0"
|
||||||
"@module-federation/sdk" "0.18.0"
|
"@module-federation/sdk" "0.18.0"
|
||||||
|
|
||||||
"@rsbuild/core@^1.5.6", "@rsbuild/core@1.x":
|
"@napi-rs/wasm-runtime@^1.0.5":
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz#dcfea99a75f06209a235f3d941e3460a51e9b14c"
|
||||||
|
integrity sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==
|
||||||
|
dependencies:
|
||||||
|
"@emnapi/core" "^1.5.0"
|
||||||
|
"@emnapi/runtime" "^1.5.0"
|
||||||
|
"@tybys/wasm-util" "^0.10.1"
|
||||||
|
|
||||||
|
"@rsbuild/core@^1.5.6":
|
||||||
version "1.5.12"
|
version "1.5.12"
|
||||||
resolved "https://registry.npmjs.org/@rsbuild/core/-/core-1.5.12.tgz"
|
resolved "https://registry.npmjs.org/@rsbuild/core/-/core-1.5.12.tgz"
|
||||||
integrity sha512-DpinE1If6WRTwQYqH+PRtJo3zshkDYHfIcWq4lTtfsPfPLrXshmRXBam3BS1RRu4v2gGT+LCNiUefftsmcmL0A==
|
integrity sha512-DpinE1If6WRTwQYqH+PRtJo3zshkDYHfIcWq4lTtfsPfPLrXshmRXBam3BS1RRu4v2gGT+LCNiUefftsmcmL0A==
|
||||||
@@ -115,6 +146,53 @@
|
|||||||
resolved "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.7.tgz"
|
resolved "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.7.tgz"
|
||||||
integrity sha512-prQ/vgJxOPdlYiR4gVeOEKofTCEOu70JQIQApqFnw8lKM7rd9ag8ogDNqmc2L/GGXGHLAqds28oeKXRlzYf7+Q==
|
integrity sha512-prQ/vgJxOPdlYiR4gVeOEKofTCEOu70JQIQApqFnw8lKM7rd9ag8ogDNqmc2L/GGXGHLAqds28oeKXRlzYf7+Q==
|
||||||
|
|
||||||
|
"@rspack/binding-darwin-x64@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.5.7.tgz#92210902db273773bc2bcb1e587d66e025b9d1b0"
|
||||||
|
integrity sha512-FPqiWSbEEerqfJrGnYe68svvl6NyuQFAb3qqFe/Q0MqFhBYmAZwa0R2/ylugCdgFLZxmkFuWqpDgItpvJb/E3Q==
|
||||||
|
|
||||||
|
"@rspack/binding-linux-arm64-gnu@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.5.7.tgz#a8042c41264c5e8603d67e56277d45c2b012f0cd"
|
||||||
|
integrity sha512-fwy+NY+0CHrZqqzDrjPBlTuK53W4dG5EEg/QQFAE7KVM+okRqPk8tg45bJ5628rCNLe13GDmPIE107LmgspNqA==
|
||||||
|
|
||||||
|
"@rspack/binding-linux-arm64-musl@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.5.7.tgz#15421d912a758f63d19c104b6d40b96b4ae09e03"
|
||||||
|
integrity sha512-576u/0F4ZUzpHckFme4vQ0sSxjE+B/gVP4tNJ+P6bJaclXLFXV4icbjTUQwOIgmA1EQz/JFeKGGJZ4p6mowpBQ==
|
||||||
|
|
||||||
|
"@rspack/binding-linux-x64-gnu@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.5.7.tgz#0b3c973c8c900ba774e0f5ea275e6dbdace9c16f"
|
||||||
|
integrity sha512-brSHywXjjeuWkv0ywgxS4VgDgquarEb4XGr+eXhOaPcc8x2rNefyc4hErplrI7+oxPXVuGK5VE4ZH5bj3Yknvg==
|
||||||
|
|
||||||
|
"@rspack/binding-linux-x64-musl@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.5.7.tgz#b7a9f984686a07fa66762acb18af1a4ad1800a87"
|
||||||
|
integrity sha512-HcS0DzbLlWCwVfYcWMbTgILh4GELD6m4CZoFEhIr4fJCJi0p8NgLYycy1QtDhaUjs8TKalmyMwHrJwGnD141JA==
|
||||||
|
|
||||||
|
"@rspack/binding-wasm32-wasi@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.5.7.tgz#c0a30d4700725723c6198961dbc7d2ecfa713e21"
|
||||||
|
integrity sha512-uTRUEuK+TVlvUBSWXVoxD+6JTN+rvtRqVlO+A7I7VnOY7p9Rpvk1sXcHtEwg/XuDCq4DALnvlzbFLh7G3zILvw==
|
||||||
|
dependencies:
|
||||||
|
"@napi-rs/wasm-runtime" "^1.0.5"
|
||||||
|
|
||||||
|
"@rspack/binding-win32-arm64-msvc@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.5.7.tgz#53184c858b08e47429a1b281a18d9f30e5a06806"
|
||||||
|
integrity sha512-dFHrXRUmMTkxEn/Uw2RLbIckKfi0Zmn2NnEXwedWdyRgZW4Vhk7+VBxM22O/CHZmAGt12Ol25yTuVv58ANLEKA==
|
||||||
|
|
||||||
|
"@rspack/binding-win32-ia32-msvc@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.5.7.tgz#dc12761a5903e6f1aefd368158d450bdfe30d563"
|
||||||
|
integrity sha512-PNtnOIUzE9p/Fbl6l/1Zs7bhn8ccTlaHTgZgQq0sO/QxjLlbU0WPjRl+YLo27cAningSOAbANuYlN8vAcuimrw==
|
||||||
|
|
||||||
|
"@rspack/binding-win32-x64-msvc@1.5.7":
|
||||||
|
version "1.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.5.7.tgz#b7f5e023edcb299782e9e396bfa4767476bd1bde"
|
||||||
|
integrity sha512-22gTaYkwaIUvyXRxf1RVnFTJPqF2hD1pgAQNBIz7kYybe6vvSZ6KInW4WyG4vjYKrJg/cbS4QvtlLn0lYXrdIw==
|
||||||
|
|
||||||
"@rspack/binding@1.5.7":
|
"@rspack/binding@1.5.7":
|
||||||
version "1.5.7"
|
version "1.5.7"
|
||||||
resolved "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.7.tgz"
|
resolved "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.7.tgz"
|
||||||
@@ -140,7 +218,7 @@
|
|||||||
"@rspack/binding" "1.5.7"
|
"@rspack/binding" "1.5.7"
|
||||||
"@rspack/lite-tapable" "1.0.1"
|
"@rspack/lite-tapable" "1.0.1"
|
||||||
|
|
||||||
"@rspack/lite-tapable@~1.0.1", "@rspack/lite-tapable@1.0.1":
|
"@rspack/lite-tapable@1.0.1", "@rspack/lite-tapable@~1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.0.1.tgz"
|
resolved "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.0.1.tgz"
|
||||||
integrity sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==
|
integrity sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==
|
||||||
@@ -153,7 +231,7 @@
|
|||||||
error-stack-parser "^2.1.4"
|
error-stack-parser "^2.1.4"
|
||||||
html-entities "^2.6.0"
|
html-entities "^2.6.0"
|
||||||
|
|
||||||
"@swc/helpers@^0.5.17", "@swc/helpers@>=0.5.1":
|
"@swc/helpers@^0.5.17":
|
||||||
version "0.5.17"
|
version "0.5.17"
|
||||||
resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz"
|
resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz"
|
||||||
integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==
|
integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==
|
||||||
@@ -173,11 +251,73 @@
|
|||||||
source-map-js "^1.2.1"
|
source-map-js "^1.2.1"
|
||||||
tailwindcss "4.1.14"
|
tailwindcss "4.1.14"
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-android-arm64@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz#8903678d75715d913b8f7c5f6fa0517af83b5111"
|
||||||
|
integrity sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==
|
||||||
|
|
||||||
"@tailwindcss/oxide-darwin-arm64@4.1.14":
|
"@tailwindcss/oxide-darwin-arm64@4.1.14":
|
||||||
version "4.1.14"
|
version "4.1.14"
|
||||||
resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz"
|
resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz"
|
||||||
integrity sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==
|
integrity sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-darwin-x64@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz#ac1af82da01299143129fdf615f6fcc046b4094e"
|
||||||
|
integrity sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-freebsd-x64@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz#a955cedf9b020147d222f92490e9d331db9b5c36"
|
||||||
|
integrity sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz#5474bee4d377144107f3f0198a3c0225a46c02e6"
|
||||||
|
integrity sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm64-gnu@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz#b06ca140083b353735414e32f7a8786f55ce2dd6"
|
||||||
|
integrity sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-arm64-musl@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz#85f4cabea2a07609274d1f747bd098c5da2a7cd2"
|
||||||
|
integrity sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-x64-gnu@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz#0d7fbf91763a2f6886044a050298489107d120bd"
|
||||||
|
integrity sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-linux-x64-musl@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz#93578713064ba4c16df517df01b3c546ecc9878d"
|
||||||
|
integrity sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz#9e55999129a952a3dcc2196cc9cc55248cc1b1fe"
|
||||||
|
integrity sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==
|
||||||
|
dependencies:
|
||||||
|
"@emnapi/core" "^1.5.0"
|
||||||
|
"@emnapi/runtime" "^1.5.0"
|
||||||
|
"@emnapi/wasi-threads" "^1.1.0"
|
||||||
|
"@napi-rs/wasm-runtime" "^1.0.5"
|
||||||
|
"@tybys/wasm-util" "^0.10.1"
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-win32-arm64-msvc@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz#097c00bfc60cd84943a9cb5e853b25fa25525c77"
|
||||||
|
integrity sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-win32-x64-msvc@4.1.14":
|
||||||
|
version "4.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz#eaa49fa930ce16b23478d3b58c079a40ac0b6622"
|
||||||
|
integrity sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==
|
||||||
|
|
||||||
"@tailwindcss/oxide@4.1.14":
|
"@tailwindcss/oxide@4.1.14":
|
||||||
version "4.1.14"
|
version "4.1.14"
|
||||||
resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz"
|
resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz"
|
||||||
@@ -210,6 +350,13 @@
|
|||||||
postcss "^8.4.41"
|
postcss "^8.4.41"
|
||||||
tailwindcss "4.1.14"
|
tailwindcss "4.1.14"
|
||||||
|
|
||||||
|
"@tybys/wasm-util@^0.10.1":
|
||||||
|
version "0.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414"
|
||||||
|
integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==
|
||||||
|
dependencies:
|
||||||
|
tslib "^2.4.0"
|
||||||
|
|
||||||
"@types/debug@^4.0.0":
|
"@types/debug@^4.0.0":
|
||||||
version "4.1.12"
|
version "4.1.12"
|
||||||
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz"
|
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz"
|
||||||
@@ -253,7 +400,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz"
|
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz"
|
||||||
integrity sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==
|
integrity sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==
|
||||||
|
|
||||||
"@types/react@^19.0.0", "@types/react@^19.1.13", "@types/react@>=18":
|
"@types/react@^19.1.13":
|
||||||
version "19.1.14"
|
version "19.1.14"
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-19.1.14.tgz"
|
resolved "https://registry.npmjs.org/@types/react/-/react-19.1.14.tgz"
|
||||||
integrity sha512-ukd93VGzaNPMAUPy0gRDSC57UuQbnH9Kussp7HBjM06YFi9uZTFhOvMSO2OKqXm1rSgzOE+pVx1k1PYHGwlc8Q==
|
integrity sha512-ukd93VGzaNPMAUPy0gRDSC57UuQbnH9Kussp7HBjM06YFi9uZTFhOvMSO2OKqXm1rSgzOE+pVx1k1PYHGwlc8Q==
|
||||||
@@ -724,6 +871,51 @@ lightningcss-darwin-arm64@1.30.1:
|
|||||||
resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz"
|
resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz"
|
||||||
integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==
|
integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==
|
||||||
|
|
||||||
|
lightningcss-darwin-x64@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22"
|
||||||
|
integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==
|
||||||
|
|
||||||
|
lightningcss-freebsd-x64@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4"
|
||||||
|
integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==
|
||||||
|
|
||||||
|
lightningcss-linux-arm-gnueabihf@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908"
|
||||||
|
integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-gnu@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009"
|
||||||
|
integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-musl@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe"
|
||||||
|
integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==
|
||||||
|
|
||||||
|
lightningcss-linux-x64-gnu@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157"
|
||||||
|
integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==
|
||||||
|
|
||||||
|
lightningcss-linux-x64-musl@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26"
|
||||||
|
integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==
|
||||||
|
|
||||||
|
lightningcss-win32-arm64-msvc@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039"
|
||||||
|
integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==
|
||||||
|
|
||||||
|
lightningcss-win32-x64-msvc@1.30.1:
|
||||||
|
version "1.30.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352"
|
||||||
|
integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==
|
||||||
|
|
||||||
lightningcss@1.30.1:
|
lightningcss@1.30.1:
|
||||||
version "1.30.1"
|
version "1.30.1"
|
||||||
resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz"
|
resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz"
|
||||||
@@ -1214,12 +1406,12 @@ react-markdown@^10.1.0:
|
|||||||
unist-util-visit "^5.0.0"
|
unist-util-visit "^5.0.0"
|
||||||
vfile "^6.0.0"
|
vfile "^6.0.0"
|
||||||
|
|
||||||
react-refresh@^0.17.0, "react-refresh@>=0.10.0 <1.0.0":
|
react-refresh@^0.17.0:
|
||||||
version "0.17.0"
|
version "0.17.0"
|
||||||
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz"
|
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz"
|
||||||
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
|
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
|
||||||
|
|
||||||
react@^19.1.1, react@>=18:
|
react@^19.1.1:
|
||||||
version "19.1.1"
|
version "19.1.1"
|
||||||
resolved "https://registry.npmjs.org/react/-/react-19.1.1.tgz"
|
resolved "https://registry.npmjs.org/react/-/react-19.1.1.tgz"
|
||||||
integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==
|
integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==
|
||||||
@@ -1384,7 +1576,7 @@ trough@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz"
|
resolved "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz"
|
||||||
integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==
|
integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==
|
||||||
|
|
||||||
tslib@^2.8.0:
|
tslib@^2.4.0, tslib@^2.8.0:
|
||||||
version "2.8.1"
|
version "2.8.1"
|
||||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
||||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
0
uv.lock → services/raggr/uv.lock
generated
0
uv.lock → services/raggr/uv.lock
generated
Reference in New Issue
Block a user