diff --git a/app/(chat)/page.tsx b/app/(chat)/chat/page.tsx similarity index 95% rename from app/(chat)/page.tsx rename to app/(chat)/chat/page.tsx index 85d31a0..75044b5 100644 --- a/app/(chat)/page.tsx +++ b/app/(chat)/chat/page.tsx @@ -4,7 +4,7 @@ import { Chat } from '@/components/chat'; import { DEFAULT_CHAT_MODEL } from '@/lib/ai/models'; import { generateUUID } from '@/lib/utils'; import { DataStreamHandler } from '@/components/data-stream-handler'; -import { auth } from '../(auth)/auth'; +import { auth } from '../../(auth)/auth'; import { redirect } from 'next/navigation'; export default async function Page() { @@ -31,7 +31,7 @@ export default async function Page() { initialVisibilityType="private" isReadonly={false} session={session} - autoResume={false} + autoResume={false} initialApiKey={apiKeyFromCookie?.value ?? ''} /> diff --git a/app/globals.css b/app/globals.css index ed93ab9..1ef04dd 100644 --- a/app/globals.css +++ b/app/globals.css @@ -6,6 +6,16 @@ --foreground-rgb: 0, 0, 0; --background-start-rgb: 214, 219, 220; --background-end-rgb: 255, 255, 255; + --black: #040404; + --tower-gray: #aec0bd; + --mountain-meadow: #169994; + --deep-sea-green: #076057; + --tiber: #042d2d; + --corduroy: #5b6464; + --mine-shaft: #2c2c2c; + --blue-chill: #087a85; + --blue-whale: #043b44; + --black-pearl: #071b24; } /* Light-only: remove dark scheme overrides */ @@ -120,5 +130,9 @@ } .suggestion-highlight { - @apply bg-blue-200 hover:bg-blue-300; + background-color: rgba(7, 96, 87, 0.2); +} + +.suggestion-highlight:hover { + background-color: rgba(7, 96, 87, 0.3); } diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..eca2661 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,21 @@ +import Link from 'next/link'; +import Spline from '@splinetool/react-spline/next'; + +export default function Home() { + return ( +
+ +
+ + Try Demo + +
+
+ ); +} diff --git a/components/message.tsx b/components/message.tsx index 7661d14..d9f2276 100644 --- a/components/message.tsx +++ b/components/message.tsx @@ -52,7 +52,7 @@ const PurePreviewMessage = ({ >
{ className={cx( '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-[var(--deep-sea-green)] group-data-[role=user]/message:text-white': true, }, )} > diff --git a/components/webset-table.tsx b/components/webset-table.tsx index 2653f48..41c6663 100644 --- a/components/webset-table.tsx +++ b/components/webset-table.tsx @@ -269,10 +269,21 @@ export function WebsetTable({ csv }: WebsetTableProps) { style={{ width: columnWidths[header] ?? 150 }} className="px-4 py-2 font-bold border-r border-b border-border bg-muted sticky top-0 z-10" > -
{ - if (sortedColumn === header) setSortDirection((d) => (d === 'asc' ? 'desc' : 'asc')); - else setSortedColumn(header); - }}> +
{ + if (sortedColumn === header) setSortDirection((d) => (d === 'asc' ? 'desc' : 'asc')); + else setSortedColumn(header); + }} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + if (sortedColumn === header) setSortDirection((d) => (d === 'asc' ? 'desc' : 'asc')); + else setSortedColumn(header); + } + }} + > {visibleColumns[header] === false ? ( {header} diff --git a/lib/googleTokens.ts b/lib/googleTokens.ts index a3752d5..ef66fdc 100644 --- a/lib/googleTokens.ts +++ b/lib/googleTokens.ts @@ -18,7 +18,8 @@ export async function getFreshAccessToken(): Promise { const tokenSet = getTokenSet(sessionId); let accessToken = jar.get('gc_access_token')?.value || tokenSet?.access_token; - let refreshToken = jar.get('gc_refresh_token')?.value || tokenSet?.refresh_token; + let refreshToken = + jar.get('gc_refresh_token')?.value || tokenSet?.refresh_token; const expiresAtStr = jar.get('gc_expires_at')?.value || (tokenSet?.expires_at != null ? String(tokenSet.expires_at) : undefined); @@ -26,16 +27,20 @@ export async function getFreshAccessToken(): Promise { const now = Date.now(); const isExpiringSoon = expiresAt != null && now > expiresAt - EXPIRY_SKEW_MS; - const shouldRefresh = Boolean(refreshToken && (!accessToken || isExpiringSoon)); + const shouldRefresh = Boolean( + refreshToken && (!accessToken || isExpiringSoon), + ); - if (shouldRefresh) { + if (shouldRefresh && refreshToken) { try { const config = await getGoogleClient(); - const refreshed = await refreshTokenGrant(config, refreshToken!); + const refreshed = await refreshTokenGrant(config, refreshToken); accessToken = refreshed.access_token || accessToken; refreshToken = refreshed.refresh_token || refreshToken; expiresAt = - refreshed.expires_in != null ? now + refreshed.expires_in * 1000 : expiresAt; + refreshed.expires_in != null + ? now + refreshed.expires_in * 1000 + : expiresAt; // Persist refreshed tokens const cookieOptions = { @@ -46,7 +51,8 @@ export async function getFreshAccessToken(): Promise { maxAge: 60 * 60 * 24 * 7, }; if (accessToken) jar.set('gc_access_token', accessToken, cookieOptions); - if (refreshToken) jar.set('gc_refresh_token', refreshToken, cookieOptions); + if (refreshToken) + jar.set('gc_refresh_token', refreshToken, cookieOptions); if (expiresAt) jar.set('gc_expires_at', String(expiresAt), cookieOptions); if (sessionId) { const existing = tokenSet || {}; @@ -64,4 +70,3 @@ export async function getFreshAccessToken(): Promise { return { accessToken, refreshToken, expiresAt }; } - diff --git a/package.json b/package.json index f12672a..242f391 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "test": "export PLAYWRIGHT=True && pnpm exec playwright test" }, "dependencies": { - "@ai-sdk/react": "^1.2.11", "@ai-sdk/openai": "^1.2.15", + "@ai-sdk/react": "^1.2.11", "@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-python": "^6.1.6", "@codemirror/state": "^6.5.0", @@ -33,11 +33,13 @@ "@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-popover": "^1.1.2", "@radix-ui/react-select": "^2.1.2", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.3", "@radix-ui/react-visually-hidden": "^1.1.0", + "@splinetool/react-spline": "^4.1.0", "@vercel/analytics": "^1.3.1", "@vercel/blob": "^0.24.1", "@vercel/functions": "^2.0.0", @@ -61,6 +63,7 @@ "next": "15.3.0-canary.31", "next-auth": "5.0.0-beta.25", "next-themes": "^0.3.0", + "openid-client": "^6.6.4", "orderedmap": "^2.1.1", "papaparse": "^5.5.2", "postgres": "^3.4.4", @@ -86,9 +89,7 @@ "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7", "usehooks-ts": "^3.1.0", - "zod": "^3.23.8", - "@radix-ui/react-popover": "^1.1.2", - "openid-client": "^6.6.4" + "zod": "^3.23.8" }, "devDependencies": { "@biomejs/biome": "1.9.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 021bece..3c543fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,9 @@ importers: '@radix-ui/react-visually-hidden': specifier: ^1.1.0 version: 1.1.2(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) + '@splinetool/react-spline': + specifier: ^4.1.0 + version: 4.1.0(@splinetool/runtime@1.10.53)(next@15.3.0-canary.31(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021))(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) '@vercel/analytics': specifier: ^1.3.1 version: 1.5.0(next@15.3.0-canary.31(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) @@ -1785,6 +1788,20 @@ packages: '@rushstack/eslint-patch@1.11.0': resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==} + '@splinetool/react-spline@4.1.0': + resolution: {integrity: sha512-Y379gm17gw+1nxT/YXTCJnVIWuu7tsUH1tp/YxsYb0pZnc9Gljk7Om4Kpq7WPq0bZ4zidVCxf6xn6jgDcbHifQ==} + peerDependencies: + '@splinetool/runtime': '*' + next: '>=14.2.0' + react: '*' + react-dom: '*' + peerDependenciesMeta: + next: + optional: true + + '@splinetool/runtime@1.10.53': + resolution: {integrity: sha512-C0hl9yTbfr9sTbdTtVJ1g2K5DKNs1ijlgR9LWWp+rYfSnF0NJzYsozJ/Wra5RDJq/mUG6BPG52v+zpIMCV41mg==} + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -2088,6 +2105,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + blurhash@2.0.5: + resolution: {integrity: sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -3374,6 +3394,10 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + on-change@4.0.2: + resolution: {integrity: sha512-cMtCyuJmTx/bg2HCpHo3ZLeF7FZnBOapLqZHr2AlLeJ5Ul0Zu2mUJJz051Fdwu/Et2YW04ZD+TtU+gVy0ACNCA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3652,6 +3676,9 @@ packages: '@types/react': '>=18' react: '>=18' + react-merge-refs@2.1.1: + resolution: {integrity: sha512-jLQXJ/URln51zskhgppGJ2ub7b2WFKGq3cl3NYKtlHoTG+dN2q7EzWrn3hN3EgPsTMvpR9tpq5ijdp7YwFZkag==} + react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -3779,6 +3806,9 @@ packages: secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -3990,6 +4020,9 @@ packages: resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} engines: {node: '>=18'} + thumbhash@0.1.1: + resolution: {integrity: sha512-kH5pKeIIBPQXAOni2AiY/Cu/NKdkFREdpH+TLdM0g6WA7RriCv0kPLgP731ady67MhTAqrVG/4mnEeibVuCJcg==} + tinyglobby@0.2.12: resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} engines: {node: '>=12.0.0'} @@ -5421,6 +5454,23 @@ snapshots: '@rushstack/eslint-patch@1.11.0': {} + '@splinetool/react-spline@4.1.0(@splinetool/runtime@1.10.53)(next@15.3.0-canary.31(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021))(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)': + dependencies: + '@splinetool/runtime': 1.10.53 + blurhash: 2.0.5 + lodash.debounce: 4.0.8 + react: 19.0.0-rc-45804af1-20241021 + react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021) + react-merge-refs: 2.1.1 + thumbhash: 0.1.1 + optionalDependencies: + next: 15.3.0-canary.31(@opentelemetry/api@1.9.0)(@playwright/test@1.51.0)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021) + + '@splinetool/runtime@1.10.53': + dependencies: + on-change: 4.0.2 + semver-compare: 1.0.0 + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.15': @@ -5722,6 +5772,8 @@ snapshots: binary-extensions@2.3.0: {} + blurhash@2.0.5: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -7358,6 +7410,8 @@ snapshots: obuf@1.1.2: {} + on-change@4.0.2: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -7670,6 +7724,8 @@ snapshots: transitivePeerDependencies: - supports-color + react-merge-refs@2.1.1: {} + react-remove-scroll-bar@2.3.8(@types/react@18.3.18)(react@19.0.0-rc-45804af1-20241021): dependencies: react: 19.0.0-rc-45804af1-20241021 @@ -7829,6 +7885,8 @@ snapshots: secure-json-parse@2.7.0: {} + semver-compare@1.0.0: {} + semver@6.3.1: {} semver@7.7.1: {} @@ -8110,6 +8168,8 @@ snapshots: throttleit@2.1.0: {} + thumbhash@0.1.1: {} + tinyglobby@0.2.12: dependencies: fdir: 6.4.3(picomatch@4.0.2)