Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- [ ] check if Bulk add dialog and Bulk edit dialog can use a common logic instead of duplicating the code.
- [ ] remove the demo routes and data, but add the learning and knowledge base to the docs (learning.md).
- [ ] add in account deletion option, also need to think of how to handle the case when user deletes their account from clerk, panel.
- [ ] update /docs and not found page.

---

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "tijori",
"private": true,
"type": "module",
"version": "0.0.12",
"version": "0.0.13",
"scripts": {
"dev": "vite dev",
"dev:convex": "bunx convex dev",
Expand Down
80 changes: 80 additions & 0 deletions src/components/docs-components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useState } from "react";
import { Check, Copy } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

interface DocsCodeBlockProps {
code: string;
language?: string;
className?: string;
}

export function DocsCodeBlock({ code, language = "bash", className }: DocsCodeBlockProps) {
const [copied, setCopied] = useState(false);

const handleCopy = () => {
navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
Comment on lines +15 to +18

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Clipboard write not awaited - shows success even on failure

The handleCopy function in DocsCodeBlock does not await the Promise returned by navigator.clipboard.writeText() and sets copied to true unconditionally. This means the UI will show "copied" feedback even if the clipboard operation fails.

Click to expand

Problem

The code immediately sets copied(true) without waiting for the clipboard operation to complete:

const handleCopy = () => {
  navigator.clipboard.writeText(code);
  setCopied(true); // Called immediately, not after promise resolves
  setTimeout(() => setCopied(false), 2000);
};

Comparison with existing patterns

Other clipboard usages in the codebase properly await and handle errors:

  • src/components/share-dialog.tsx:210 uses await navigator.clipboard.writeText(shareUrl)
  • src/components/environment-variables/useVariableActions.ts:66 uses await with try-catch

Impact

Users may see the "copied" checkmark icon even when:

  • Clipboard permissions are denied
  • The browser doesn't support the Clipboard API
  • The operation fails for any other reason

This could lead to user frustration when they paste and find nothing was copied.

Recommendation: Change the function to be async and await the clipboard operation with error handling:

const handleCopy = async () => {
  try {
    await navigator.clipboard.writeText(code);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  } catch (err) {
    console.error("Failed to copy:", err);
  }
};
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +15 to +18

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 DocsCodeBlock clipboard copy sets success state even when clipboard API fails

The clipboard copy handler doesn't handle errors, causing the UI to show a success state even when the copy operation fails.

Click to expand

Issue

In src/components/docs-components.tsx:15-18:

const handleCopy = () => {
  navigator.clipboard.writeText(code);
  setCopied(true);
  setTimeout(() => setCopied(false), 2000);
};

navigator.clipboard.writeText() returns a Promise that can reject in several scenarios:

  • Non-secure contexts (HTTP instead of HTTPS)
  • User denies clipboard permission
  • Browser doesn't support the Clipboard API

Since the Promise isn't awaited or caught, the code immediately sets copied to true regardless of whether the operation succeeded.

Actual vs Expected Behavior

  • Actual: User sees checkmark indicating success even when copy fails
  • Expected: Should only show success indicator when copy actually succeeds, or show an error state on failure

Recommendation: Add async/await with try-catch to handle clipboard errors: const handleCopy = async () => { try { await navigator.clipboard.writeText(code); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch { /* optionally show error */ } };

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

};
Comment on lines +15 to +19
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add error handling for clipboard operations.

navigator.clipboard.writeText() can fail (e.g., permissions denied, non-secure context). The promise rejection is currently unhandled.

🛠️ Proposed fix
   const handleCopy = () => {
-    navigator.clipboard.writeText(code);
-    setCopied(true);
-    setTimeout(() => setCopied(false), 2000);
+    navigator.clipboard.writeText(code)
+      .then(() => {
+        setCopied(true);
+        setTimeout(() => setCopied(false), 2000);
+      })
+      .catch((err) => {
+        console.error("Failed to copy:", err);
+      });
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleCopy = () => {
navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const handleCopy = () => {
navigator.clipboard.writeText(code)
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
.catch((err) => {
console.error("Failed to copy:", err);
});
};
🤖 Prompt for AI Agents
In `@src/components/docs-components.tsx` around lines 15 - 19, The handleCopy
function must handle failures from navigator.clipboard.writeText: change it to
await or use .then/.catch around navigator.clipboard.writeText(code) and only
call setCopied(true) when the promise resolves; on rejection log or surface the
error (e.g., console.error or show a UI error) and ensure any timeout cleanup
(the setTimeout that clears setCopied) is not scheduled on failure; update the
handleCopy implementation accordingly so navigator.clipboard.writeText,
setCopied, and the clear timeout are coordinated and errors are handled.


return (
<div
className={cn(
"group relative my-6 overflow-hidden rounded-lg border border-border/60 bg-muted/30",
className
)}
>
<div className="flex items-center justify-between border-b border-border/40 bg-muted/20 px-4 py-2">
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/60">
{language}
</span>
<Button
variant="ghost"
size="icon-sm"
className="h-6 w-6 text-muted-foreground transition-all hover:bg-primary/10 hover:text-primary"
onClick={handleCopy}
>
{copied ? <Check className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
</Button>
Comment on lines +32 to +39
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing title attribute on copy Button.

🛠️ Proposed fix
         <Button
           variant="ghost"
           size="icon-sm"
           className="h-6 w-6 text-muted-foreground transition-all hover:bg-primary/10 hover:text-primary"
           onClick={handleCopy}
+          title="Copy code to clipboard"
         >
           {copied ? <Check className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
         </Button>

As per coding guidelines: "Add title attribute to Button components from @/components/ui/button".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Button
variant="ghost"
size="icon-sm"
className="h-6 w-6 text-muted-foreground transition-all hover:bg-primary/10 hover:text-primary"
onClick={handleCopy}
>
{copied ? <Check className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
</Button>
<Button
variant="ghost"
size="icon-sm"
className="h-6 w-6 text-muted-foreground transition-all hover:bg-primary/10 hover:text-primary"
onClick={handleCopy}
title="Copy code to clipboard"
>
{copied ? <Check className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
</Button>
🤖 Prompt for AI Agents
In `@src/components/docs-components.tsx` around lines 32 - 39, The Button used for
copy in the Docs component is missing an accessible title; update the Button
component instance that uses onClick={handleCopy} (the one rendering {copied ?
<Check .../> : <Copy .../>}) to include a descriptive title attribute (e.g.,
"Copy code" / "Copied") to satisfy the guideline for Button components from
'@/components/ui/button' and improve accessibility.

</div>
<div className="relative">
<pre className="overflow-x-auto p-4 font-mono text-xs leading-relaxed text-muted-foreground">
<code>{code}</code>
</pre>
</div>
</div>
);
}

interface DocsStepHeaderProps {
children: React.ReactNode;
className?: string;
}

/**
* Step header that automatically numbers itself when used inside a container with 'docs-step-container' class
*/
export function DocsStepHeader({ children, className }: DocsStepHeaderProps) {
return (
<div className={cn("docs-step-header flex items-center gap-4 mb-4 group", className)}>
<div className="docs-step-number flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-[15px] font-black text-primary-foreground shadow-lg shadow-primary/20 transition-transform group-hover:scale-110" />
<h2 className="text-2xl font-bold tracking-tight text-foreground transition-colors group-hover:text-primary">
{children}
</h2>
</div>
);
}

interface DocsHeaderProps {
children: React.ReactNode;
className?: string;
}

export function DocsHeader({ children, className }: DocsHeaderProps) {
return (
<h2 className={cn("text-2xl font-bold tracking-tight text-foreground mb-6", className)}>
{children}
</h2>
);
}
91 changes: 91 additions & 0 deletions src/components/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Link } from "@tanstack/react-router";
import { ArrowLeft, FileText, HelpCircle, Home } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

interface NotFoundProps {
title?: string;
description?: string;
backLink?: string;
backText?: string;
isDocs?: boolean;
}

export function NotFound({
title = "Page Not Found",
description = "Oops! The page you're looking for seems to have vanished into the vault.",
backLink = "/",
backText = "Back to Home",
isDocs = false,
}: NotFoundProps) {
return (
<div
className={cn(
"flex flex-col items-center justify-center px-6 transition-all duration-700 animate-in fade-in slide-in-from-bottom-8",
isDocs ? "min-h-[400px] py-12" : "min-h-[80vh] py-20"
)}
>
<div className="relative mb-8">
<div className="absolute inset-0 blur-3xl opacity-20 bg-primary rounded-full animate-pulse" />
<div className="relative flex h-24 w-24 items-center justify-center rounded-3xl bg-muted/50 border border-border/50 text-primary shadow-2xl backdrop-blur-sm">
<HelpCircle className="h-12 w-12 animate-bounce" />
</div>
</div>

<div className="max-w-md text-center space-y-4">
<h1 className="text-4xl font-extrabold tracking-tight sm:text-5xl bg-clip-text text-transparent bg-linear-to-b from-foreground to-foreground/70">
404
</h1>
<h2 className="text-2xl font-bold tracking-tight text-foreground">{title}</h2>
<p className="text-muted-foreground text-lg leading-relaxed">{description}</p>
</div>

<div className="mt-10 flex flex-wrap items-center justify-center gap-4">
<Link to={backLink}>
<Button
size="lg"
className="rounded-xl gap-2 shadow-xl shadow-primary/20 font-semibold group"
>
<ArrowLeft className="h-4 w-4 transition-transform group-hover:-translate-x-1" />
{backText}
</Button>
</Link>
<Link to="/">
<Button variant="outline" size="lg" className="rounded-xl gap-2 font-semibold">
<Home className="h-4 w-4" />
Dashboard
</Button>
</Link>
{!isDocs && (
<Link to="/docs">
<Button variant="ghost" size="lg" className="rounded-xl gap-2 font-semibold">
<FileText className="h-4 w-4" />
Read Docs
</Button>
</Link>
Comment on lines +45 to +65
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing title attributes on Button components.

Button components should include title attributes for accessibility and tooltip support.

🛠️ Proposed fix
         <Link to={backLink}>
           <Button
             size="lg"
             className="rounded-xl gap-2 shadow-xl shadow-primary/20 font-semibold group"
+            title={backText}
           >
             <ArrowLeft className="h-4 w-4 transition-transform group-hover:-translate-x-1" />
             {backText}
           </Button>
         </Link>
         <Link to="/">
-          <Button variant="outline" size="lg" className="rounded-xl gap-2 font-semibold">
+          <Button variant="outline" size="lg" className="rounded-xl gap-2 font-semibold" title="Go to Dashboard">
             <Home className="h-4 w-4" />
             Dashboard
           </Button>
         </Link>
         {!isDocs && (
           <Link to="/docs">
-            <Button variant="ghost" size="lg" className="rounded-xl gap-2 font-semibold">
+            <Button variant="ghost" size="lg" className="rounded-xl gap-2 font-semibold" title="Read documentation">
               <FileText className="h-4 w-4" />
               Read Docs
             </Button>
           </Link>
         )}

As per coding guidelines: "Add title attribute to Button components from @/components/ui/button".

🤖 Prompt for AI Agents
In `@src/components/not-found.tsx` around lines 45 - 65, The Button components
rendered in not-found.tsx (the Button from '@/components/ui/button' used for the
back link, Dashboard and Read Docs) are missing title attributes; add a
descriptive title prop to each Button: for the back link use title={backText ||
'Back'} (or similar), for the Dashboard button use title="Dashboard", and for
the Read Docs button use title="Read Docs" to satisfy accessibility/tooltip
requirements.

)}
</div>

{!isDocs && (
<div className="mt-20 grid grid-cols-1 sm:grid-cols-2 gap-4 w-full max-w-2xl">
<div className="p-6 rounded-2xl border border-border/40 bg-muted/10 hover:bg-muted/20 transition-colors">
<h3 className="font-bold text-foreground mb-1">Looking for setup?</h3>
<p className="text-sm text-muted-foreground mb-4">Check our local development guide.</p>
<Link to="/docs/local-setup" className="text-xs font-bold text-primary hover:underline">
View Guide →
</Link>
</div>
<div className="p-6 rounded-2xl border border-border/40 bg-muted/10 hover:bg-muted/20 transition-colors">
<h3 className="font-bold text-foreground mb-1">Security questions?</h3>
<p className="text-sm text-muted-foreground mb-4">
Learn about our zero-knowledge architecture.
</p>
<Link to="/docs/security" className="text-xs font-bold text-primary hover:underline">
Explore Security →
</Link>
</div>
</div>
)}
</div>
);
}
4 changes: 2 additions & 2 deletions src/components/onboarding-tutorial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const DASHBOARD_STEPS: TutorialStep[] = [
title: "Your Projects",
description: "Projects live here. Open one to manage environments and encrypted variables.",
selector: '[data-tutorial-id="projects-section"]',
placement: "top",
placement: "bottom",
},
{
id: "new-project",
Expand Down Expand Up @@ -237,7 +237,7 @@ export function OnboardingTutorial({ enabled = true, restartSignal }: TutorialOv
if (!isActive) return;

const updateMeasurements = () => {
const target = step ? (document.querySelector(step.selector)) : null;
const target = step ? document.querySelector(step.selector) : null;
if (!target) {
const nextIndex = findNextAvailable(currentIndex + 1);
if (nextIndex === -1) {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export const SHARE_EXPIRY_OPTIONS = [
export type ShareExpiryValue = (typeof SHARE_EXPIRY_OPTIONS)[number]["value"];

export const META_DATA = {
github: "https://github.com/pantharshit007/tijori",
github_repo: "https://github.com/pantharshit007/tijori",
github: "https://github.com/pantharshit007",
twitter: "https://x.com/pantharshit007",
};

Expand Down
Loading