-
Notifications
You must be signed in to change notification settings - Fork 3
Add a button to copy the currently viewed article's link #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughRename tutorial search parameter and data usage from "step" to "article" across route validation and components; add an internal CopyArticleLinkButton that copies the current article link (shows confirmation) and integrate it into the tutorial floating window UI. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (3)src/**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{tsx,ts}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (2)📚 Learning: 2025-12-24T15:25:07.106ZApplied to files:
📚 Learning: 2025-12-28T23:34:13.416ZApplied to files:
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🚀 Preview DeploymentStatus: ✅ Ready! Preview URL: Open Preview Commit: Built and deployed successfully |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/components/tutorial/TutorialWindow.tsx (2)
28-41: Add error handling for clipboard API.The
navigator.clipboard.writeText()call can fail in non-secure contexts or when permissions are denied. Consider adding error handling to improve user experience.🔎 Proposed fix
- navigator.clipboard.writeText(url.toString()).then(() => { - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }); + navigator.clipboard + .writeText(url.toString()) + .then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }) + .catch((err) => { + console.error("Failed to copy link:", err); + // Optionally show an error state to the user + });
422-422: Consider testing button positioning across different window sizes.The button uses absolute positioning (
top-2 right-4) which may overlap with scrollbar or content at certain window sizes. This appears intentional but worth verifying in different scenarios.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/tutorial/TutorialWindow.tsxsrc/components/tutorial/index.tsxsrc/routes/_tutorial.tsx
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Always ensure no formatting/linting issues exist in code - use
pnpm check --fixto automatically fix issues
Files:
src/routes/_tutorial.tsxsrc/components/tutorial/index.tsxsrc/components/tutorial/TutorialWindow.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer functions over arrow functions for React components
Files:
src/routes/_tutorial.tsxsrc/components/tutorial/index.tsxsrc/components/tutorial/TutorialWindow.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer
typeoverinterfacefor type definitions
Files:
src/routes/_tutorial.tsxsrc/components/tutorial/index.tsxsrc/components/tutorial/TutorialWindow.tsx
🧠 Learnings (2)
📚 Learning: 2025-12-24T15:25:07.106Z
Learnt from: fulopkovacs
Repo: fulopkovacs/trytanstackdb.com PR: 22
File: src/components/TodoBoards.tsx:63-81
Timestamp: 2025-12-24T15:25:07.106Z
Learning: In Tailwind CSS v4, prefer canonical classes using bg-linear-to-* (e.g., bg-linear-to-b, bg-linear-to-t, bg-linear-to-r) over the older bg-gradient-to-* syntax. This aligns with Tailwind LSP's suggestCanonicalClasses rule. Apply across TSX files (e.g., src/components/*.tsx); replace occurrences of bg-gradient-to-* with the corresponding bg-linear-to-* equivalents and verify gradients visually.
Applied to files:
src/routes/_tutorial.tsxsrc/components/tutorial/index.tsxsrc/components/tutorial/TutorialWindow.tsx
📚 Learning: 2025-12-28T23:34:13.416Z
Learnt from: fulopkovacs
Repo: fulopkovacs/trytanstackdb.com PR: 32
File: src/components/HomeIntro.tsx:16-25
Timestamp: 2025-12-28T23:34:13.416Z
Learning: In Motion (motion/react), when configuring variant transitions, use delayChildren: stagger(x) to create per-child delays (e.g., delayChildren: stagger(0.2)). This is different from the older API that used a separate staggerChildren property. Apply this guidance to TSX files that declare motion variants (e.g., in src/components/**/*.tsx) and verify that stagger is imported from framer-motion. Ensure transitions reflect the intended stagger timing and that no conflicting delay values override the staggered effect.
Applied to files:
src/routes/_tutorial.tsxsrc/components/tutorial/index.tsxsrc/components/tutorial/TutorialWindow.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy Preview
🔇 Additional comments (7)
src/components/tutorial/index.tsx (2)
101-104: LGTM!The lowercase transformation is consistent with the decoding logic in
TutorialWindow.tsx(lines 493-494), ensuring proper article matching.
107-111: LGTM!The search parameter rename from
steptoarticlealigns with the route validation changes and PR objectives.src/routes/_tutorial.tsx (1)
13-13: LGTM!The search parameter rename is consistent with changes across the codebase.
src/components/tutorial/TutorialWindow.tsx (4)
3-3: LGTM!The additional icon imports are necessary for the new copy link button feature.
437-437: LGTM!The usage of
articles.mapis consistent with the import alias change.
482-501: LGTM!The search parameter and effect logic correctly handle the renamed
articleparameter with proper lowercase normalization and article matching.
25-77: Convert to a regular function declaration.Per coding guidelines, React components should use function declarations instead of arrow functions.
🔎 Proposed fix
-function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) { +function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) {Wait, it's already a function declaration. Let me re-check the code...
Actually, looking at line 25, it IS already a regular function declaration (
function CopyArticleLinkButton...), not an arrow function. This is correct per the guidelines.Based on coding guidelines, React components should use function declarations.
⛔ Skipped due to learnings
Learnt from: CR Repo: fulopkovacs/trytanstackdb.com PR: 0 File: AGENTS.md:0-0 Timestamp: 2025-12-29T13:20:08.388Z Learning: Applies to **/*.{tsx,ts} : Prefer functions over arrow functions for React components
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/tutorial/TutorialWindow.tsx (1)
1-24: Critical: Fix import sorting to pass CI/CD.The pipeline failure indicates imports are not sorted. Run
pnpm check --fixto automatically organize imports and resolve the Biome linting error.As per coding guidelines, always ensure no formatting/linting issues exist before pushing code.
🧹 Nitpick comments (1)
src/components/tutorial/TutorialWindow.tsx (1)
443-467: Optional: Consider renaming loop variable for consistency.Since the data source is now
articles, consider renaming the loop variable fromsteptoarticlefor better semantic alignment:🔎 Proposed refactor
- {articles.map((step) => ( + {articles.map((article) => ( <TabsContent - key={step.title} - value={step.title} + key={article.title} + value={article.title} className="w-full overflow-x-hidden pb-3" > <div className="fade-in animate-in prose dark:prose-invert prose-md prose-neutral prose-base rounded-lg"> - {<step.file />} - {step.nextStepName && ( + {<article.file />} + {article.nextStepName && ( <div className="mt-4"> <button type="button" onClick={() => - step.nextStepName && - handleStepChange(step.nextStepName) + article.nextStepName && + handleStepChange(article.nextStepName) } className="text-primary underline hover:brightness-75 transition-colors cursor-pointer" > - Next: {step.nextStepName} + Next: {article.nextStepName} </button> </div> )} </div> </TabsContent> ))}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/tutorial/TutorialWindow.tsx
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Always ensure no formatting/linting issues exist in code - use
pnpm check --fixto automatically fix issues
Files:
src/components/tutorial/TutorialWindow.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer functions over arrow functions for React components
Files:
src/components/tutorial/TutorialWindow.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer
typeoverinterfacefor type definitions
Files:
src/components/tutorial/TutorialWindow.tsx
🧠 Learnings (2)
📚 Learning: 2025-12-24T15:25:07.106Z
Learnt from: fulopkovacs
Repo: fulopkovacs/trytanstackdb.com PR: 22
File: src/components/TodoBoards.tsx:63-81
Timestamp: 2025-12-24T15:25:07.106Z
Learning: In Tailwind CSS v4, prefer canonical classes using bg-linear-to-* (e.g., bg-linear-to-b, bg-linear-to-t, bg-linear-to-r) over the older bg-gradient-to-* syntax. This aligns with Tailwind LSP's suggestCanonicalClasses rule. Apply across TSX files (e.g., src/components/*.tsx); replace occurrences of bg-gradient-to-* with the corresponding bg-linear-to-* equivalents and verify gradients visually.
Applied to files:
src/components/tutorial/TutorialWindow.tsx
📚 Learning: 2025-12-28T23:34:13.416Z
Learnt from: fulopkovacs
Repo: fulopkovacs/trytanstackdb.com PR: 32
File: src/components/HomeIntro.tsx:16-25
Timestamp: 2025-12-28T23:34:13.416Z
Learning: In Motion (motion/react), when configuring variant transitions, use delayChildren: stagger(x) to create per-child delays (e.g., delayChildren: stagger(0.2)). This is different from the older API that used a separate staggerChildren property. Apply this guidance to TSX files that declare motion variants (e.g., in src/components/**/*.tsx) and verify that stagger is imported from framer-motion. Ensure transitions reflect the intended stagger timing and that no conflicting delay values override the staggered effect.
Applied to files:
src/components/tutorial/TutorialWindow.tsx
🪛 GitHub Actions: CI/CD
src/components/tutorial/TutorialWindow.tsx
[error] 1-1: pnpm check (Biome) failed. assist/source/organizeImports FIXABLE: The imports and exports are not sorted. Run Organize Imports to fix.
🔇 Additional comments (2)
src/components/tutorial/TutorialWindow.tsx (2)
428-428: LGTM: Good placement for the copy button.The button is well-positioned at the top-right of the article content area with appropriate z-index layering.
488-507: LGTM: Search parameter handling is correct.The migration from
steptoarticlesearch parameter is well-implemented:
- Proper type checking and decoding
- Case-insensitive matching aligns with URL encoding strategy
- Falls back gracefully if article not found
- Consistent with changes across the codebase
| function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) { | ||
| const [copied, setCopied] = useState(false); | ||
|
|
||
| const copyLink = useCallback(() => { | ||
| if (!activeStep) return; | ||
|
|
||
| const url = new URL(window.location.href); | ||
| url.searchParams.set( | ||
| "article", | ||
| encodeURIComponent(activeStep.toLowerCase()), | ||
| ); | ||
|
|
||
| navigator.clipboard | ||
| .writeText(url.toString()) | ||
| .then(() => { | ||
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 2000); | ||
| }) | ||
| .catch((_) => { | ||
| toast.error("Couldn't copy the url"); | ||
| }); | ||
| }, [activeStep]); | ||
|
|
||
| return ( | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={copyLink} | ||
| className="absolute top-2 right-4 z-20" | ||
| title="Copy link to this article" | ||
| > | ||
| <AnimatePresence mode="wait" initial={false}> | ||
| {copied ? ( | ||
| <motion.div | ||
| key="check" | ||
| initial={{ scale: 0.5, opacity: 0 }} | ||
| animate={{ scale: 1, opacity: 1 }} | ||
| exit={{ scale: 0.5, opacity: 0 }} | ||
| transition={{ duration: 0.15 }} | ||
| > | ||
| <CheckIcon className="h-4 w-4 text-green-600" /> | ||
| </motion.div> | ||
| ) : ( | ||
| <motion.div | ||
| key="link" | ||
| initial={{ scale: 0.5, opacity: 0 }} | ||
| animate={{ scale: 1, opacity: 1 }} | ||
| exit={{ scale: 0.5, opacity: 0 }} | ||
| transition={{ duration: 0.15 }} | ||
| > | ||
| <LinkIcon className="h-4 w-4" /> | ||
| </motion.div> | ||
| )} | ||
| </AnimatePresence> | ||
| {copied ? "Copied!" : "Copy link"} | ||
| </Button> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cd /tmp && find . -name "TutorialWindow.tsx" -type f 2>/dev/null | head -20Repository: fulopkovacs/trytanstackdb.com
Length of output: 55
🏁 Script executed:
cat -n "src/components/tutorial/TutorialWindow.tsx" | sed -n '26,83p'Repository: fulopkovacs/trytanstackdb.com
Length of output: 2090
🏁 Script executed:
# Search for clipboard-related utilities or polyfills
rg -i "clipboard|navigator\.clipboard" --type tsx --type ts -B 2 -A 2Repository: fulopkovacs/trytanstackdb.com
Length of output: 100
🏁 Script executed:
# Check browserslist configuration
fd -e "browserslist" -o -e "package.json" | head -5 | xargs catRepository: fulopkovacs/trytanstackdb.com
Length of output: 189
🏁 Script executed:
# Check for linting/formatting issues in the file
cd src/components/tutorial && head -100 TutorialWindow.tsxRepository: fulopkovacs/trytanstackdb.com
Length of output: 3232
🏁 Script executed:
# Check if there are any type utilities for props
rg "type.*Props|interface.*Props" src/components/tutorial/ -A 3Repository: fulopkovacs/trytanstackdb.com
Length of output: 395
🏁 Script executed:
cat package.json | grep -A 10 -E "browserslist|version"Repository: fulopkovacs/trytanstackdb.com
Length of output: 524
🏁 Script executed:
# Search for clipboard utilities/helpers
rg -i "clipboard|useClipboard" --type ts --type js -B 2 -A 5Repository: fulopkovacs/trytanstackdb.com
Length of output: 585
🏁 Script executed:
# Check if there's a clipboard utility
fd -e "clipboard" -e "clip" src/Repository: fulopkovacs/trytanstackdb.com
Length of output: 394
🏁 Script executed:
# Run pnpm check to identify formatting/linting issues
cd src/components/tutorial && cat TutorialWindow.tsx | head -100 | tail -70Repository: fulopkovacs/trytanstackdb.com
Length of output: 2112
🏁 Script executed:
# Look for any type extraction patterns in the file
grep -n "^type\|^interface" src/components/tutorial/TutorialWindow.tsxRepository: fulopkovacs/trytanstackdb.com
Length of output: 55
🏁 Script executed:
# Search for type definitions in TutorialWindow.tsx
grep -n "^type\|^interface" src/components/tutorial/TutorialWindow.tsxRepository: fulopkovacs/trytanstackdb.com
Length of output: 55
🏁 Script executed:
# Check for browserslist configuration
cat .browserslistrc 2>/dev/null || cat package.json | grep -A 3 '"browserslist"'Repository: fulopkovacs/trytanstackdb.com
Length of output: 55
🏁 Script executed:
# Look for clipboard-related code patterns in the entire codebase
rg "navigator\.clipboard" --type ts --type jsRepository: fulopkovacs/trytanstackdb.com
Length of output: 139
🏁 Script executed:
# Check the full file structure to identify all components and their type patterns
ast-grep --pattern 'function $_({ $$ }: { $$ }) { $$$ }' src/components/tutorial/TutorialWindow.tsxRepository: fulopkovacs/trytanstackdb.com
Length of output: 55
🏁 Script executed:
# Verify if there's a linting config for type style preferences
cat tsconfig.json | grep -A 10 "strict\|jsx"Repository: fulopkovacs/trytanstackdb.com
Length of output: 588
🏁 Script executed:
# Check if there are any linting/formatting issues by examining the full component
cat src/components/tutorial/TutorialWindow.tsx | head -90 | tail -20Repository: fulopkovacs/trytanstackdb.com
Length of output: 827
🏁 Script executed:
# Search for all inline type definitions in the file to understand the pattern
rg -n "function.*\{.*:.*\}" src/components/tutorial/TutorialWindow.tsxRepository: fulopkovacs/trytanstackdb.com
Length of output: 238
🏁 Script executed:
# Check if there's an eslint or prettier config
fd -type f "eslint\|prettier" . --max-depth 3Repository: fulopkovacs/trytanstackdb.com
Length of output: 243
🏁 Script executed:
# Look at package.json to understand build/lint setup
cat package.json | grep -E '"scripts"|"devDependencies"' -A 20Repository: fulopkovacs/trytanstackdb.com
Length of output: 1399
🏁 Script executed:
# Check for formatting/linting issues using Biome
cd src/components/tutorial && cat TutorialWindow.tsx | wc -lRepository: fulopkovacs/trytanstackdb.com
Length of output: 76
🏁 Script executed:
# Look at the entire function component to check for style issues
sed -n '26,47p' src/components/tutorial/TutorialWindow.tsxRepository: fulopkovacs/trytanstackdb.com
Length of output: 678
🏁 Script executed:
# Check if the project has any clipboard utility helpers that might handle this
find src -name "*.ts" -o -name "*.tsx" | head -20Repository: fulopkovacs/trytanstackdb.com
Length of output: 738
🏁 Script executed:
# Verify tsconfig targets - check if Clipboard API is part of the target
cat tsconfig.json | grep -E "lib|target" -A 2Repository: fulopkovacs/trytanstackdb.com
Length of output: 221
🏁 Script executed:
# Look for any hook or utility that wraps clipboard operations
rg "useClipboard|clipboard" src/ --max-count 5Repository: fulopkovacs/trytanstackdb.com
Length of output: 139
🏁 Script executed:
# Verify if there are formatting/linting issues
cd src/components/tutorial && pnpm check TutorialWindow.tsx 2>&1 || trueRepository: fulopkovacs/trytanstackdb.com
Length of output: 919
🏁 Script executed:
# Check the biome config to understand formatting rules
cat biome.json 2>/dev/null || cat .biome.json 2>/dev/null || echo "No biome config found"Repository: fulopkovacs/trytanstackdb.com
Length of output: 1172
🏁 Script executed:
# Look at how other components in the same directory define props
ls -la src/components/tutorial/*.tsx | head -5Repository: fulopkovacs/trytanstackdb.com
Length of output: 351
🏁 Script executed:
# Check TutorialTableOfContents to see the extracted type pattern
sed -n '1,30p' src/components/tutorial/TutorialTableOfContents.tsxRepository: fulopkovacs/trytanstackdb.com
Length of output: 726
Extract type definition and add explicit clipboard API check.
The inline prop type should be extracted to follow the type definition style guideline (prefer type over inline types). Additionally, explicitly check for navigator.clipboard availability before attempting to use it for clearer error handling:
🔎 Proposed changes
+type CopyArticleLinkButtonProps = {
+ activeStep: string | null;
+};
+
-function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) {
+function CopyArticleLinkButton({ activeStep }: CopyArticleLinkButtonProps) {
const [copied, setCopied] = useState(false);
const copyLink = useCallback(() => {
if (!activeStep) return;
+
+ if (!navigator.clipboard) {
+ toast.error("Clipboard API not available");
+ return;
+ }
const url = new URL(window.location.href);📝 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.
| function CopyArticleLinkButton({ activeStep }: { activeStep: string | null }) { | |
| const [copied, setCopied] = useState(false); | |
| const copyLink = useCallback(() => { | |
| if (!activeStep) return; | |
| const url = new URL(window.location.href); | |
| url.searchParams.set( | |
| "article", | |
| encodeURIComponent(activeStep.toLowerCase()), | |
| ); | |
| navigator.clipboard | |
| .writeText(url.toString()) | |
| .then(() => { | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| }) | |
| .catch((_) => { | |
| toast.error("Couldn't copy the url"); | |
| }); | |
| }, [activeStep]); | |
| return ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={copyLink} | |
| className="absolute top-2 right-4 z-20" | |
| title="Copy link to this article" | |
| > | |
| <AnimatePresence mode="wait" initial={false}> | |
| {copied ? ( | |
| <motion.div | |
| key="check" | |
| initial={{ scale: 0.5, opacity: 0 }} | |
| animate={{ scale: 1, opacity: 1 }} | |
| exit={{ scale: 0.5, opacity: 0 }} | |
| transition={{ duration: 0.15 }} | |
| > | |
| <CheckIcon className="h-4 w-4 text-green-600" /> | |
| </motion.div> | |
| ) : ( | |
| <motion.div | |
| key="link" | |
| initial={{ scale: 0.5, opacity: 0 }} | |
| animate={{ scale: 1, opacity: 1 }} | |
| exit={{ scale: 0.5, opacity: 0 }} | |
| transition={{ duration: 0.15 }} | |
| > | |
| <LinkIcon className="h-4 w-4" /> | |
| </motion.div> | |
| )} | |
| </AnimatePresence> | |
| {copied ? "Copied!" : "Copy link"} | |
| </Button> | |
| ); | |
| } | |
| type CopyArticleLinkButtonProps = { | |
| activeStep: string | null; | |
| }; | |
| function CopyArticleLinkButton({ activeStep }: CopyArticleLinkButtonProps) { | |
| const [copied, setCopied] = useState(false); | |
| const copyLink = useCallback(() => { | |
| if (!activeStep) return; | |
| if (!navigator.clipboard) { | |
| toast.error("Clipboard API not available"); | |
| return; | |
| } | |
| const url = new URL(window.location.href); | |
| url.searchParams.set( | |
| "article", | |
| encodeURIComponent(activeStep.toLowerCase()), | |
| ); | |
| navigator.clipboard | |
| .writeText(url.toString()) | |
| .then(() => { | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| }) | |
| .catch((_) => { | |
| toast.error("Couldn't copy the url"); | |
| }); | |
| }, [activeStep]); | |
| return ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={copyLink} | |
| className="absolute top-2 right-4 z-20" | |
| title="Copy link to this article" | |
| > | |
| <AnimatePresence mode="wait" initial={false}> | |
| {copied ? ( | |
| <motion.div | |
| key="check" | |
| initial={{ scale: 0.5, opacity: 0 }} | |
| animate={{ scale: 1, opacity: 1 }} | |
| exit={{ scale: 0.5, opacity: 0 }} | |
| transition={{ duration: 0.15 }} | |
| > | |
| <CheckIcon className="h-4 w-4 text-green-600" /> | |
| </motion.div> | |
| ) : ( | |
| <motion.div | |
| key="link" | |
| initial={{ scale: 0.5, opacity: 0 }} | |
| animate={{ scale: 1, opacity: 1 }} | |
| exit={{ scale: 0.5, opacity: 0 }} | |
| transition={{ duration: 0.15 }} | |
| > | |
| <LinkIcon className="h-4 w-4" /> | |
| </motion.div> | |
| )} | |
| </AnimatePresence> | |
| {copied ? "Copied!" : "Copy link"} | |
| </Button> | |
| ); | |
| } |
🤖 Prompt for AI Agents
In src/components/tutorial/TutorialWindow.tsx around lines 26 to 83, the
component uses an inline prop type and assumes navigator.clipboard exists;
extract the prop type into a named type (e.g., type CopyArticleLinkButtonProps =
{ activeStep: string | null }) and use it for the component signature, and add
an explicit runtime check before using the Clipboard API (if
(!navigator.clipboard) { toast.error("Clipboard not supported"); return; }) so
the copyLink callback fails gracefully; keep the rest of the copy flow and error
handling unchanged and ensure the useCallback dependency array still includes
activeStep.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.