Switch to vercel's biome setup (#543)
This commit is contained in:
parent
b8643353c0
commit
43aa1c6e58
52 changed files with 414 additions and 201 deletions
|
|
@ -17,7 +17,7 @@ export interface LoginActionState {
|
||||||
|
|
||||||
export const login = async (
|
export const login = async (
|
||||||
_: LoginActionState,
|
_: LoginActionState,
|
||||||
formData: FormData
|
formData: FormData,
|
||||||
): Promise<LoginActionState> => {
|
): Promise<LoginActionState> => {
|
||||||
try {
|
try {
|
||||||
const validatedData = authFormSchema.parse({
|
const validatedData = authFormSchema.parse({
|
||||||
|
|
@ -53,7 +53,7 @@ export interface RegisterActionState {
|
||||||
|
|
||||||
export const register = async (
|
export const register = async (
|
||||||
_: RegisterActionState,
|
_: RegisterActionState,
|
||||||
formData: FormData
|
formData: FormData,
|
||||||
): Promise<RegisterActionState> => {
|
): Promise<RegisterActionState> => {
|
||||||
try {
|
try {
|
||||||
const validatedData = authFormSchema.parse({
|
const validatedData = authFormSchema.parse({
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@ export const {
|
||||||
providers: [
|
providers: [
|
||||||
Credentials({
|
Credentials({
|
||||||
credentials: {},
|
credentials: {},
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: TODO
|
|
||||||
async authorize({ email, password }: any) {
|
async authorize({ email, password }: any) {
|
||||||
const users = await getUser(email);
|
const users = await getUser(email);
|
||||||
if (users.length === 0) return null;
|
if (users.length === 0) return null;
|
||||||
|
// biome-ignore lint: Forbidden non-null assertion.
|
||||||
const passwordsMatch = await compare(password, users[0].password!);
|
const passwordsMatch = await compare(password, users[0].password!);
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: TODO
|
if (!passwordsMatch) return null;
|
||||||
return users[0] as any;
|
return users[0] as any;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
@ -43,7 +43,6 @@ export const {
|
||||||
token,
|
token,
|
||||||
}: {
|
}: {
|
||||||
session: ExtendedSession;
|
session: ExtendedSession;
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: TODO
|
|
||||||
token: any;
|
token: any;
|
||||||
}) {
|
}) {
|
||||||
if (session.user) {
|
if (session.user) {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export default function Page() {
|
||||||
login,
|
login,
|
||||||
{
|
{
|
||||||
status: 'idle',
|
status: 'idle',
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export default function Page() {
|
||||||
register,
|
register,
|
||||||
{
|
{
|
||||||
status: 'idle',
|
status: 'idle',
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
'use server';
|
'use server';
|
||||||
|
|
||||||
import { CoreMessage, type CoreUserMessage, generateText } from 'ai';
|
import { type CoreUserMessage, generateText } from 'ai';
|
||||||
import { cookies } from 'next/headers';
|
import { cookies } from 'next/headers';
|
||||||
|
|
||||||
import { customModel } from '@/lib/ai';
|
import { customModel } from '@/lib/ai';
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ export async function POST(request: Request) {
|
||||||
}),
|
}),
|
||||||
execute: async ({ latitude, longitude }) => {
|
execute: async ({ latitude, longitude }) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m&hourly=temperature_2m&daily=sunrise,sunset&timezone=auto`
|
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m&hourly=temperature_2m&daily=sunrise,sunset&timezone=auto`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const weatherData = await response.json();
|
const weatherData = await response.json();
|
||||||
|
|
@ -350,7 +350,7 @@ export async function POST(request: Request) {
|
||||||
content: message.content,
|
content: message.content,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const FileSchema = z.object({
|
||||||
['image/jpeg', 'image/png', 'application/pdf'].includes(file.type),
|
['image/jpeg', 'image/png', 'application/pdf'].includes(file.type),
|
||||||
{
|
{
|
||||||
message: 'File type should be JPEG, PNG, or PDF',
|
message: 'File type should be JPEG, PNG, or PDF',
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ export async function POST(request: Request) {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: 'Failed to process request' },
|
{ error: 'Failed to process request' },
|
||||||
{ status: 500 }
|
{ status: 500 },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ export async function GET() {
|
||||||
return Response.json('Unauthorized!', { status: 401 });
|
return Response.json('Unauthorized!', { status: 401 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// biome-ignore lint: Forbidden non-null assertion.
|
||||||
const chats = await getChatsByUserId({ id: session.user.id! });
|
const chats = await getChatsByUserId({ id: session.user.id! });
|
||||||
return Response.json(chats);
|
return Response.json(chats);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { CoreMessage } from 'ai';
|
|
||||||
import { cookies } from 'next/headers';
|
import { cookies } from 'next/headers';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ export default async function RootLayout({
|
||||||
>
|
>
|
||||||
<head>
|
<head>
|
||||||
<script
|
<script
|
||||||
// biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>
|
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: THEME_COLOR_SCRIPT,
|
__html: THEME_COLOR_SCRIPT,
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
99
biome.json
99
biome.json
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||||
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": true },
|
|
||||||
"files": {
|
"files": {
|
||||||
"ignoreUnknown": false,
|
"ignoreUnknown": false,
|
||||||
"ignore": [
|
"ignore": [
|
||||||
|
|
@ -13,46 +12,118 @@
|
||||||
".vercel"
|
".vercel"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"vcs": {
|
||||||
|
"enabled": true,
|
||||||
|
"clientKind": "git",
|
||||||
|
"defaultBranch": "main",
|
||||||
|
"useIgnoreFile": true
|
||||||
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"useEditorconfig": true,
|
|
||||||
"formatWithErrors": false,
|
"formatWithErrors": false,
|
||||||
"indentStyle": "space",
|
"indentStyle": "space",
|
||||||
"indentWidth": 2,
|
"indentWidth": 2,
|
||||||
"lineEnding": "lf",
|
"lineEnding": "lf",
|
||||||
"lineWidth": 80,
|
"lineWidth": 80,
|
||||||
"attributePosition": "auto",
|
"attributePosition": "auto"
|
||||||
"bracketSpacing": true,
|
|
||||||
"ignore": ["**/pnpm-lock.yaml", "lib/db/drizzle"]
|
|
||||||
},
|
},
|
||||||
"organizeImports": { "enabled": true },
|
|
||||||
"linter": {
|
"linter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true,
|
"recommended": true,
|
||||||
"a11y": {
|
"a11y": {
|
||||||
"noSvgWithoutTitle": "off",
|
"useHtmlLang": "warn",
|
||||||
"useKeyWithClickEvents": "off"
|
"noHeaderScope": "warn",
|
||||||
|
"useValidAriaRole": {
|
||||||
|
"level": "warn",
|
||||||
|
"options": {
|
||||||
|
"ignoreNonDom": false,
|
||||||
|
"allowInvalidRoles": ["none", "text"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"style": {
|
"useSemanticElements": "off",
|
||||||
"noNonNullAssertion": "off"
|
"noSvgWithoutTitle": "off",
|
||||||
|
"useMediaCaption": "off",
|
||||||
|
"noAutofocus": "off",
|
||||||
|
"noBlankTarget": "off"
|
||||||
|
},
|
||||||
|
"complexity": {
|
||||||
|
"noUselessStringConcat": "warn",
|
||||||
|
"noForEach": "off",
|
||||||
|
"noUselessSwitchCase": "off",
|
||||||
|
"noUselessThisAlias": "off"
|
||||||
},
|
},
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"useExhaustiveDependencies": "off"
|
"noUnusedImports": "warn",
|
||||||
|
"useArrayLiterals": "warn",
|
||||||
|
"noNewSymbol": "warn",
|
||||||
|
"useJsxKeyInIterable": "off",
|
||||||
|
"useExhaustiveDependencies": "off",
|
||||||
|
"noUnnecessaryContinue": "off"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"noDangerouslySetInnerHtml": "off"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"useFragmentSyntax": "warn",
|
||||||
|
"noYodaExpression": "warn",
|
||||||
|
"useDefaultParameterLast": "warn",
|
||||||
|
"useExponentiationOperator": "off",
|
||||||
|
"noUnusedTemplateLiteral": "off",
|
||||||
|
"noUselessElse": "off"
|
||||||
|
},
|
||||||
|
"suspicious": {
|
||||||
|
"noExplicitAny": "off"
|
||||||
|
},
|
||||||
|
"nursery": {
|
||||||
|
"noStaticElementInteractions": "warn",
|
||||||
|
"noHeadImportInDocument": "warn",
|
||||||
|
"noDocumentImportInPage": "warn",
|
||||||
|
"noDuplicateElseIf": "warn",
|
||||||
|
"noIrregularWhitespace": "warn",
|
||||||
|
"useValidAutocomplete": "warn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"javascript": {
|
"javascript": {
|
||||||
|
"jsxRuntime": "reactClassic",
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"jsxQuoteStyle": "double",
|
"jsxQuoteStyle": "double",
|
||||||
"quoteProperties": "asNeeded",
|
"quoteProperties": "asNeeded",
|
||||||
"trailingCommas": "es5",
|
"trailingCommas": "all",
|
||||||
"semicolons": "always",
|
"semicolons": "always",
|
||||||
"arrowParentheses": "always",
|
"arrowParentheses": "always",
|
||||||
|
"bracketSpacing": true,
|
||||||
"bracketSameLine": false,
|
"bracketSameLine": false,
|
||||||
"quoteStyle": "single",
|
"quoteStyle": "single",
|
||||||
"attributePosition": "auto",
|
"attributePosition": "auto"
|
||||||
"bracketSpacing": true
|
}
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"trailingCommas": "none"
|
||||||
|
},
|
||||||
|
"parser": {
|
||||||
|
"allowComments": true,
|
||||||
|
"allowTrailingCommas": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"css": {
|
||||||
|
"formatter": { "enabled": false },
|
||||||
|
"linter": { "enabled": false }
|
||||||
|
},
|
||||||
|
"organizeImports": { "enabled": false },
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"include": ["playwright/**", "tooling/playwright/src/test/test.ts"],
|
||||||
|
"linter": {
|
||||||
|
"rules": {
|
||||||
|
"correctness": {
|
||||||
|
"noEmptyPattern": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
||||||
131
biome.jsonc
Normal file
131
biome.jsonc
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||||
|
"files": {
|
||||||
|
"ignoreUnknown": false,
|
||||||
|
"ignore": [
|
||||||
|
"**/pnpm-lock.yaml",
|
||||||
|
"lib/db/migrations",
|
||||||
|
"lib/editor/react-renderer.tsx",
|
||||||
|
"node_modules",
|
||||||
|
".next",
|
||||||
|
"public",
|
||||||
|
".vercel"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"vcs": {
|
||||||
|
"enabled": true,
|
||||||
|
"clientKind": "git",
|
||||||
|
"defaultBranch": "main",
|
||||||
|
"useIgnoreFile": true
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"formatWithErrors": false,
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"lineEnding": "lf",
|
||||||
|
"lineWidth": 80,
|
||||||
|
"attributePosition": "auto"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true,
|
||||||
|
"a11y": {
|
||||||
|
"useHtmlLang": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"noHeaderScope": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"useValidAriaRole": {
|
||||||
|
"level": "warn",
|
||||||
|
"options": {
|
||||||
|
"ignoreNonDom": false,
|
||||||
|
"allowInvalidRoles": ["none", "text"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"useSemanticElements": "off", // Rule is buggy, revisit later
|
||||||
|
"noSvgWithoutTitle": "off", // We do not intend to adhere to this rule
|
||||||
|
"useMediaCaption": "off", // We would need a cultural change to turn this on
|
||||||
|
"noAutofocus": "off", // We're highly intentional about when we use autofocus
|
||||||
|
"noBlankTarget": "off" // Covered by Conformance
|
||||||
|
},
|
||||||
|
"complexity": {
|
||||||
|
"noUselessStringConcat": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"noForEach": "off", // forEach is too familiar to ban
|
||||||
|
"noUselessSwitchCase": "off", // Turned off due to developer preferences
|
||||||
|
"noUselessThisAlias": "off" // Turned off due to developer preferences
|
||||||
|
},
|
||||||
|
"correctness": {
|
||||||
|
"noUnusedImports": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"useArrayLiterals": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"noNewSymbol": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"useJsxKeyInIterable": "off", // Rule is buggy, revisit later
|
||||||
|
"useExhaustiveDependencies": "off", // Community feedback on this rule has been poor, we will continue with ESLint
|
||||||
|
"noUnnecessaryContinue": "off" // Turned off due to developer preferences
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"noDangerouslySetInnerHtml": "off" // Covered by Conformance
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"useFragmentSyntax": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"noYodaExpression": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"useDefaultParameterLast": "warn", // Not in recommended ruleset, turning on manually
|
||||||
|
"useExponentiationOperator": "off", // Obscure and arguably not easily readable
|
||||||
|
"noUnusedTemplateLiteral": "off", // Stylistic opinion
|
||||||
|
"noUselessElse": "off" // Stylistic opinion
|
||||||
|
},
|
||||||
|
"suspicious": {
|
||||||
|
"noExplicitAny": "off" // We trust Vercelians to use any only when necessary
|
||||||
|
},
|
||||||
|
"nursery": {
|
||||||
|
"noStaticElementInteractions": "warn",
|
||||||
|
"noHeadImportInDocument": "warn",
|
||||||
|
"noDocumentImportInPage": "warn",
|
||||||
|
"noDuplicateElseIf": "warn",
|
||||||
|
"noIrregularWhitespace": "warn",
|
||||||
|
"useValidAutocomplete": "warn"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"jsxRuntime": "reactClassic",
|
||||||
|
"formatter": {
|
||||||
|
"jsxQuoteStyle": "double",
|
||||||
|
"quoteProperties": "asNeeded",
|
||||||
|
"trailingCommas": "all",
|
||||||
|
"semicolons": "always",
|
||||||
|
"arrowParentheses": "always",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"quoteStyle": "single",
|
||||||
|
"attributePosition": "auto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"trailingCommas": "none"
|
||||||
|
},
|
||||||
|
"parser": {
|
||||||
|
"allowComments": true,
|
||||||
|
"allowTrailingCommas": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"css": {
|
||||||
|
"formatter": { "enabled": false },
|
||||||
|
"linter": { "enabled": false }
|
||||||
|
},
|
||||||
|
"organizeImports": { "enabled": false },
|
||||||
|
"overrides": [
|
||||||
|
// Playwright requires an object destructure, even if empty
|
||||||
|
// https://github.com/microsoft/playwright/issues/30007
|
||||||
|
{
|
||||||
|
"include": ["playwright/**"],
|
||||||
|
"linter": {
|
||||||
|
"rules": {
|
||||||
|
"correctness": {
|
||||||
|
"noEmptyPattern": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ import {
|
||||||
useSidebar,
|
useSidebar,
|
||||||
} from '@/components/ui/sidebar';
|
} from '@/components/ui/sidebar';
|
||||||
import { BetterTooltip } from '@/components/ui/tooltip';
|
import { BetterTooltip } from '@/components/ui/tooltip';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
export function AppSidebar({ user }: { user: User | undefined }) {
|
export function AppSidebar({ user }: { user: User | undefined }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -28,21 +29,21 @@ export function AppSidebar({ user }: { user: User | undefined }) {
|
||||||
<SidebarHeader>
|
<SidebarHeader>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
<div
|
<Link
|
||||||
|
href="/"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpenMobile(false);
|
setOpenMobile(false);
|
||||||
router.push('/');
|
|
||||||
router.refresh();
|
|
||||||
}}
|
}}
|
||||||
className="flex flex-row gap-3 items-center"
|
className="flex flex-row gap-3 items-center"
|
||||||
>
|
>
|
||||||
<span className="text-lg font-semibold px-2 hover:bg-muted rounded-md cursor-pointer">
|
<span className="text-lg font-semibold px-2 hover:bg-muted rounded-md cursor-pointer">
|
||||||
Chatbot
|
Chatbot
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</Link>
|
||||||
<BetterTooltip content="New Chat" align="start">
|
<BetterTooltip content="New Chat" align="start">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
type="button"
|
||||||
className="p-2 h-fit"
|
className="p-2 h-fit"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpenMobile(false);
|
setOpenMobile(false);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export function PureBlockStreamHandler({
|
||||||
|
|
||||||
function areEqual(
|
function areEqual(
|
||||||
prevProps: BlockStreamHandlerProps,
|
prevProps: BlockStreamHandlerProps,
|
||||||
nextProps: BlockStreamHandlerProps
|
nextProps: BlockStreamHandlerProps,
|
||||||
) {
|
) {
|
||||||
if (!prevProps.streamingData && !nextProps.streamingData) {
|
if (!prevProps.streamingData && !nextProps.streamingData) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -80,13 +80,13 @@ export function Block({
|
||||||
votes: Array<Vote> | undefined;
|
votes: Array<Vote> | undefined;
|
||||||
append: (
|
append: (
|
||||||
message: Message | CreateMessage,
|
message: Message | CreateMessage,
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => Promise<string | null | undefined>;
|
) => Promise<string | null | undefined>;
|
||||||
handleSubmit: (
|
handleSubmit: (
|
||||||
event?: {
|
event?: {
|
||||||
preventDefault?: () => void;
|
preventDefault?: () => void;
|
||||||
},
|
},
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => void;
|
) => void;
|
||||||
}) {
|
}) {
|
||||||
const [messagesContainerRef, messagesEndRef] =
|
const [messagesContainerRef, messagesEndRef] =
|
||||||
|
|
@ -100,7 +100,7 @@ export function Block({
|
||||||
block && block.status !== 'streaming'
|
block && block.status !== 'streaming'
|
||||||
? `/api/document?id=${block.documentId}`
|
? `/api/document?id=${block.documentId}`
|
||||||
: null,
|
: null,
|
||||||
fetcher
|
fetcher,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: suggestions } = useSWR<Array<Suggestion>>(
|
const { data: suggestions } = useSWR<Array<Suggestion>>(
|
||||||
|
|
@ -110,7 +110,7 @@ export function Block({
|
||||||
fetcher,
|
fetcher,
|
||||||
{
|
{
|
||||||
dedupingInterval: 5000,
|
dedupingInterval: 5000,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const [mode, setMode] = useState<'edit' | 'diff'>('edit');
|
const [mode, setMode] = useState<'edit' | 'diff'>('edit');
|
||||||
|
|
@ -176,15 +176,15 @@ export function Block({
|
||||||
}
|
}
|
||||||
return currentDocuments;
|
return currentDocuments;
|
||||||
},
|
},
|
||||||
{ revalidate: false }
|
{ revalidate: false },
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[block, mutate]
|
[block, mutate],
|
||||||
);
|
);
|
||||||
|
|
||||||
const debouncedHandleContentChange = useDebounceCallback(
|
const debouncedHandleContentChange = useDebounceCallback(
|
||||||
handleContentChange,
|
handleContentChange,
|
||||||
2000
|
2000,
|
||||||
);
|
);
|
||||||
|
|
||||||
const saveContent = useCallback(
|
const saveContent = useCallback(
|
||||||
|
|
@ -199,7 +199,7 @@ export function Block({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[document, debouncedHandleContentChange, handleContentChange]
|
[document, debouncedHandleContentChange, handleContentChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
function getDocumentContentById(index: number) {
|
function getDocumentContentById(index: number) {
|
||||||
|
|
@ -430,7 +430,7 @@ export function Block({
|
||||||
new Date(),
|
new Date(),
|
||||||
{
|
{
|
||||||
addSuffix: true,
|
addSuffix: true,
|
||||||
}
|
},
|
||||||
)}`}
|
)}`}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -496,7 +496,7 @@ export function Block({
|
||||||
'p-2 h-fit !pointer-events-auto dark:hover:bg-zinc-700',
|
'p-2 h-fit !pointer-events-auto dark:hover:bg-zinc-700',
|
||||||
{
|
{
|
||||||
'bg-muted': mode === 'diff',
|
'bg-muted': mode === 'diff',
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleVersionChange('toggle');
|
handleVersionChange('toggle');
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ export function Chat({
|
||||||
|
|
||||||
const { data: votes } = useSWR<Array<Vote>>(
|
const { data: votes } = useSWR<Array<Vote>>(
|
||||||
`/api/vote?chatId=${id}`,
|
`/api/vote?chatId=${id}`,
|
||||||
fetcher
|
fetcher,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [messagesContainerRef, messagesEndRef] =
|
const [messagesContainerRef, messagesEndRef] =
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@ export const DiffView = ({ oldContent, newContent }: DiffEditorProps) => {
|
||||||
const parser = DOMParser.fromSchema(diffSchema);
|
const parser = DOMParser.fromSchema(diffSchema);
|
||||||
|
|
||||||
const oldHtmlContent = renderToString(
|
const oldHtmlContent = renderToString(
|
||||||
<ReactMarkdown>{oldContent}</ReactMarkdown>
|
<ReactMarkdown>{oldContent}</ReactMarkdown>,
|
||||||
);
|
);
|
||||||
const newHtmlContent = renderToString(
|
const newHtmlContent = renderToString(
|
||||||
<ReactMarkdown>{newContent}</ReactMarkdown>
|
<ReactMarkdown>{newContent}</ReactMarkdown>,
|
||||||
);
|
);
|
||||||
|
|
||||||
const oldContainer = document.createElement('div');
|
const oldContainer = document.createElement('div');
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ export function DocumentToolResult({
|
||||||
setBlock,
|
setBlock,
|
||||||
}: DocumentToolResultProps) {
|
}: DocumentToolResultProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<button
|
||||||
|
type="button"
|
||||||
className="bg-background cursor-pointer border py-2 px-3 rounded-xl w-fit flex flex-row gap-3 items-start"
|
className="bg-background cursor-pointer border py-2 px-3 rounded-xl w-fit flex flex-row gap-3 items-start"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
const rect = event.currentTarget.getBoundingClientRect();
|
const rect = event.currentTarget.getBoundingClientRect();
|
||||||
|
|
@ -64,7 +65,7 @@ export function DocumentToolResult({
|
||||||
<div className="">
|
<div className="">
|
||||||
{getActionText(type)} {result.title}
|
{getActionText(type)} {result.title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ function PureEditor({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editorRef.current && content) {
|
if (editorRef.current && content) {
|
||||||
const currentContent = buildContentFromDocument(
|
const currentContent = buildContentFromDocument(
|
||||||
editorRef.current.state.doc
|
editorRef.current.state.doc,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (status === 'streaming') {
|
if (status === 'streaming') {
|
||||||
|
|
@ -98,7 +98,7 @@ function PureEditor({
|
||||||
const transaction = editorRef.current.state.tr.replaceWith(
|
const transaction = editorRef.current.state.tr.replaceWith(
|
||||||
0,
|
0,
|
||||||
editorRef.current.state.doc.content.size,
|
editorRef.current.state.doc.content.size,
|
||||||
newDocument.content
|
newDocument.content,
|
||||||
);
|
);
|
||||||
|
|
||||||
transaction.setMeta('no-save', true);
|
transaction.setMeta('no-save', true);
|
||||||
|
|
@ -112,7 +112,7 @@ function PureEditor({
|
||||||
const transaction = editorRef.current.state.tr.replaceWith(
|
const transaction = editorRef.current.state.tr.replaceWith(
|
||||||
0,
|
0,
|
||||||
editorRef.current.state.doc.content.size,
|
editorRef.current.state.doc.content.size,
|
||||||
newDocument.content
|
newDocument.content,
|
||||||
);
|
);
|
||||||
|
|
||||||
transaction.setMeta('no-save', true);
|
transaction.setMeta('no-save', true);
|
||||||
|
|
@ -125,14 +125,14 @@ function PureEditor({
|
||||||
if (editorRef.current?.state.doc && content) {
|
if (editorRef.current?.state.doc && content) {
|
||||||
const projectedSuggestions = projectWithPositions(
|
const projectedSuggestions = projectWithPositions(
|
||||||
editorRef.current.state.doc,
|
editorRef.current.state.doc,
|
||||||
suggestions
|
suggestions,
|
||||||
).filter(
|
).filter(
|
||||||
(suggestion) => suggestion.selectionStart && suggestion.selectionEnd
|
(suggestion) => suggestion.selectionStart && suggestion.selectionEnd,
|
||||||
);
|
);
|
||||||
|
|
||||||
const decorations = createDecorations(
|
const decorations = createDecorations(
|
||||||
projectedSuggestions,
|
projectedSuggestions,
|
||||||
editorRef.current
|
editorRef.current,
|
||||||
);
|
);
|
||||||
|
|
||||||
const transaction = editorRef.current.state.tr;
|
const transaction = editorRef.current.state.tr;
|
||||||
|
|
|
||||||
|
|
@ -119,5 +119,5 @@ const NonMemoizedMarkdown = ({ children }: { children: string }) => {
|
||||||
|
|
||||||
export const Markdown = memo(
|
export const Markdown = memo(
|
||||||
NonMemoizedMarkdown,
|
NonMemoizedMarkdown,
|
||||||
(prevProps, nextProps) => prevProps.children === nextProps.children
|
(prevProps, nextProps) => prevProps.children === nextProps.children,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export function MessageActions({
|
||||||
if (!currentVotes) return [];
|
if (!currentVotes) return [];
|
||||||
|
|
||||||
const votesWithoutCurrent = currentVotes.filter(
|
const votesWithoutCurrent = currentVotes.filter(
|
||||||
(vote) => vote.messageId !== message.id
|
(vote) => vote.messageId !== message.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
@ -92,7 +92,7 @@ export function MessageActions({
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
{ revalidate: false }
|
{ revalidate: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
return 'Upvoted Response!';
|
return 'Upvoted Response!';
|
||||||
|
|
@ -134,7 +134,7 @@ export function MessageActions({
|
||||||
if (!currentVotes) return [];
|
if (!currentVotes) return [];
|
||||||
|
|
||||||
const votesWithoutCurrent = currentVotes.filter(
|
const votesWithoutCurrent = currentVotes.filter(
|
||||||
(vote) => vote.messageId !== message.id
|
(vote) => vote.messageId !== message.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
@ -146,7 +146,7 @@ export function MessageActions({
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
{ revalidate: false }
|
{ revalidate: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
return 'Downvoted Response!';
|
return 'Downvoted Response!';
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export const PreviewMessage = ({
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
'group-data-[role=user]/message:bg-primary group-data-[role=user]/message:text-primary-foreground flex gap-4 group-data-[role=user]/message:px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl group-data-[role=user]/message:py-2 rounded-xl'
|
'group-data-[role=user]/message:bg-primary group-data-[role=user]/message:text-primary-foreground flex gap-4 group-data-[role=user]/message:px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl group-data-[role=user]/message:py-2 rounded-xl',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{message.role === 'assistant' && (
|
{message.role === 'assistant' && (
|
||||||
|
|
@ -158,7 +158,7 @@ export const ThinkingMessage = () => {
|
||||||
'flex gap-4 group-data-[role=user]/message:px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl group-data-[role=user]/message:py-2 rounded-xl',
|
'flex gap-4 group-data-[role=user]/message:px-3 w-full group-data-[role=user]/message:w-fit group-data-[role=user]/message:ml-auto group-data-[role=user]/message:max-w-2xl group-data-[role=user]/message:py-2 rounded-xl',
|
||||||
{
|
{
|
||||||
'group-data-[role=user]/message:bg-muted': true,
|
'group-data-[role=user]/message:bg-muted': true,
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="size-8 flex items-center rounded-full justify-center ring-1 shrink-0 ring-border">
|
<div className="size-8 flex items-center rounded-full justify-center ring-1 shrink-0 ring-border">
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export function ModelSelector({
|
||||||
|
|
||||||
const selectModel = useMemo(
|
const selectModel = useMemo(
|
||||||
() => models.find((model) => model.id === optimisticModelId),
|
() => models.find((model) => model.id === optimisticModelId),
|
||||||
[optimisticModelId]
|
[optimisticModelId],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -36,7 +36,7 @@ export function ModelSelector({
|
||||||
asChild
|
asChild
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-fit data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
'w-fit data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Button variant="outline" className="md:px-2 md:h-[34px]">
|
<Button variant="outline" className="md:px-2 md:h-[34px]">
|
||||||
|
|
|
||||||
|
|
@ -66,13 +66,13 @@ export function MultimodalInput({
|
||||||
setMessages: Dispatch<SetStateAction<Array<Message>>>;
|
setMessages: Dispatch<SetStateAction<Array<Message>>>;
|
||||||
append: (
|
append: (
|
||||||
message: Message | CreateMessage,
|
message: Message | CreateMessage,
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => Promise<string | null | undefined>;
|
) => Promise<string | null | undefined>;
|
||||||
handleSubmit: (
|
handleSubmit: (
|
||||||
event?: {
|
event?: {
|
||||||
preventDefault?: () => void;
|
preventDefault?: () => void;
|
||||||
},
|
},
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => void;
|
) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -94,7 +94,7 @@ export function MultimodalInput({
|
||||||
|
|
||||||
const [localStorageInput, setLocalStorageInput] = useLocalStorage(
|
const [localStorageInput, setLocalStorageInput] = useLocalStorage(
|
||||||
'input',
|
'input',
|
||||||
''
|
'',
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -180,7 +180,7 @@ export function MultimodalInput({
|
||||||
const uploadPromises = files.map((file) => uploadFile(file));
|
const uploadPromises = files.map((file) => uploadFile(file));
|
||||||
const uploadedAttachments = await Promise.all(uploadPromises);
|
const uploadedAttachments = await Promise.all(uploadPromises);
|
||||||
const successfullyUploadedAttachments = uploadedAttachments.filter(
|
const successfullyUploadedAttachments = uploadedAttachments.filter(
|
||||||
(attachment) => attachment !== undefined
|
(attachment) => attachment !== undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
setAttachments((currentAttachments) => [
|
setAttachments((currentAttachments) => [
|
||||||
|
|
@ -193,7 +193,7 @@ export function MultimodalInput({
|
||||||
setUploadQueue([]);
|
setUploadQueue([]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setAttachments]
|
[setAttachments],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -269,7 +269,7 @@ export function MultimodalInput({
|
||||||
onChange={handleInput}
|
onChange={handleInput}
|
||||||
className={cx(
|
className={cx(
|
||||||
'min-h-[24px] max-h-[calc(75dvh)] overflow-hidden resize-none rounded-xl text-base bg-muted',
|
'min-h-[24px] max-h-[calc(75dvh)] overflow-hidden resize-none rounded-xl text-base bg-muted',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
rows={3}
|
rows={3}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ export function SidebarHistory({ user }: { user: User | undefined }) {
|
||||||
lastWeek: [],
|
lastWeek: [],
|
||||||
lastMonth: [],
|
lastMonth: [],
|
||||||
older: [],
|
older: [],
|
||||||
} as GroupedChats
|
} as GroupedChats,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import type { ComponentProps } from 'react';
|
||||||
|
|
||||||
import { type SidebarTrigger, useSidebar } from '@/components/ui/sidebar';
|
import { type SidebarTrigger, useSidebar } from '@/components/ui/sidebar';
|
||||||
import { BetterTooltip } from '@/components/ui/tooltip';
|
import { BetterTooltip } from '@/components/ui/tooltip';
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
|
|
||||||
import { SidebarLeftIcon } from './icons';
|
import { SidebarLeftIcon } from './icons';
|
||||||
import { Button } from './ui/button';
|
import { Button } from './ui/button';
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,15 @@ export const Suggestion = ({
|
||||||
<div className="size-4 bg-muted-foreground/25 rounded-full" />
|
<div className="size-4 bg-muted-foreground/25 rounded-full" />
|
||||||
<div className="font-medium">Assistant</div>
|
<div className="font-medium">Assistant</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<button
|
||||||
|
type="button"
|
||||||
className="text-xs text-gray-500 cursor-pointer"
|
className="text-xs text-gray-500 cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsExpanded(false);
|
setIsExpanded(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CrossIcon size={12} />
|
<CrossIcon size={12} />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>{suggestion.description}</div>
|
<div>{suggestion.description}</div>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import {
|
||||||
StopIcon,
|
StopIcon,
|
||||||
SummarizeIcon,
|
SummarizeIcon,
|
||||||
} from './icons';
|
} from './icons';
|
||||||
import { Button } from './ui/button';
|
|
||||||
|
|
||||||
type ToolProps = {
|
type ToolProps = {
|
||||||
type: 'final-polish' | 'request-suggestions' | 'adjust-reading-level';
|
type: 'final-polish' | 'request-suggestions' | 'adjust-reading-level';
|
||||||
|
|
@ -45,7 +44,7 @@ type ToolProps = {
|
||||||
isAnimating: boolean;
|
isAnimating: boolean;
|
||||||
append: (
|
append: (
|
||||||
message: Message | CreateMessage,
|
message: Message | CreateMessage,
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => Promise<string | null | undefined>;
|
) => Promise<string | null | undefined>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -159,7 +158,7 @@ const ReadingLevelSelector = ({
|
||||||
isAnimating: boolean;
|
isAnimating: boolean;
|
||||||
append: (
|
append: (
|
||||||
message: Message | CreateMessage,
|
message: Message | CreateMessage,
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => Promise<string | null | undefined>;
|
) => Promise<string | null | undefined>;
|
||||||
}) => {
|
}) => {
|
||||||
const LEVELS = [
|
const LEVELS = [
|
||||||
|
|
@ -212,7 +211,7 @@ const ReadingLevelSelector = ({
|
||||||
{
|
{
|
||||||
'bg-primary text-primary-foreground': currentLevel !== 2,
|
'bg-primary text-primary-foreground': currentLevel !== 2,
|
||||||
'bg-background text-foreground': currentLevel === 2,
|
'bg-background text-foreground': currentLevel === 2,
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
style={{ y }}
|
style={{ y }}
|
||||||
drag="y"
|
drag="y"
|
||||||
|
|
@ -272,7 +271,7 @@ export const Tools = ({
|
||||||
setSelectedTool: Dispatch<SetStateAction<string | null>>;
|
setSelectedTool: Dispatch<SetStateAction<string | null>>;
|
||||||
append: (
|
append: (
|
||||||
message: Message | CreateMessage,
|
message: Message | CreateMessage,
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => Promise<string | null | undefined>;
|
) => Promise<string | null | undefined>;
|
||||||
isAnimating: boolean;
|
isAnimating: boolean;
|
||||||
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
|
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
|
||||||
|
|
@ -338,7 +337,7 @@ export const Toolbar = ({
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
append: (
|
append: (
|
||||||
message: Message | CreateMessage,
|
message: Message | CreateMessage,
|
||||||
chatRequestOptions?: ChatRequestOptions
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => Promise<string | null | undefined>;
|
) => Promise<string | null | undefined>;
|
||||||
stop: () => void;
|
stop: () => void;
|
||||||
setMessages: Dispatch<SetStateAction<Message[]>>;
|
setMessages: Dispatch<SetStateAction<Message[]>>;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ const AlertDialogOverlay = React.forwardRef<
|
||||||
<AlertDialogPrimitive.Overlay
|
<AlertDialogPrimitive.Overlay
|
||||||
className={cn(
|
className={cn(
|
||||||
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|
@ -37,7 +37,7 @@ const AlertDialogContent = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -52,7 +52,7 @@ const AlertDialogHeader = ({
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col space-y-2 text-center sm:text-left',
|
'flex flex-col space-y-2 text-center sm:text-left',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -66,7 +66,7 @@ const AlertDialogFooter = ({
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -119,7 +119,7 @@ const AlertDialogCancel = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({ variant: 'outline' }),
|
buttonVariants({ variant: 'outline' }),
|
||||||
'mt-2 sm:mt-0',
|
'mt-2 sm:mt-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ const buttonVariants = cva(
|
||||||
variant: 'default',
|
variant: 'default',
|
||||||
size: 'default',
|
size: 'default',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
|
|
@ -49,7 +49,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Button.displayName = 'Button';
|
Button.displayName = 'Button';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ const Card = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'rounded-lg border bg-card text-card-foreground shadow-sm',
|
'rounded-lg border bg-card text-card-foreground shadow-sm',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -37,7 +37,7 @@ const CardTitle = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-2xl font-semibold leading-none tracking-tight',
|
'text-2xl font-semibold leading-none tracking-tight',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
|
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
|
||||||
inset && 'pl-8',
|
inset && 'pl-8',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
@ -48,7 +48,7 @@ const DropdownMenuSubContent = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -66,7 +66,7 @@ const DropdownMenuContent = React.forwardRef<
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
'z-50 min-w-[8rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
'z-50 min-w-[8rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -85,7 +85,7 @@ const DropdownMenuItem = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex gap-2 cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
'relative flex gap-2 cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
||||||
inset && 'pl-8',
|
inset && 'pl-8',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -100,7 +100,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -124,7 +124,7 @@ const DropdownMenuRadioItem = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
@ -149,7 +149,7 @@ const DropdownMenuLabel = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'px-2 py-1.5 text-sm font-semibold',
|
'px-2 py-1.5 text-sm font-semibold',
|
||||||
inset && 'pl-8',
|
inset && 'pl-8',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
type={type}
|
type={type}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Input.displayName = 'Input';
|
Input.displayName = 'Input';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const labelVariants = cva(
|
const labelVariants = cva(
|
||||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
|
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
||||||
);
|
);
|
||||||
|
|
||||||
const Label = React.forwardRef<
|
const Label = React.forwardRef<
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const SelectTrigger = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
@ -40,7 +40,7 @@ const SelectScrollUpButton = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex cursor-default items-center justify-center py-1',
|
'flex cursor-default items-center justify-center py-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
@ -57,7 +57,7 @@ const SelectScrollDownButton = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex cursor-default items-center justify-center py-1',
|
'flex cursor-default items-center justify-center py-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
@ -78,7 +78,7 @@ const SelectContent = React.forwardRef<
|
||||||
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
position === 'popper' &&
|
position === 'popper' &&
|
||||||
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
position={position}
|
position={position}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -88,7 +88,7 @@ const SelectContent = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'p-1',
|
'p-1',
|
||||||
position === 'popper' &&
|
position === 'popper' &&
|
||||||
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
|
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
@ -119,7 +119,7 @@ const SelectItem = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const Separator = React.forwardRef<
|
||||||
>(
|
>(
|
||||||
(
|
(
|
||||||
{ className, orientation = 'horizontal', decorative = true, ...props },
|
{ className, orientation = 'horizontal', decorative = true, ...props },
|
||||||
ref
|
ref,
|
||||||
) => (
|
) => (
|
||||||
<SeparatorPrimitive.Root
|
<SeparatorPrimitive.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|
@ -20,11 +20,11 @@ const Separator = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'shrink-0 bg-border',
|
'shrink-0 bg-border',
|
||||||
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ const SheetOverlay = React.forwardRef<
|
||||||
<SheetPrimitive.Overlay
|
<SheetPrimitive.Overlay
|
||||||
className={cn(
|
className={cn(
|
||||||
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|
@ -46,7 +46,7 @@ const sheetVariants = cva(
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
side: 'right',
|
side: 'right',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
interface SheetContentProps
|
interface SheetContentProps
|
||||||
|
|
@ -81,7 +81,7 @@ const SheetHeader = ({
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col space-y-2 text-center sm:text-left',
|
'flex flex-col space-y-2 text-center sm:text-left',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -95,7 +95,7 @@ const SheetFooter = ({
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ const SidebarProvider = React.forwardRef<
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
},
|
},
|
||||||
ref
|
ref,
|
||||||
) => {
|
) => {
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const [openMobile, setOpenMobile] = React.useState(false);
|
const [openMobile, setOpenMobile] = React.useState(false);
|
||||||
|
|
@ -91,7 +91,7 @@ const SidebarProvider = React.forwardRef<
|
||||||
// This sets the cookie to keep the sidebar state.
|
// This sets the cookie to keep the sidebar state.
|
||||||
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
||||||
},
|
},
|
||||||
[setOpenProp, open]
|
[setOpenProp, open],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Helper to toggle the sidebar.
|
// Helper to toggle the sidebar.
|
||||||
|
|
@ -131,7 +131,15 @@ const SidebarProvider = React.forwardRef<
|
||||||
setOpenMobile,
|
setOpenMobile,
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
}),
|
}),
|
||||||
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
[
|
||||||
|
state,
|
||||||
|
open,
|
||||||
|
setOpen,
|
||||||
|
isMobile,
|
||||||
|
openMobile,
|
||||||
|
setOpenMobile,
|
||||||
|
toggleSidebar,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -147,7 +155,7 @@ const SidebarProvider = React.forwardRef<
|
||||||
}
|
}
|
||||||
className={cn(
|
className={cn(
|
||||||
'group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar',
|
'group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
data-state={state}
|
data-state={state}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|
@ -158,7 +166,7 @@ const SidebarProvider = React.forwardRef<
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</SidebarContext.Provider>
|
</SidebarContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
SidebarProvider.displayName = 'SidebarProvider';
|
SidebarProvider.displayName = 'SidebarProvider';
|
||||||
|
|
||||||
|
|
@ -179,7 +187,7 @@ const Sidebar = React.forwardRef<
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
},
|
},
|
||||||
ref
|
ref,
|
||||||
) => {
|
) => {
|
||||||
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
||||||
|
|
||||||
|
|
@ -188,7 +196,7 @@ const Sidebar = React.forwardRef<
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground',
|
'flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -239,7 +247,7 @@ const Sidebar = React.forwardRef<
|
||||||
'group-data-[side=right]:rotate-180',
|
'group-data-[side=right]:rotate-180',
|
||||||
variant === 'floating' || variant === 'inset'
|
variant === 'floating' || variant === 'inset'
|
||||||
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'
|
? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'
|
||||||
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]'
|
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
|
|
@ -252,7 +260,7 @@ const Sidebar = React.forwardRef<
|
||||||
variant === 'floating' || variant === 'inset'
|
variant === 'floating' || variant === 'inset'
|
||||||
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'
|
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'
|
||||||
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',
|
: 'group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
@ -265,7 +273,7 @@ const Sidebar = React.forwardRef<
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Sidebar.displayName = 'Sidebar';
|
Sidebar.displayName = 'Sidebar';
|
||||||
|
|
||||||
|
|
@ -315,7 +323,7 @@ const SidebarRail = React.forwardRef<
|
||||||
'group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar',
|
'group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar',
|
||||||
'[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
|
'[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
|
||||||
'[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
|
'[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -333,7 +341,7 @@ const SidebarInset = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative flex min-h-svh flex-1 flex-col bg-background',
|
'relative flex min-h-svh flex-1 flex-col bg-background',
|
||||||
'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow',
|
'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -351,7 +359,7 @@ const SidebarInput = React.forwardRef<
|
||||||
data-sidebar="input"
|
data-sidebar="input"
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',
|
'h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -414,7 +422,7 @@ const SidebarContent = React.forwardRef<
|
||||||
data-sidebar="content"
|
data-sidebar="content"
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden',
|
'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -450,7 +458,7 @@ const SidebarGroupLabel = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'duration-200 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
'duration-200 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
||||||
'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
|
'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -473,7 +481,7 @@ const SidebarGroupAction = React.forwardRef<
|
||||||
// Increases the hit area of the button on mobile.
|
// Increases the hit area of the button on mobile.
|
||||||
'after:absolute after:-inset-2 after:md:hidden',
|
'after:absolute after:-inset-2 after:md:hidden',
|
||||||
'group-data-[collapsible=icon]:hidden',
|
'group-data-[collapsible=icon]:hidden',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -539,7 +547,7 @@ const sidebarMenuButtonVariants = cva(
|
||||||
variant: 'default',
|
variant: 'default',
|
||||||
size: 'default',
|
size: 'default',
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const SidebarMenuButton = React.forwardRef<
|
const SidebarMenuButton = React.forwardRef<
|
||||||
|
|
@ -560,7 +568,7 @@ const SidebarMenuButton = React.forwardRef<
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
},
|
},
|
||||||
ref
|
ref,
|
||||||
) => {
|
) => {
|
||||||
const Comp = asChild ? Slot : 'button';
|
const Comp = asChild ? Slot : 'button';
|
||||||
const { isMobile, state } = useSidebar();
|
const { isMobile, state } = useSidebar();
|
||||||
|
|
@ -597,7 +605,7 @@ const SidebarMenuButton = React.forwardRef<
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
SidebarMenuButton.displayName = 'SidebarMenuButton';
|
SidebarMenuButton.displayName = 'SidebarMenuButton';
|
||||||
|
|
||||||
|
|
@ -624,7 +632,7 @@ const SidebarMenuAction = React.forwardRef<
|
||||||
'group-data-[collapsible=icon]:hidden',
|
'group-data-[collapsible=icon]:hidden',
|
||||||
showOnHover &&
|
showOnHover &&
|
||||||
'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',
|
'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -646,7 +654,7 @@ const SidebarMenuBadge = React.forwardRef<
|
||||||
'peer-data-[size=default]/menu-button:top-1.5',
|
'peer-data-[size=default]/menu-button:top-1.5',
|
||||||
'peer-data-[size=lg]/menu-button:top-2.5',
|
'peer-data-[size=lg]/menu-button:top-2.5',
|
||||||
'group-data-[collapsible=icon]:hidden',
|
'group-data-[collapsible=icon]:hidden',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -701,7 +709,7 @@ const SidebarMenuSub = React.forwardRef<
|
||||||
className={cn(
|
className={cn(
|
||||||
'mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5',
|
'mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5',
|
||||||
'group-data-[collapsible=icon]:hidden',
|
'group-data-[collapsible=icon]:hidden',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
@ -736,7 +744,7 @@ const SidebarMenuSubButton = React.forwardRef<
|
||||||
size === 'sm' && 'text-xs',
|
size === 'sm' && 'text-xs',
|
||||||
size === 'md' && 'text-sm',
|
size === 'md' && 'text-sm',
|
||||||
'group-data-[collapsible=icon]:hidden',
|
'group-data-[collapsible=icon]:hidden',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||||
<textarea
|
<textarea
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Textarea.displayName = 'Textarea';
|
Textarea.displayName = 'Textarea';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const TooltipContent = React.forwardRef<
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||||
className
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ export const VersionFooter = ({
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
timestamp: getDocumentTimestampByIndex(
|
timestamp: getDocumentTimestampByIndex(
|
||||||
documents,
|
documents,
|
||||||
currentVersionIndex
|
currentVersionIndex,
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
@ -75,14 +75,14 @@ export const VersionFooter = ({
|
||||||
new Date(
|
new Date(
|
||||||
getDocumentTimestampByIndex(
|
getDocumentTimestampByIndex(
|
||||||
documents,
|
documents,
|
||||||
currentVersionIndex
|
currentVersionIndex,
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -207,10 +207,10 @@ export function Weather({
|
||||||
weatherAtLocation?: WeatherAtLocation;
|
weatherAtLocation?: WeatherAtLocation;
|
||||||
}) {
|
}) {
|
||||||
const currentHigh = Math.max(
|
const currentHigh = Math.max(
|
||||||
...weatherAtLocation.hourly.temperature_2m.slice(0, 24)
|
...weatherAtLocation.hourly.temperature_2m.slice(0, 24),
|
||||||
);
|
);
|
||||||
const currentLow = Math.min(
|
const currentLow = Math.min(
|
||||||
...weatherAtLocation.hourly.temperature_2m.slice(0, 24)
|
...weatherAtLocation.hourly.temperature_2m.slice(0, 24),
|
||||||
);
|
);
|
||||||
|
|
||||||
const isDay = isWithinInterval(new Date(weatherAtLocation.current.time), {
|
const isDay = isWithinInterval(new Date(weatherAtLocation.current.time), {
|
||||||
|
|
@ -235,17 +235,17 @@ export function Weather({
|
||||||
|
|
||||||
// Find the index of the current time or the next closest time
|
// Find the index of the current time or the next closest time
|
||||||
const currentTimeIndex = weatherAtLocation.hourly.time.findIndex(
|
const currentTimeIndex = weatherAtLocation.hourly.time.findIndex(
|
||||||
(time) => new Date(time) >= new Date(weatherAtLocation.current.time)
|
(time) => new Date(time) >= new Date(weatherAtLocation.current.time),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Slice the arrays to get the desired number of items
|
// Slice the arrays to get the desired number of items
|
||||||
const displayTimes = weatherAtLocation.hourly.time.slice(
|
const displayTimes = weatherAtLocation.hourly.time.slice(
|
||||||
currentTimeIndex,
|
currentTimeIndex,
|
||||||
currentTimeIndex + hoursToShow
|
currentTimeIndex + hoursToShow,
|
||||||
);
|
);
|
||||||
const displayTemperatures = weatherAtLocation.hourly.temperature_2m.slice(
|
const displayTemperatures = weatherAtLocation.hourly.temperature_2m.slice(
|
||||||
currentTimeIndex,
|
currentTimeIndex,
|
||||||
currentTimeIndex + hoursToShow
|
currentTimeIndex + hoursToShow,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -257,7 +257,7 @@ export function Weather({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'bg-indigo-900': !isDay,
|
'bg-indigo-900': !isDay,
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
|
|
@ -270,7 +270,7 @@ export function Weather({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'bg-indigo-100': !isDay,
|
'bg-indigo-100': !isDay,
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="text-4xl font-medium text-blue-50">
|
<div className="text-4xl font-medium text-blue-50">
|
||||||
|
|
@ -296,7 +296,7 @@ export function Weather({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'bg-indigo-200': !isDay,
|
'bg-indigo-200': !isDay,
|
||||||
}
|
},
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="text-blue-50 text-sm">
|
<div className="text-blue-50 text-sm">
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ export default defineConfig({
|
||||||
out: './lib/db/migrations',
|
out: './lib/db/migrations',
|
||||||
dialect: 'postgresql',
|
dialect: 'postgresql',
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
|
// biome-ignore lint: Forbidden non-null assertion.
|
||||||
url: process.env.POSTGRES_URL!,
|
url: process.env.POSTGRES_URL!,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ const MOBILE_BREAKPOINT = 768;
|
||||||
|
|
||||||
export function useIsMobile() {
|
export function useIsMobile() {
|
||||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
|
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
|
||||||
undefined
|
undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import {
|
||||||
// Optionally, if not using email/pass login, you can
|
// Optionally, if not using email/pass login, you can
|
||||||
// use the Drizzle adapter for Auth.js / NextAuth
|
// use the Drizzle adapter for Auth.js / NextAuth
|
||||||
// https://authjs.dev/reference/adapter/drizzle
|
// https://authjs.dev/reference/adapter/drizzle
|
||||||
|
|
||||||
|
// biome-ignore lint: Forbidden non-null assertion.
|
||||||
const client = postgres(`${process.env.POSTGRES_URL!}?sslmode=require`);
|
const client = postgres(`${process.env.POSTGRES_URL!}?sslmode=require`);
|
||||||
const db = drizzle(client);
|
const db = drizzle(client);
|
||||||
|
|
||||||
|
|
@ -232,8 +234,8 @@ export async function deleteDocumentsByIdAfterTimestamp({
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(suggestion.documentId, id),
|
eq(suggestion.documentId, id),
|
||||||
gt(suggestion.documentCreatedAt, timestamp)
|
gt(suggestion.documentCreatedAt, timestamp),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return await db
|
return await db
|
||||||
|
|
@ -241,7 +243,7 @@ export async function deleteDocumentsByIdAfterTimestamp({
|
||||||
.where(and(eq(document.id, id), gt(document.createdAt, timestamp)));
|
.where(and(eq(document.id, id), gt(document.createdAt, timestamp)));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
'Failed to delete documents by id after timestamp from database'
|
'Failed to delete documents by id after timestamp from database',
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +274,7 @@ export async function getSuggestionsByDocumentId({
|
||||||
.where(and(eq(suggestion.documentId, documentId)));
|
.where(and(eq(suggestion.documentId, documentId)));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
'Failed to get suggestions by document version from database'
|
'Failed to get suggestions by document version from database',
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export const vote = pgTable(
|
||||||
return {
|
return {
|
||||||
pk: primaryKey({ columns: [table.chatId, table.messageId] }),
|
pk: primaryKey({ columns: [table.chatId, table.messageId] }),
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export type Vote = InferSelectModel<typeof vote>;
|
export type Vote = InferSelectModel<typeof vote>;
|
||||||
|
|
@ -77,7 +77,7 @@ export const document = pgTable(
|
||||||
return {
|
return {
|
||||||
pk: primaryKey({ columns: [table.id, table.createdAt] }),
|
pk: primaryKey({ columns: [table.id, table.createdAt] }),
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export type Document = InferSelectModel<typeof document>;
|
export type Document = InferSelectModel<typeof document>;
|
||||||
|
|
@ -103,7 +103,7 @@ export const suggestion = pgTable(
|
||||||
columns: [table.documentId, table.documentCreatedAt],
|
columns: [table.documentId, table.documentCreatedAt],
|
||||||
foreignColumns: [document.id, document.createdAt],
|
foreignColumns: [document.id, document.createdAt],
|
||||||
}),
|
}),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export type Suggestion = InferSelectModel<typeof suggestion>;
|
export type Suggestion = InferSelectModel<typeof suggestion>;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export function headingRule(level: number) {
|
||||||
return textblockTypeInputRule(
|
return textblockTypeInputRule(
|
||||||
new RegExp(`^(#{1,${level}})\\s$`),
|
new RegExp(`^(#{1,${level}})\\s$`),
|
||||||
documentSchema.nodes.heading,
|
documentSchema.nodes.heading,
|
||||||
() => ({ level })
|
() => ({ level }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export const patchDocumentNode = (schema, oldNode, newNode) => {
|
||||||
const matchedNodes = matchNodes(
|
const matchedNodes = matchNodes(
|
||||||
schema,
|
schema,
|
||||||
diffOldChildren,
|
diffOldChildren,
|
||||||
diffNewChildren
|
diffNewChildren,
|
||||||
).sort((a, b) => b.count - a.count);
|
).sort((a, b) => b.count - a.count);
|
||||||
const bestMatch = matchedNodes[0];
|
const bestMatch = matchedNodes[0];
|
||||||
if (bestMatch) {
|
if (bestMatch) {
|
||||||
|
|
@ -62,11 +62,11 @@ export const patchDocumentNode = (schema, oldNode, newNode) => {
|
||||||
...patchRemainNodes(
|
...patchRemainNodes(
|
||||||
schema,
|
schema,
|
||||||
oldBeforeMatchChildren,
|
oldBeforeMatchChildren,
|
||||||
newBeforeMatchChildren
|
newBeforeMatchChildren,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
finalLeftChildren.push(
|
finalLeftChildren.push(
|
||||||
...diffOldChildren.slice(oldStartIndex, oldEndIndex)
|
...diffOldChildren.slice(oldStartIndex, oldEndIndex),
|
||||||
);
|
);
|
||||||
|
|
||||||
const oldAfterMatchChildren = diffOldChildren.slice(oldEndIndex);
|
const oldAfterMatchChildren = diffOldChildren.slice(oldEndIndex);
|
||||||
|
|
@ -76,17 +76,17 @@ export const patchDocumentNode = (schema, oldNode, newNode) => {
|
||||||
...patchRemainNodes(
|
...patchRemainNodes(
|
||||||
schema,
|
schema,
|
||||||
oldAfterMatchChildren,
|
oldAfterMatchChildren,
|
||||||
newAfterMatchChildren
|
newAfterMatchChildren,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
finalLeftChildren.push(
|
finalLeftChildren.push(
|
||||||
...patchRemainNodes(schema, diffOldChildren, diffNewChildren)
|
...patchRemainNodes(schema, diffOldChildren, diffNewChildren),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
finalLeftChildren.push(
|
finalLeftChildren.push(
|
||||||
...patchRemainNodes(schema, diffOldChildren, diffNewChildren)
|
...patchRemainNodes(schema, diffOldChildren, diffNewChildren),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +155,7 @@ const patchRemainNodes = (schema, oldChildren, newChildren) => {
|
||||||
!isTextNode(rightOldNode) && matchNodeType(rightOldNode, rightNewNode);
|
!isTextNode(rightOldNode) && matchNodeType(rightOldNode, rightNewNode);
|
||||||
if (Array.isArray(leftOldNode) && Array.isArray(leftNewNode)) {
|
if (Array.isArray(leftOldNode) && Array.isArray(leftNewNode)) {
|
||||||
finalLeftChildren.push(
|
finalLeftChildren.push(
|
||||||
...patchTextNodes(schema, leftOldNode, leftNewNode)
|
...patchTextNodes(schema, leftOldNode, leftNewNode),
|
||||||
);
|
);
|
||||||
left += 1;
|
left += 1;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -165,7 +165,7 @@ const patchRemainNodes = (schema, oldChildren, newChildren) => {
|
||||||
const equalityLeft = computeChildEqualityFactor(leftOldNode, leftNewNode);
|
const equalityLeft = computeChildEqualityFactor(leftOldNode, leftNewNode);
|
||||||
const equalityRight = computeChildEqualityFactor(
|
const equalityRight = computeChildEqualityFactor(
|
||||||
rightOldNode,
|
rightOldNode,
|
||||||
rightNewNode
|
rightNewNode,
|
||||||
);
|
);
|
||||||
if (equalityLeft < equalityRight) {
|
if (equalityLeft < equalityRight) {
|
||||||
updateLeft = false;
|
updateLeft = false;
|
||||||
|
|
@ -175,21 +175,21 @@ const patchRemainNodes = (schema, oldChildren, newChildren) => {
|
||||||
}
|
}
|
||||||
if (updateLeft) {
|
if (updateLeft) {
|
||||||
finalLeftChildren.push(
|
finalLeftChildren.push(
|
||||||
patchDocumentNode(schema, leftOldNode, leftNewNode)
|
patchDocumentNode(schema, leftOldNode, leftNewNode),
|
||||||
);
|
);
|
||||||
left += 1;
|
left += 1;
|
||||||
} else if (updateRight) {
|
} else if (updateRight) {
|
||||||
finalRightChildren.unshift(
|
finalRightChildren.unshift(
|
||||||
patchDocumentNode(schema, rightOldNode, rightNewNode)
|
patchDocumentNode(schema, rightOldNode, rightNewNode),
|
||||||
);
|
);
|
||||||
right += 1;
|
right += 1;
|
||||||
} else {
|
} else {
|
||||||
// Delete and insert
|
// Delete and insert
|
||||||
finalLeftChildren.push(
|
finalLeftChildren.push(
|
||||||
createDiffNode(schema, leftOldNode, DiffType.Deleted)
|
createDiffNode(schema, leftOldNode, DiffType.Deleted),
|
||||||
);
|
);
|
||||||
finalLeftChildren.push(
|
finalLeftChildren.push(
|
||||||
createDiffNode(schema, leftNewNode, DiffType.Inserted)
|
createDiffNode(schema, leftNewNode, DiffType.Inserted),
|
||||||
);
|
);
|
||||||
left += 1;
|
left += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +202,7 @@ const patchRemainNodes = (schema, oldChildren, newChildren) => {
|
||||||
...oldChildren
|
...oldChildren
|
||||||
.slice(left, left + deleteNodeLen)
|
.slice(left, left + deleteNodeLen)
|
||||||
.flat()
|
.flat()
|
||||||
.map((node) => createDiffNode(schema, node, DiffType.Deleted))
|
.map((node) => createDiffNode(schema, node, DiffType.Deleted)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,7 +211,7 @@ const patchRemainNodes = (schema, oldChildren, newChildren) => {
|
||||||
...newChildren
|
...newChildren
|
||||||
.slice(left, left + insertNodeLen)
|
.slice(left, left + insertNodeLen)
|
||||||
.flat()
|
.flat()
|
||||||
.map((node) => createDiffNode(schema, node, DiffType.Inserted))
|
.map((node) => createDiffNode(schema, node, DiffType.Inserted)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +233,7 @@ export const patchTextNodes = (schema, oldNode, newNode) => {
|
||||||
// Map sentences to unique characters
|
// Map sentences to unique characters
|
||||||
const { chars1, chars2, lineArray } = sentencesToChars(
|
const { chars1, chars2, lineArray } = sentencesToChars(
|
||||||
oldSentences,
|
oldSentences,
|
||||||
newSentences
|
newSentences,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Perform the diff
|
// Perform the diff
|
||||||
|
|
@ -253,7 +253,7 @@ export const patchTextNodes = (schema, oldNode, newNode) => {
|
||||||
const node = createTextNode(
|
const node = createTextNode(
|
||||||
schema,
|
schema,
|
||||||
sentence,
|
sentence,
|
||||||
type !== DiffType.Unchanged ? [createDiffMark(schema, type)] : []
|
type !== DiffType.Unchanged ? [createDiffMark(schema, type)] : [],
|
||||||
);
|
);
|
||||||
return node;
|
return node;
|
||||||
});
|
});
|
||||||
|
|
@ -427,7 +427,7 @@ export const createNewNode = (oldNode, children) => {
|
||||||
oldNode.type,
|
oldNode.type,
|
||||||
oldNode.attrs,
|
oldNode.attrs,
|
||||||
Fragment.fromArray(children),
|
Fragment.fromArray(children),
|
||||||
oldNode.marks
|
oldNode.marks,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -448,8 +448,8 @@ function mapDocumentNode(node, mapper) {
|
||||||
Fragment.from(
|
Fragment.from(
|
||||||
node.content.content
|
node.content.content
|
||||||
.map((node) => mapDocumentNode(node, mapper))
|
.map((node) => mapDocumentNode(node, mapper))
|
||||||
.filter((n) => n)
|
.filter((n) => n),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
return mapper(copy) || copy;
|
return mapper(copy) || copy;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export const buildContentFromDocument = (document: Node) => {
|
||||||
|
|
||||||
export const createDecorations = (
|
export const createDecorations = (
|
||||||
suggestions: Array<UISuggestion>,
|
suggestions: Array<UISuggestion>,
|
||||||
view: EditorView
|
view: EditorView,
|
||||||
) => {
|
) => {
|
||||||
const decorations: Array<Decoration> = [];
|
const decorations: Array<Decoration> = [];
|
||||||
|
|
||||||
|
|
@ -39,8 +39,8 @@ export const createDecorations = (
|
||||||
{
|
{
|
||||||
suggestionId: suggestion.id,
|
suggestionId: suggestion.id,
|
||||||
type: 'highlight',
|
type: 'highlight',
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
decorations.push(
|
decorations.push(
|
||||||
|
|
@ -53,8 +53,8 @@ export const createDecorations = (
|
||||||
{
|
{
|
||||||
suggestionId: suggestion.id,
|
suggestionId: suggestion.id,
|
||||||
type: 'widget',
|
type: 'widget',
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ function findPositionsInDoc(doc: Node, searchText: string): Position | null {
|
||||||
|
|
||||||
export function projectWithPositions(
|
export function projectWithPositions(
|
||||||
doc: Node,
|
doc: Node,
|
||||||
suggestions: Array<Suggestion>
|
suggestions: Array<Suggestion>,
|
||||||
): Array<UISuggestion> {
|
): Array<UISuggestion> {
|
||||||
return suggestions.map((suggestion) => {
|
return suggestions.map((suggestion) => {
|
||||||
const positions = findPositionsInDoc(doc, suggestion.originalText);
|
const positions = findPositionsInDoc(doc, suggestion.originalText);
|
||||||
|
|
@ -68,7 +68,7 @@ export function projectWithPositions(
|
||||||
|
|
||||||
export function createSuggestionWidget(
|
export function createSuggestionWidget(
|
||||||
suggestion: UISuggestion,
|
suggestion: UISuggestion,
|
||||||
view: EditorView
|
view: EditorView,
|
||||||
): { dom: HTMLElement; destroy: () => void } {
|
): { dom: HTMLElement; destroy: () => void } {
|
||||||
const dom = document.createElement('span');
|
const dom = document.createElement('span');
|
||||||
const root = createRoot(dom);
|
const root = createRoot(dom);
|
||||||
|
|
@ -90,7 +90,7 @@ export function createSuggestionWidget(
|
||||||
state.doc,
|
state.doc,
|
||||||
currentDecorations.find().filter((decoration: Decoration) => {
|
currentDecorations.find().filter((decoration: Decoration) => {
|
||||||
return decoration.spec.suggestionId !== suggestion.id;
|
return decoration.spec.suggestionId !== suggestion.id;
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
decorationTransaction.setMeta(suggestionsPluginKey, {
|
decorationTransaction.setMeta(suggestionsPluginKey, {
|
||||||
|
|
@ -103,7 +103,7 @@ export function createSuggestionWidget(
|
||||||
const textTransaction = view.state.tr.replaceWith(
|
const textTransaction = view.state.tr.replaceWith(
|
||||||
suggestion.selectionStart,
|
suggestion.selectionStart,
|
||||||
suggestion.selectionEnd,
|
suggestion.selectionEnd,
|
||||||
state.schema.text(suggestion.suggestedText)
|
state.schema.text(suggestion.suggestedText),
|
||||||
);
|
);
|
||||||
|
|
||||||
textTransaction.setMeta('no-debounce', true);
|
textTransaction.setMeta('no-debounce', true);
|
||||||
|
|
|
||||||
18
lib/utils.ts
18
lib/utils.ts
|
|
@ -24,7 +24,7 @@ export const fetcher = async (url: string) => {
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const error = new Error(
|
const error = new Error(
|
||||||
'An error occurred while fetching the data.'
|
'An error occurred while fetching the data.',
|
||||||
) as ApplicationError;
|
) as ApplicationError;
|
||||||
|
|
||||||
error.info = await res.json();
|
error.info = await res.json();
|
||||||
|
|
@ -64,7 +64,7 @@ function addToolMessageToChat({
|
||||||
...message,
|
...message,
|
||||||
toolInvocations: message.toolInvocations.map((toolInvocation) => {
|
toolInvocations: message.toolInvocations.map((toolInvocation) => {
|
||||||
const toolResult = toolMessage.content.find(
|
const toolResult = toolMessage.content.find(
|
||||||
(tool) => tool.toolCallId === toolInvocation.toolCallId
|
(tool) => tool.toolCallId === toolInvocation.toolCallId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (toolResult) {
|
if (toolResult) {
|
||||||
|
|
@ -85,7 +85,7 @@ function addToolMessageToChat({
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertToUIMessages(
|
export function convertToUIMessages(
|
||||||
messages: Array<DBMessage>
|
messages: Array<DBMessage>,
|
||||||
): Array<Message> {
|
): Array<Message> {
|
||||||
return messages.reduce((chatMessages: Array<Message>, message) => {
|
return messages.reduce((chatMessages: Array<Message>, message) => {
|
||||||
if (message.role === 'tool') {
|
if (message.role === 'tool') {
|
||||||
|
|
@ -127,7 +127,7 @@ export function convertToUIMessages(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sanitizeResponseMessages(
|
export function sanitizeResponseMessages(
|
||||||
messages: Array<CoreToolMessage | CoreAssistantMessage>
|
messages: Array<CoreToolMessage | CoreAssistantMessage>,
|
||||||
): Array<CoreToolMessage | CoreAssistantMessage> {
|
): Array<CoreToolMessage | CoreAssistantMessage> {
|
||||||
const toolResultIds: Array<string> = [];
|
const toolResultIds: Array<string> = [];
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ export function sanitizeResponseMessages(
|
||||||
? toolResultIds.includes(content.toolCallId)
|
? toolResultIds.includes(content.toolCallId)
|
||||||
: content.type === 'text'
|
: content.type === 'text'
|
||||||
? content.text.length > 0
|
? content.text.length > 0
|
||||||
: true
|
: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -161,7 +161,7 @@ export function sanitizeResponseMessages(
|
||||||
});
|
});
|
||||||
|
|
||||||
return messagesBySanitizedContent.filter(
|
return messagesBySanitizedContent.filter(
|
||||||
(message) => message.content.length > 0
|
(message) => message.content.length > 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,7 +182,7 @@ export function sanitizeUIMessages(messages: Array<Message>): Array<Message> {
|
||||||
const sanitizedToolInvocations = message.toolInvocations.filter(
|
const sanitizedToolInvocations = message.toolInvocations.filter(
|
||||||
(toolInvocation) =>
|
(toolInvocation) =>
|
||||||
toolInvocation.state === 'result' ||
|
toolInvocation.state === 'result' ||
|
||||||
toolResultIds.includes(toolInvocation.toolCallId)
|
toolResultIds.includes(toolInvocation.toolCallId),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -194,7 +194,7 @@ export function sanitizeUIMessages(messages: Array<Message>): Array<Message> {
|
||||||
return messagesBySanitizedToolInvocations.filter(
|
return messagesBySanitizedToolInvocations.filter(
|
||||||
(message) =>
|
(message) =>
|
||||||
message.content.length > 0 ||
|
message.content.length > 0 ||
|
||||||
(message.toolInvocations && message.toolInvocations.length > 0)
|
(message.toolInvocations && message.toolInvocations.length > 0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,7 +205,7 @@ export function getMostRecentUserMessage(messages: Array<CoreMessage>) {
|
||||||
|
|
||||||
export function getDocumentTimestampByIndex(
|
export function getDocumentTimestampByIndex(
|
||||||
documents: Array<Document>,
|
documents: Array<Document>,
|
||||||
index: number
|
index: number,
|
||||||
) {
|
) {
|
||||||
if (!documents) return new Date();
|
if (!documents) return new Date();
|
||||||
if (index > documents.length) return new Date();
|
if (index > documents.length) return new Date();
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
"dev": "next dev --turbo",
|
"dev": "next dev --turbo",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint && biome lint --write --unsafe",
|
||||||
"lint:fix": "next lint --fix && biome lint --write --unsafe",
|
"lint:fix": "next lint --fix && biome lint --write --unsafe",
|
||||||
"format": "biome format --write",
|
"format": "biome format --write",
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue