-
Notifications
You must be signed in to change notification settings - Fork 1
Landing page #4
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
Landing page #4
Conversation
WalkthroughAdds a full Nuxt 4 landing-site scaffold under Changes
Sequence Diagram(s)sequenceDiagram
participant Browser
participant NuxtServer as "Nuxt Server (app.vue)"
participant Content as "Nuxt Content"
participant ClientSearch as "Client Search (lazy)"
Browser->>NuxtServer: GET /
NuxtServer->>Content: useAsyncData(fetch navigation) [server]
Content-->>NuxtServer: navigation data
NuxtServer->>Browser: render HTML (nav + initial content)
Browser->>NuxtServer: hydrate/mount
Browser->>ClientSearch: trigger lazy fetch (useLazyAsyncData server:false)
ClientSearch->>Content: fetch searchable files (client)
Content-->>ClientSearch: files
ClientSearch->>Browser: enable client-only search UI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
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: 16
🧹 Nitpick comments (18)
landing/content/4.changelog/6.performance.md (1)
21-21: Consider minor tone refinement for consistency.The closing sentence could be slightly more inviting by adding "please": "Please let us know if you notice the difference...". This aligns with friendly, approachable SaaS communication conventions and slightly softens the ask.
landing/.env.example (1)
2-2: Add an example value to clarify expected format.Developers would benefit from seeing a sample URL format (e.g.,
https://example.com) to understand what value should be provided in their.env.localfile.# Public URL, used for OG Image when running nuxt generate - NUXT_PUBLIC_SITE_URL= + NUXT_PUBLIC_SITE_URL=https://example.comlanding/.github/workflows/ci.yml (1)
30-34: Consider adding a build step to verify production readiness.The workflow performs linting and type checking but skips the build step. Adding
pnpm run build(orpnpm run generatefor static export) would catch runtime issues and ensure the landing page builds successfully in the CI environment.- name: Typecheck run: pnpm run typecheck + + - name: Build + run: pnpm run buildlanding/app/components/OgImage/OgImageSaas.vue (1)
6-15: Consider using TypeScript interface with defineProps for better type safety.The current object-based prop definition works but Vue 3 with TypeScript recommends the more type-safe interface syntax.
Apply this diff to modernize the prop definitions:
<script setup lang="ts"> defineOptions({ inheritAttrs: false }) -defineProps({ - title: { - type: String, - required: true - }, - description: { - type: String, - required: true - } -}) +interface Props { + title: string + description: string +} + +defineProps<Props>() </script>landing/content/1.docs/2.essentials/4.images-embeds.md (1)
23-25: Document the @nuxt/image installation requirement more clearly.The note mentions conditional behavior when
@nuxt/imageis installed, but users may not realize this is an optional enhancement rather than a requirement.Consider clarifying whether
@nuxt/imageis required for this template or optional:::note -If [`@nuxt/image`](https://image.nuxt.com/get-started/installation) is installed, the `<NuxtImg>` component will be used instead of the native `img` tag. +The template optionally supports [`@nuxt/image`](https://image.nuxt.com/get-started/installation). When installed, the `<NuxtImg>` component will be used instead of the native `img` tag for automatic optimization. ::landing/app/components/HeroBackground.vue (2)
7-14: ReplacesetTimeout(..., 0)withnextTick()for cleaner defer logic.The
setTimeoutwith 0ms delay is used to defer execution, but Vue'snextTick()is the idiomatic way to achieve this. The nestedsetTimeoutpattern for sequenced animations could also be simplified.Apply this diff to use
nextTick():onMounted(() => { - setTimeout(() => { + nextTick(() => { appear.value = true setTimeout(() => { appeared.value = true }, 1000) - }, 0) + }) })Alternatively, consider using CSS animations or transitions for more declarative timing control.
31-85: Hardcoded SVG gradient IDs may cause conflicts if component is reused.The gradient IDs (
paint0_linear_414_5526,paint1_linear_414_5526,path-1-inside-1_414_5526) are hardcoded. While this component is likely used only once per page as a hero background, future reuse could cause ID conflicts.If this component might be reused, consider generating unique IDs similar to the suggestion for
ImagePlaceholder.vue:<script setup lang="ts"> +const maskId = useId() +const gradient0Id = useId() +const gradient1Id = useId() + const { isLoading } = useLoadingIndicator() // ... rest of script </script> <template> <div ...> <svg ...> <mask - id="path-1-inside-1_414_5526" + :id="maskId" fill="white" > <path d="M0 0H1440V181H0V0Z" /> </mask> <path d="M0 0H1440V181H0V0Z" - fill="url(#paint0_linear_414_5526)" + :fill="`url(#${gradient0Id})`" fill-opacity="0.22" /> <path d="M0 2H1440V-2H0V2Z" - fill="url(#paint1_linear_414_5526)" - mask="url(#path-1-inside-1_414_5526)" + :fill="`url(#${gradient1Id})`" + :mask="`url(#${maskId})`" /> <defs> <linearGradient - id="paint0_linear_414_5526" + :id="gradient0Id" ... > <!-- ... --> </linearGradient> <linearGradient - id="paint1_linear_414_5526" + :id="gradient1Id" ... > <!-- ... --> </linearGradient> </defs> </svg> </div> </template>landing/app/pages/signup.vue (1)
47-51: Consider adopting Zod 4's new standalone string schemas.The current schema uses the legacy Zod 3 API (
z.string().email()). Zod 4 introduces standalone string format schemas and a unified error parameter approach for better consistency.Based on library documentation
Apply this diff to adopt the new Zod 4 patterns:
const schema = z.object({ - name: z.string().min(1, 'Name is required'), - email: z.string().email('Invalid email'), - password: z.string().min(8, 'Must be at least 8 characters') + name: z.string().min(1, { error: () => 'Name is required' }), + email: z.email({ error: () => 'Invalid email' }), + password: z.string().min(8, { error: () => 'Must be at least 8 characters' }) })landing/app/components/PromotionalVideo.vue (1)
1-29: Consider making video sources configurable.The video URLs are currently hardcoded. Consider accepting them as props or defining them in app config to make the component more reusable and easier to update.
Example refactor:
<script setup lang="ts"> interface Props { poster?: string sources?: Array<{ src: string; type: string }> } const props = withDefaults(defineProps<Props>(), { poster: '/default-poster.jpg', sources: () => [ { src: '/videos/promo.webm', type: 'video/webm' }, { src: '/videos/promo.mp4', type: 'video/mp4' }, ], }) </script> <template> <div class="relative"> <UPageCard variant="subtle" class="rounded-2xl"> <video class="rounded-xl" preload="none" :poster="poster" :controls="true" > <source v-for="source in sources" :key="source.src" :src="source.src" :type="source.type" > <track kind="captions" src="/captions/promotional-video.vtt" srclang="en" label="English" > </video> </UPageCard> </div> </template>landing/app/components/content/Pictures.vue (1)
10-10: Fix extra spaces in class string.There are extra spaces between "flex-row" and "space-x-4" in the conditional class binding.
Apply this diff:
- :class="orientation === 'vertical' ? 'flex-col space-y-4' : 'flex-row space-x-4'" + :class="orientation === 'vertical' ? 'flex-col space-y-4' : 'flex-row space-x-4'"landing/app/components/content/PictureAndText.vue (1)
12-19: Consider adding responsive grid classes for mobile.The grid uses
grid-cols-3without responsive breakpoints, which may result in cramped layout on mobile devices. Consider using responsive utilities to stack the layout on smaller screens.Apply this diff:
- <div class="grid grid-cols-3 items-center w-full gap-x-8"> + <div class="grid grid-cols-1 md:grid-cols-3 items-center w-full gap-8 md:gap-x-8"> <div :class="{ 'order-2': reverse }"> <slot name="image" /> </div> - <div class="col-span-2"> + <div class="md:col-span-2"> <slot /> </div> </div>landing/app/pages/pricing.vue (1)
16-27: Consider using more semantic values for the billing toggle.The
isYearlytoggle uses numeric string values ('0' and '1'), which reduces readability. Consider using semantic string values like 'monthly' and 'yearly' for better code clarity.Apply this diff:
-const isYearly = ref('0') +const isYearly = ref('monthly') const items = ref([ { label: 'Monthly', - value: '0' + value: 'monthly' }, { label: 'Yearly', - value: '1' + value: 'yearly' } ])And update the comparisons:
- :price="isYearly === '1' ? plan.price.year : plan.price.month" - :billing-cycle="isYearly === '1' ? '/year' : '/month'" + :price="isYearly === 'yearly' ? plan.price.year : plan.price.month" + :billing-cycle="isYearly === 'yearly' ? '/year' : '/month'"landing/app/components/TemplateMenu.vue (1)
44-46: Consider simplifying the dynamic class binding.The inline array filtering and joining for the
trailingIconclasses works but could be more readable using Vue's class binding syntax.Apply this diff for a cleaner approach:
:ui="{ - trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' ') + trailingIcon: { + 'transition-transform duration-200': true, + 'rotate-180': open + } }"Note: Check if the
:uiprop accepts object class bindings. If it requires a string, the current approach is fine.landing/app/pages/changelog/index.vue (1)
29-32: Consider using a stable identifier as the key.Using
indexas the key works but isn't ideal if the versions list could be reordered or filtered. If each version has a unique identifier (likeversion._idorversion.date), use that instead.Example:
<UChangelogVersion v-for="(version, index) in versions" - :key="index" + :key="version._id || version.date" v-bind="version" >landing/app/pages/blog/index.vue (1)
4-5: Consider adding error handling for async data fetches.If
queryCollectionfails or returns null, the page may render incorrectly or throw. Consider adding error boundaries or null checks.landing/content/0.index.yml (1)
83-137: Consider hosting avatar images locally or on a reliable CDN.The testimonials section uses pravatar.cc (a third-party placeholder service) for all avatar images. While fine for development, this introduces a reliability dependency for production. If pravatar.cc experiences downtime, all testimonial avatars will fail to load.
Consider either:
- Hosting actual user avatars on your own infrastructure or CDN
- Using placeholder avatars from your static assets directory
- Implementing graceful fallbacks when images fail to load
landing/app/pages/index.vue (1)
39-43: Remove or gate debug UI for production.The debug warning UI should either be removed or placed behind a development-only check to avoid exposing internal state in production.
Apply this diff to remove the debug UI:
<template> <div> - <div v-if="!page" class="p-8"> - <h1 class="text-2xl font-bold text-red-500">⚠️ Page data not loaded</h1> - <p class="mt-4">Check the browser console for error messages.</p> - <p class="mt-2 text-sm text-gray-600">page value: {{ page }}</p> - </div> - <div v-if="page">Or gate it behind a dev check:
- <div v-if="!page" class="p-8"> + <div v-if="!page && import.meta.dev" class="p-8">landing/content.config.ts (1)
9-10: Consider using.min(1)instead of.nonempty()for Zod 4.While
.nonempty()still works in Zod 4, the recommended approach for non-empty string validation is now.min(1). This applies to multiple locations throughout the file where string validation requires non-empty values.Example refactor:
const createBaseSchema = () => z.object({ - title: z.string().nonempty(), - description: z.string().nonempty() + title: z.string().min(1), + description: z.string().min(1) })This pattern should be applied consistently throughout lines 9, 10, 14, 18, 19, 29, 45, 58, 60-62, 84-85, 88-89, 98, 104-105, 119, 122, 124, 128, and 139 for consistency with Zod 4 best practices.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
landing/bun.lockbis excluded by!**/bun.lockblanding/public/favicon.icois excluded by!**/*.icolanding/public/sendook-logo.svgis excluded by!**/*.svglanding/public/sendook-logomark.svgis excluded by!**/*.svg
📒 Files selected for processing (69)
landing/.editorconfig(1 hunks)landing/.env.example(1 hunks)landing/.github/workflows/ci.yml(1 hunks)landing/.gitignore(1 hunks)landing/.npmrc(1 hunks)landing/README.md(1 hunks)landing/app/app.config.ts(1 hunks)landing/app/app.vue(1 hunks)landing/app/assets/css/main.css(1 hunks)landing/app/components/AppFooter.vue(1 hunks)landing/app/components/AppHeader.vue(1 hunks)landing/app/components/AppLogo.vue(1 hunks)landing/app/components/HeroBackground.vue(1 hunks)landing/app/components/ImagePlaceholder.vue(1 hunks)landing/app/components/OgImage/OgImageSaas.vue(1 hunks)landing/app/components/PromotionalVideo.vue(1 hunks)landing/app/components/StarsBg.vue(1 hunks)landing/app/components/TemplateMenu.vue(1 hunks)landing/app/components/content/PictureAndText.vue(1 hunks)landing/app/components/content/Pictures.vue(1 hunks)landing/app/error.vue(1 hunks)landing/app/layouts/auth.vue(1 hunks)landing/app/layouts/default.vue(1 hunks)landing/app/layouts/docs.vue(1 hunks)landing/app/pages/blog.vue(1 hunks)landing/app/pages/blog/[slug].vue(1 hunks)landing/app/pages/blog/index.vue(1 hunks)landing/app/pages/changelog/index.vue(1 hunks)landing/app/pages/docs/[...slug].vue(1 hunks)landing/app/pages/index.vue(1 hunks)landing/app/pages/login.vue(1 hunks)landing/app/pages/pricing.vue(1 hunks)landing/app/pages/signup.vue(1 hunks)landing/app/types/index.d.ts(1 hunks)landing/content.config.ts(1 hunks)landing/content/0.index.yml(1 hunks)landing/content/1.docs/1.getting-started/.navigation.yml(1 hunks)landing/content/1.docs/1.getting-started/1.index.md(1 hunks)landing/content/1.docs/1.getting-started/2.installation.md(1 hunks)landing/content/1.docs/1.getting-started/3.usage.md(1 hunks)landing/content/1.docs/2.essentials/.navigation.yml(1 hunks)landing/content/1.docs/2.essentials/1.markdown-syntax.md(1 hunks)landing/content/1.docs/2.essentials/2.code-blocks.md(1 hunks)landing/content/1.docs/2.essentials/3.prose-components.md(1 hunks)landing/content/1.docs/2.essentials/4.images-embeds.md(1 hunks)landing/content/2.pricing.yml(1 hunks)landing/content/3.blog.yml(1 hunks)landing/content/3.blog/1.asian-cuisine.md(1 hunks)landing/content/3.blog/2.pyrenees.md(1 hunks)landing/content/3.blog/3.james-webb.md(1 hunks)landing/content/3.blog/4.meditation.md(1 hunks)landing/content/3.blog/5.animals.md(1 hunks)landing/content/3.blog/6.cryptocurrencies.md(1 hunks)landing/content/4.changelog.yml(1 hunks)landing/content/4.changelog/1.launch.md(1 hunks)landing/content/4.changelog/10.fun.md(1 hunks)landing/content/4.changelog/2.teams.md(1 hunks)landing/content/4.changelog/3.dark-mode.md(1 hunks)landing/content/4.changelog/4.integrations.md(1 hunks)landing/content/4.changelog/5.mobile.md(1 hunks)landing/content/4.changelog/6.performance.md(1 hunks)landing/content/4.changelog/7.analytics.md(1 hunks)landing/content/4.changelog/8.api.md(1 hunks)landing/content/4.changelog/9.security.md(1 hunks)landing/eslint.config.mjs(1 hunks)landing/nuxt.config.ts(1 hunks)landing/package.json(1 hunks)landing/renovate.json(1 hunks)landing/tsconfig.json(1 hunks)
🧰 Additional context used
🪛 LanguageTool
landing/content/4.changelog/8.api.md
[style] ~23-~23: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 940 characters long)
Context: ...d help shape the next version of our API! 🚀
(EN_EXCESSIVE_EXCLAMATION)
landing/content/1.docs/2.essentials/4.images-embeds.md
[uncategorized] ~13-~13: Loose punctuation mark.
Context: ... to implement for basic image display. ::code-preview 
[uncategorized] ~20-~20: Loose punctuation mark.
Context: ...e](https://nuxt.com/new-social.jpg) ``` :: ::note If [@nuxt/image](https://ima...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~22-~22: Loose punctuation mark.
Context: ...ttps://nuxt.com/new-social.jpg) ``` :: ::note If [@nuxt/image](https://image.n...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~24-~24: Loose punctuation mark.
Context: ...e used instead of the native img tag. :: ### Using Embeds Use embeds for more...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~30-~30: Loose punctuation mark.
Context: ...mage attributes like size and styling. ::code-preview 
[uncategorized] ~39-~39: Loose punctuation mark.
Context: ...t="Nuxt Social Image" height="150"} ``` :: ## Embeds and HTML elements Embeds a...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...de interactive and multimedia content. ::code-preview --- class: "[&>div]:*:w-fu...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~49-~49: Loose punctuation mark.
Context: ...eview --- class: "[&>div]:*:w-full" --- :iframe{src="https://www.youtube-nocookie...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~56-~56: Loose punctuation mark.
Context: ...screen style="aspect-ratio: 16/9;"} ``` ::
(UNLIKELY_OPENING_PUNCTUATION)
landing/README.md
[uncategorized] ~62-~62: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ations/select_target) on your repository and you are good to go.
(COMMA_COMPOUND_SENTENCE)
landing/content/3.blog/4.meditation.md
[misspelling] ~24-~24: Did you mean “at the moment” (=currently)?
Context: ...ther hand, is about being fully present in the moment, acknowledging and accepting one's thou...
(IN_THE_MOMENT)
[uncategorized] ~27-~27: Loose punctuation mark.
Context: ...greater sense of calm and tranquility. ::pictures :::div 
landing/content/1.docs/1.getting-started/3.usage.md
[uncategorized] ~9-~9: Loose punctuation mark.
Context: ...ted/installation) for social previews. ::tip --- target: _blank to: https://ui.n...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~15-~15: Loose punctuation mark.
Context: ...on how to take the most out of Nuxt UI! :: ## Writing content You can just star...
(UNLIKELY_OPENING_PUNCTUATION)
landing/content/1.docs/2.essentials/2.code-blocks.md
[uncategorized] ~13-~13: Loose punctuation mark.
Context: ...g code elements directly in sentences. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~23-~23: Loose punctuation mark.
Context: ...e code #code ```mdcinline code` ``` :: ### Code Blocks Use code blocks to d...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~29-~29: Loose punctuation mark.
Context: ... for presenting code examples clearly. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...g({ modules: ['@nuxt/ui'] }) ``` ```` :: When writing a code-block, you can sp...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~52-~52: Loose punctuation mark.
Context: ...location and purpose within a project. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~70-~70: Loose punctuation mark.
Context: ...g({ modules: ['@nuxt/ui'] }) ``` ```` :: ::tip Some icons are already defined ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~72-~72: Loose punctuation mark.
Context: ... modules: ['@nuxt/ui'] }) ``` ```` :: ::tip Some icons are already defined by d...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~86-~86: Loose punctuation mark.
Context: ...indow-duotone' } } } }) ``` :: Every code-block has a built-in copy ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~90-~90: Loose punctuation mark.
Context: ... will copy the code to your clipboard. ::tip You can change the icon in your `ap...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~103-~103: Loose punctuation mark.
Context: ... 'i-lucide-copy-check' } } }) ``` :: #### Highlight Line To highlight lin...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~110-~110: Loose punctuation mark.
Context: ...s on important parts of code examples. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~138-~138: Loose punctuation mark.
Context: ...ucide-copy-check' } } }) ``` ```` :: ## Advanced ### CodeGroup Group cod...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~146-~146: Loose punctuation mark.
Context: ...ultiple languages or package managers. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~190-~190: Loose punctuation mark.
Context: ...ash [bun] bun add @nuxt/ui ``` :: ```` :: ::note{to="#pre"} Like the ProsePre...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~192-~192: Loose punctuation mark.
Context: ...[bun] bun add @nuxt/ui ``` :: ```` :: ::note{to="#pre"} Like the ProsePre com...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~194-~194: Loose punctuation mark.
Context: ...ndles filenames, icons and copy button. :: ### CodeTree Display code blocks in ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~200-~200: Loose punctuation mark.
Context: ...ect structures and file relationships. ::code-preview{class="[&>div]:*:my-0 [&>d...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~350-~350: Loose punctuation mark.
Context: ... for more information. ```` ::: :: ::note --- target: _blank to: https://ui....
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~356-~356: Loose punctuation mark.
Context: ...n more about the code-tree component. :: ### CodePreview Use code-preview...
(UNLIKELY_OPENING_PUNCTUATION)
[grammar] ~362-~362: Two determiners in a row. Choose either “a” or “the”.
Context: ...ults. Write the code to be previewed in a the default slot and the actual code in t...
(DT_DT)
[uncategorized] ~363-~363: Loose punctuation mark.
Context: ...nd the actual code in the code slot. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~391-~391: Loose punctuation mark.
Context: ... #code mdc `inline code` :: ```` :: ### CodeCollapse Use `code-collaps...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~397-~397: Loose punctuation mark.
Context: ...ly when needed, improving readability. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~455-~455: Loose punctuation mark.
Context: ...olor-green-950: #052E16; } ``` :: ```` ::
(UNLIKELY_OPENING_PUNCTUATION)
landing/content/4.changelog/1.launch.md
[style] ~23-~23: Consider using polite language here.
Context: ... help shape the future of our platform. Let us know what you think and what you'd like to s...
(INSERT_PLEASE)
landing/content/3.blog/2.pyrenees.md
[uncategorized] ~31-~31: Loose punctuation mark.
Context: ...nd refuge in the untouched wilderness. ::pictures :::div 
[uncategorized] ~51-~51: Loose punctuation mark.
Context: ...ds depth to the mountainous landscape. ::pictures{orientation="vertical"} :::d...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~76-~76: Loose punctuation mark.
Context: ...tunning backdrop of nature's grandeur. ::pictures :::div 
[uncategorized] ~94-~94: Loose punctuation mark.
Context: ...-lg height="200" width="200"} ::: :: ::pictures :::div 
[style] ~100-~100: Using many exclamation marks might seem excessive (in this case: 11 exclamation marks for a text that’s 4533 characters long)
Context: ...ight="300" width="600"} ::: :::div 
landing/content/4.changelog/7.analytics.md
[style] ~8-~8: Consider a different adjective to strengthen your wording.
Context: ...format&fit=crop&w=800&q=80 --- 📊 Gain deeper insights into your business with our ne...
(DEEP_PROFOUND)
[style] ~23-~23: Consider using polite language here.
Context: ...cited to see what insights you discover—let us know what you build with it! 🚀
(INSERT_PLEASE)
[style] ~23-~23: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 978 characters long)
Context: ...cover—let us know what you build with it! 🚀
(EN_EXCESSIVE_EXCLAMATION)
landing/content/3.blog/6.cryptocurrencies.md
[style] ~15-~15: Consider using a synonym to be more concise.
Context: ...l: Economy, Information Technology --- In recent years, cryptocurrencies have emerged as a dis...
(IN_RECENT_STYLE)
[uncategorized] ~32-~32: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ... exposure to a nascent asset class with high growth potential. - **Technological Innovation...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
[grammar] ~41-~41: The word “cyberattacks” is spelled as one.
Context: ...exchanges and wallets are vulnerable to cyber attacks, theft, and fraud, necessitating robust...
(CYBER_COMPOUNDS)
[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...ith its unique features and use cases. ::card-group :::card --- icon: i-si...
(UNLIKELY_OPENING_PUNCTUATION)
landing/content/3.blog/3.james-webb.md
[uncategorized] ~17-~17: Loose punctuation mark.
Context: ...e, History --- ## Building the Vision ::picture-and-text ### Designing the Futu...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~26-~26: Loose punctuation mark.
Context: ...ounded-lg height="400" width="400"} :: ::picture-and-text --- reverse: true --- ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~40-~40: Loose punctuation mark.
Context: ...00"} :: ## Embarking into the Unknown ::picture-and-text ### Launching into Spa...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~44-~44: Possible missing article found.
Context: ...s around the world held their breath as countdown reached its final moments. Then, with a...
(AI_HYDRA_LEO_MISSING_THE)
[uncategorized] ~49-~49: Loose punctuation mark.
Context: ...ounded-lg height="400" width="400"} :: ::picture-and-text --- reverse: true --- ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~63-~63: Loose punctuation mark.
Context: ...idth="400"} :: ## Legacy of Discovery ::picture-and-text ### Inspiring Future G...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...ounded-lg height="400" width="400"} :: ::picture-and-text --- reverse: true --- ...
(UNLIKELY_OPENING_PUNCTUATION)
[style] ~81-~81: Using many exclamation marks might seem excessive (in this case: 6 exclamation marks for a text that’s 3935 characters long)
Context: ...of discovery and understanding. #image 
landing/content/3.blog/1.asian-cuisine.md
[uncategorized] ~22-~22: Loose punctuation mark.
Context: ...eads that bind these diverse cuisines. ::pictures :::div 
[uncategorized] ~42-~42: Loose punctuation mark.
Context: ...ving a lingering and savory sensation. ::pictures :::div 
[uncategorized] ~74-~74: Loose punctuation mark.
Context: ....rounded-lg height="400" width="1200"} ::tabs :::div{icon="i-lucide-flame" lab...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~111-~111: Possible missing comma found.
Context: ...y cucumber. ::: :: ### Nems/Cha Gio (Vietnam 🇻🇳) 
[uncategorized] ~114-~114: Loose punctuation mark.
Context: ....rounded-lg height="400" width="1200"} ::tabs :::div --- class: flex space...
(UNLIKELY_OPENING_PUNCTUATION)
[style] ~138-~138: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...Add ground pork and cook until browned. Add fish sauce, sugar, and black pepper. ...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~139-~139: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ish sauce, sugar, and black pepper. Add shredded carrots, bean sprouts, wood ea...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[uncategorized] ~162-~162: Loose punctuation mark.
Context: ....rounded-lg height="400" width="1200"} ::tabs :::div --- class: flex space...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~215-~215: Loose punctuation mark.
Context: ....rounded-lg height="400" width="1200"} ::tabs :::div{icon="i-lucide-flame" lab...
(UNLIKELY_OPENING_PUNCTUATION)
[typographical] ~230-~230: If specifying a range, consider using an en dash instead of a hyphen.
Context: ...r, and warm water. Let it sit for about 5-10 minutes until it becomes frothy. - **...
(HYPHEN_TO_EN)
[typographical] ~236-~236: If specifying a range, consider using an en dash instead of a hyphen.
Context: ...o a floured surface and knead for about 5-7 minutes until it becomes smooth and ela...
(HYPHEN_TO_EN)
[typographical] ~238-~238: If specifying a range, consider using an en dash instead of a hyphen.
Context: ...th, and let it rise in a warm place for 1-2 hours or until it has doubled in size. ...
(HYPHEN_TO_EN)
[typographical] ~246-~246: If specifying a range, consider using an en dash instead of a hyphen.
Context: ...ut naan on a baking sheet. Bake for 5-7 minutes or until the naan puffs up and ...
(HYPHEN_TO_EN)
[uncategorized] ~246-~246: Possible missing comma found.
Context: ...aan on a baking sheet. Bake for 5-7 minutes or until the naan puffs up and the edge...
(AI_HYDRA_LEO_MISSING_COMMA)
[uncategorized] ~246-~246: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...r 5-7 minutes or until the naan puffs up and the edges turn golden brown. - **Opti...
(COMMA_COMPOUND_SENTENCE_2)
landing/content/1.docs/2.essentials/1.markdown-syntax.md
[uncategorized] ~11-~11: Loose punctuation mark.
Context: ...ation and help users navigate content. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~21-~21: Loose punctuation mark.
Context: ...- ## Titles #code mdc ## Titles :: ### Subtitles Use subtitles to divid...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~27-~27: Loose punctuation mark.
Context: ...tent hierarchy for better readability. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~37-~37: Loose punctuation mark.
Context: ...btitles #code mdc ### Subtitles :: ::tip Each title and subtitle creates...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~39-~39: Loose punctuation mark.
Context: ...les #code mdc ### Subtitles :: ::tip Each title and subtitle creates an ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~41-~41: Loose punctuation mark.
Context: ...automatically in the table of contents. :: ## Text Formatting Nuxt UI supports ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~73-~73: Loose punctuation mark.
Context: ...wrap the link text in brackets [](). ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~83-~83: Loose punctuation mark.
Context: ...t.com/getting-started/installation) ``` :: ### Internal links For linking withi...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~89-~89: Loose punctuation mark.
Context: ... like /getting-started/installation. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~99-~99: Loose punctuation mark.
Context: ...ion](/getting-started/installation) ``` :: ## Lists Organize related items in a...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~109-~109: Loose punctuation mark.
Context: ...ce. Start each item with a - symbol. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[style] ~116-~116: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...a list item. - I'm another list item. - I'm the last list item. #code ```mdc - I...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[uncategorized] ~123-~123: Loose punctuation mark.
Context: ...ist item. - I'm the last list item. ``` :: ### Ordered Use ordered lists when i...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~129-~129: Loose punctuation mark.
Context: ...rocess. Start each item with a number. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[style] ~136-~136: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...list item. 2. I'm another list item. 3. I'm the last list item. #code ```mdc 1. ...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[uncategorized] ~143-~143: Loose punctuation mark.
Context: ...st item. 3. I'm the last list item. ``` :: ### Nested Create hierarchical lists...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~149-~149: Loose punctuation mark.
Context: ... sub-items by four spaces for nesting. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[style] ~156-~156: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...t item. - I'm a nested list item. - I'm another nested list item. - I'm anoth...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~157-~157: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...em. - I'm another nested list item. - I'm another list item. #code ```mdc - I'...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[uncategorized] ~165-~165: Loose punctuation mark.
Context: ...list item. - I'm another list item. ``` :: ## Tables Present structured data in...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~171-~171: Loose punctuation mark.
Context: ... comparing data or listing properties. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~189-~189: Loose punctuation mark.
Context: ...utral|string`{lang="ts-type"} | ``` :: ## Blockquotes Highlight important q...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~199-~199: Loose punctuation mark.
Context: ... Ideal for short and impactful quotes. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~209-~209: Loose punctuation mark.
Context: ...ful and accessible user interfaces. ``` :: ### Multiline Multi-line blockquotes...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~215-~215: Loose punctuation mark.
Context: ... paragraphs within a single quotation. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~229-~229: Loose punctuation mark.
Context: ...ible Vue applications with Nuxt UI. ``` ::
(UNLIKELY_OPENING_PUNCTUATION)
landing/content/3.blog/5.animals.md
[uncategorized] ~19-~19: Loose punctuation mark.
Context: ... the ultimate threat: humans. ## Lion ::picture-and-text --- card: true --- **T...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~31-~31: Loose punctuation mark.
Context: ...ight="400" width="800"} :: ## Monkeys ::picture-and-text --- card: true --- **M...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~43-~43: Loose punctuation mark.
Context: ... height="400" width="800"} :: ## Wolf ::picture-and-text --- card: true --- **W...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~55-~55: Loose punctuation mark.
Context: ...height="400" width="800"} :: ## Bears ::picture-and-text --- card: true --- **B...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~67-~67: Loose punctuation mark.
Context: ... width="800"} :: ## Great White Shark ::picture-and-text --- card: true --- As ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~79-~79: Loose punctuation mark.
Context: ...ght="400" width="800"} :: ## Mosquito ::picture-and-text --- card: true --- Whi...
(UNLIKELY_OPENING_PUNCTUATION)
[style] ~84-~84: This wording could be more concise.
Context: ...cture-and-text --- card: true --- While tiny in size, the mosquito is responsible for mo...
(ADJECTIVE_IN_ATTRIBUTE)
[uncategorized] ~91-~91: Loose punctuation mark.
Context: ...width="800"} :: ## Golden Poison Frog ::picture-and-text --- card: true --- The...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~103-~103: Loose punctuation mark.
Context: ...t="400" width="800"} :: ## King Cobra ::picture-and-text --- card: true --- As ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~115-~115: Loose punctuation mark.
Context: ...ight="400" width="800"} :: ## Jaguars ::picture-and-text --- card: true --- **J...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~127-~127: Loose punctuation mark.
Context: ...eight="400" width="800"} :: ## Humans ::picture-and-text --- card: true --- Whi...
(UNLIKELY_OPENING_PUNCTUATION)
[style] ~136-~136: Using many exclamation marks might seem excessive (in this case: 10 exclamation marks for a text that’s 5061 characters long)
Context: ...onsequences of our own actions. #image 
landing/content/1.docs/2.essentials/3.prose-components.md
[uncategorized] ~11-~11: Loose punctuation mark.
Context: ...ped information in an interactive way. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~47-~47: Loose punctuation mark.
Context: ...stallation) to get started. ::: :: ``` :: ### Badge Use badge to display statu...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~53-~53: Loose punctuation mark.
Context: ...es, or categories within your content. ::code-preview --- label: Preview --- :...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~67-~67: Loose punctuation mark.
Context: ...`mdc ::badge v3.0.0-alpha.10 :: ``` :: ### Callout Use callout to emphasize...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~75-~75: Loose punctuation mark.
Context: ...tcuts for pre-defined semantic styles. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~89-~89: Loose punctuation mark.
Context: ... with full markdown support. :: ``` :: ::code-preview :::div{.flex.flex-co...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~91-~91: Loose punctuation mark.
Context: ...h full markdown support. :: ``` :: ::code-preview :::div{.flex.flex-col.ga...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~128-~128: Loose punctuation mark.
Context: ...on This action cannot be undone. :: ``` :: ### Card Use card to highlight con...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~136-~136: Loose punctuation mark.
Context: ...` properties for navigation. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~162-~162: Loose punctuation mark.
Context: ...hboard with multi-column layout. :: ``` :: ### CardGroup Use card-group to ar...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~168-~168: Loose punctuation mark.
Context: ...sually appealing, and responsive grid. ::code-preview :::card-group{.w-full} ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~257-~257: Loose punctuation mark.
Context: ...u can use as starting point. :: :: ``` :: ### Collapsible Use collapsible to...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~263-~263: Loose punctuation mark.
Context: ...or less frequently needed information. ::code-preview --- class: "[&>div]:*:w-fu...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~287-~287: Loose punctuation mark.
Context: ...l|string{lang="ts-type"} | :: ``` :: ### Field Use field` to describe a ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~293-~293: Loose punctuation mark.
Context: ...onent props, or configuration options. ::code-preview :::field{.w-full require...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~304-~304: Loose punctuation mark.
Context: ... with full markdown support. :: ``` :: ### FieldGroup Use field-group to ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~310-~310: Loose punctuation mark.
Context: ...multiple related fields or properties. ::code-preview :::field-group ::::f...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~349-~349: Loose punctuation mark.
Context: ...re your application's data. :: :: ``` :: ### Icon Use icon to insert icons ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~355-~355: Loose punctuation mark.
Context: ... user interface of your documentation. ::code-preview :icon{name="i-simple-icons...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~364-~364: Loose punctuation mark.
Context: ...on{name="i-simple-icons-nuxtdotjs"} ``` :: ### Kbd Use kbd to display keyboar...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~370-~370: Loose punctuation mark.
Context: ...or instructions or command references. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~374-~374: Loose punctuation mark.
Context: ...preview --- class: "[&>div]:*:my-0" --- :kbd{value="meta"} :kbd{value="K"} #code...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~380-~380: Loose punctuation mark.
Context: ... :kbd{value="meta"} :kbd{value="K"} ``` :: ### Tabs Use tabs and `tabs-item` ...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~386-~386: Loose punctuation mark.
Context: ...tent discoverability and organization. ::code-preview --- class: "[&>div]:*:my-0...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~430-~430: Loose punctuation mark.
Context: ...it ullamco et culpa. :::: ::: :: ```` :: ### Steps Use steps to create step...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~438-~438: Loose punctuation mark.
Context: ... to include in the step-by-step guide. ::code-preview --- class: "[&>div]:*:w-fu...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~480-~480: Loose punctuation mark.
Context: ...dcss"; @import "@nuxt/ui"; ``` :: ```` ::
(UNLIKELY_OPENING_PUNCTUATION)
landing/content/4.changelog/3.dark-mode.md
[style] ~22-~22: Consider using polite language here.
Context: ...more theme customization options soon! Let us know how you like the new look and if you sp...
(INSERT_PLEASE)
[style] ~23-~23: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 910 characters long)
Context: ...nd if you spot any areas for improvement! 💬
(EN_EXCESSIVE_EXCLAMATION)
landing/content/4.changelog/6.performance.md
[style] ~8-~8: Consider using “lot”.
Context: ...p&w=800&q=80 --- ⚡ Our SaaS just got a whole lot faster! This update is all about speed,...
(WHOLE_LOT)
[style] ~21-~21: Consider using polite language here.
Context: ...ools to catch slowdowns before you do. Let us know if you notice the difference—and if the...
(INSERT_PLEASE)
🪛 markdownlint-cli2 (0.18.1)
landing/content/1.docs/1.getting-started/3.usage.md
13-13: Bare URL used
(MD034, no-bare-urls)
18-18: Heading style
Expected: setext; Actual: atx
(MD003, heading-style)
landing/content/1.docs/2.essentials/2.code-blocks.md
16-16: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
20-20: No space after hash on atx style heading
(MD018, no-missing-space-atx)
32-32: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
40-40: No space after hash on atx style heading
(MD018, no-missing-space-atx)
55-55: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
55-55: Multiple headings with the same content
(MD024, no-duplicate-heading)
63-63: No space after hash on atx style heading
(MD018, no-missing-space-atx)
106-106: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4
(MD001, heading-increment)
113-113: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
113-113: Multiple headings with the same content
(MD024, no-duplicate-heading)
126-126: No space after hash on atx style heading
(MD018, no-missing-space-atx)
149-149: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
149-149: Multiple headings with the same content
(MD024, no-duplicate-heading)
169-169: No space after hash on atx style heading
(MD018, no-missing-space-atx)
353-353: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
354-354: Bare URL used
(MD034, no-bare-urls)
366-366: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
371-371: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
371-371: Headings must start at the beginning of the line
(MD023, heading-start-left)
371-371: Multiple headings with the same content
(MD024, no-duplicate-heading)
381-381: No space after hash on atx style heading
(MD018, no-missing-space-atx)
400-400: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
400-400: Multiple headings with the same content
(MD024, no-duplicate-heading)
427-427: No space after hash on atx style heading
(MD018, no-missing-space-atx)
landing/content/3.blog/6.cryptocurrencies.md
51-51: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
51-51: Headings must start at the beginning of the line
(MD023, heading-start-left)
54-54: Bare URL used
(MD034, no-bare-urls)
61-61: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
61-61: Headings must start at the beginning of the line
(MD023, heading-start-left)
64-64: Bare URL used
(MD034, no-bare-urls)
71-71: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
71-71: Headings must start at the beginning of the line
(MD023, heading-start-left)
74-74: Bare URL used
(MD034, no-bare-urls)
81-81: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
81-81: Headings must start at the beginning of the line
(MD023, heading-start-left)
84-84: Bare URL used
(MD034, no-bare-urls)
91-91: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
91-91: Headings must start at the beginning of the line
(MD023, heading-start-left)
94-94: Bare URL used
(MD034, no-bare-urls)
101-101: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
101-101: Headings must start at the beginning of the line
(MD023, heading-start-left)
104-104: Bare URL used
(MD034, no-bare-urls)
landing/content/3.blog/1.asian-cuisine.md
77-77: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
80-80: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
81-81: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
82-82: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
83-83: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
84-84: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
88-88: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
90-90: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
93-93: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
98-98: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
101-101: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
103-103: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
106-106: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
118-118: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
118-118: Headings must start at the beginning of the line
(MD023, heading-start-left)
122-122: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
123-123: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
124-124: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
125-125: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
126-126: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
127-127: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
128-128: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
129-129: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
130-130: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
131-131: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
132-132: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
136-136: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
140-140: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
142-142: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
145-145: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
147-147: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
150-150: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
152-152: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
154-154: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
166-166: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
166-166: Headings must start at the beginning of the line
(MD023, heading-start-left)
166-166: Multiple headings with the same content
(MD024, no-duplicate-heading)
170-170: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
171-171: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
172-172: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
173-173: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
174-174: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
175-175: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
176-176: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
177-177: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
178-178: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
179-179: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
180-180: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
184-184: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
187-187: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
191-191: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
198-198: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
201-201: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
203-203: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
206-206: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
218-218: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
219-219: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
220-220: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
221-221: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
222-222: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
223-223: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
224-224: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
225-225: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
229-229: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
231-231: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
235-235: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
237-237: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
239-239: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
241-241: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
244-244: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
247-247: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
249-249: Unordered list indentation
Expected: 0; Actual: 2
(MD007, ul-indent)
landing/content/1.docs/2.essentials/1.markdown-syntax.md
14-14: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
16-16: Multiple headings with the same content
(MD024, no-duplicate-heading)
18-18: No space after hash on atx style heading
(MD018, no-missing-space-atx)
30-30: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
30-30: Multiple headings with the same content
(MD024, no-duplicate-heading)
34-34: No space after hash on atx style heading
(MD018, no-missing-space-atx)
76-76: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
76-76: Multiple headings with the same content
(MD024, no-duplicate-heading)
80-80: No space after hash on atx style heading
(MD018, no-missing-space-atx)
92-92: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
92-92: Multiple headings with the same content
(MD024, no-duplicate-heading)
96-96: No space after hash on atx style heading
(MD018, no-missing-space-atx)
112-112: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
112-112: Multiple headings with the same content
(MD024, no-duplicate-heading)
118-118: No space after hash on atx style heading
(MD018, no-missing-space-atx)
132-132: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
132-132: Multiple headings with the same content
(MD024, no-duplicate-heading)
138-138: No space after hash on atx style heading
(MD018, no-missing-space-atx)
152-152: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
152-152: Multiple headings with the same content
(MD024, no-duplicate-heading)
159-159: No space after hash on atx style heading
(MD018, no-missing-space-atx)
174-174: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
176-176: Tables should be surrounded by blank lines
(MD058, blanks-around-tables)
182-182: No space after hash on atx style heading
(MD018, no-missing-space-atx)
202-202: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
202-202: Multiple headings with the same content
(MD024, no-duplicate-heading)
206-206: No space after hash on atx style heading
(MD018, no-missing-space-atx)
218-218: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
218-218: Multiple headings with the same content
(MD024, no-duplicate-heading)
224-224: No space after hash on atx style heading
(MD018, no-missing-space-atx)
landing/content/3.blog/5.animals.md
22-22: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
26-26: No space after hash on atx style heading
(MD018, no-missing-space-atx)
34-34: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
34-34: Multiple headings with the same content
(MD024, no-duplicate-heading)
38-38: No space after hash on atx style heading
(MD018, no-missing-space-atx)
46-46: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
46-46: Multiple headings with the same content
(MD024, no-duplicate-heading)
50-50: No space after hash on atx style heading
(MD018, no-missing-space-atx)
58-58: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
58-58: Multiple headings with the same content
(MD024, no-duplicate-heading)
62-62: No space after hash on atx style heading
(MD018, no-missing-space-atx)
70-70: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
70-70: Multiple headings with the same content
(MD024, no-duplicate-heading)
74-74: No space after hash on atx style heading
(MD018, no-missing-space-atx)
82-82: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
82-82: Multiple headings with the same content
(MD024, no-duplicate-heading)
86-86: No space after hash on atx style heading
(MD018, no-missing-space-atx)
94-94: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
94-94: Multiple headings with the same content
(MD024, no-duplicate-heading)
98-98: No space after hash on atx style heading
(MD018, no-missing-space-atx)
106-106: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
106-106: Multiple headings with the same content
(MD024, no-duplicate-heading)
110-110: No space after hash on atx style heading
(MD018, no-missing-space-atx)
118-118: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
118-118: Multiple headings with the same content
(MD024, no-duplicate-heading)
122-122: No space after hash on atx style heading
(MD018, no-missing-space-atx)
130-130: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
130-130: Multiple headings with the same content
(MD024, no-duplicate-heading)
136-136: No space after hash on atx style heading
(MD018, no-missing-space-atx)
landing/content/1.docs/2.essentials/3.prose-components.md
17-17: No space after hash on atx style heading
(MD018, no-missing-space-atx)
36-36: No space after hash on atx style heading
(MD018, no-missing-space-atx)
48-48: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
53-53: No space after hash on atx style heading
(MD018, no-missing-space-atx)
| @@ -0,0 +1,34 @@ | |||
| name: ci | |||
|
|
|||
| on: push | |||
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.
Add pull_request trigger to catch issues during code review.
The workflow currently only runs on push, which means CI validation happens after code is merged. Add pull_request trigger to run checks before merge and provide early feedback during review.
- on: push
+ on:
+ - push
+ - pull_request📝 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.
| on: push | |
| on: | |
| - push | |
| - pull_request |
🤖 Prompt for AI Agents
In landing/.github/workflows/ci.yml around line 3, the workflow only triggers on
push so CI doesn't run for PRs; update the workflow triggers to include
pull_request alongside push (e.g., add a pull_request key with the same branches
or patterns as push) so checks run on PRs and provide early feedback during
review.
| function onSubmit() { | ||
| loading.value = true | ||
|
|
||
| toast.add({ | ||
| title: 'Subscribed!', | ||
| description: 'You\'ve been subscribed to our newsletter.' | ||
| }) | ||
| } |
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.
Reset loading state and clear email after submission.
Two issues:
- Line 43 sets
loading.value = truebut never resets it, leaving the form permanently in a loading state. - The
emailfield is never cleared after submission, creating poor UX.
Apply this diff:
function onSubmit() {
loading.value = true
toast.add({
title: 'Subscribed!',
description: 'You\'ve been subscribed to our newsletter.'
})
+
+ loading.value = false
+ email.value = ''
}For a production implementation, you'd want to reset loading after an async operation completes, but for this template the immediate reset is appropriate.
📝 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 onSubmit() { | |
| loading.value = true | |
| toast.add({ | |
| title: 'Subscribed!', | |
| description: 'You\'ve been subscribed to our newsletter.' | |
| }) | |
| } | |
| function onSubmit() { | |
| loading.value = true | |
| toast.add({ | |
| title: 'Subscribed!', | |
| description: 'You\'ve been subscribed to our newsletter.' | |
| }) | |
| loading.value = false | |
| email.value = '' | |
| } |
🤖 Prompt for AI Agents
In landing/app/components/AppFooter.vue around lines 42 to 49, onSubmit
currently sets loading.value = true but never resets it and never clears the
email field; update onSubmit to set loading.value = true, immediately set
loading.value = false after the (placeholder) submission completes, and clear
the email model (e.g., set email.value = ''), ensuring both loading and email
are reset for correct UX.
| <pattern | ||
| id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e" | ||
| x="0" | ||
| y="0" | ||
| width="10" | ||
| height="10" | ||
| patternUnits="userSpaceOnUse" | ||
| > | ||
| <path d="M-3 13 15-5M-5 5l18-18M-1 21 17 3" /> | ||
| </pattern> | ||
| </defs> | ||
| <rect | ||
| stroke="none" | ||
| fill="url(#pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e)" |
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.
Generate unique SVG pattern IDs to prevent conflicts.
The hardcoded pattern ID pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e will cause rendering issues if multiple instances of this component appear on the same page, as SVG IDs must be unique within a document.
Use useId() to generate a unique ID per component instance:
<script setup lang="ts">
+const patternId = useId()
</script>
<template>
<UPageCard
variant="subtle"
>
<div class="relative overflow-hidden rounded-sm border border-dashed border-accented opacity-75 px-4 flex items-center justify-center aspect-video">
<svg
class="absolute inset-0 h-full w-full stroke-inverted/10"
fill="none"
>
<defs>
<pattern
- id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e"
+ :id="patternId"
x="0"
y="0"
width="10"
height="10"
patternUnits="userSpaceOnUse"
>
<path d="M-3 13 15-5M-5 5l18-18M-1 21 17 3" />
</pattern>
</defs>
<rect
stroke="none"
- fill="url(#pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e)"
+ :fill="`url(#${patternId})`"
width="100%"
height="100%"
/>
</svg>
<slot />
</div>
</UPageCard>
</template>Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In landing/app/components/ImagePlaceholder.vue around lines 11-24 the SVG
pattern uses a hardcoded id which will collide when multiple component instances
render; in setup() call useId() to generate a unique suffix (e.g. const id =
useId(); const patternId = `pattern-${id}`), replace the hardcoded id on the
<pattern> with :id="patternId" and replace the fill reference with a bound
attribute like :fill="`url(#${patternId})`" so each component instance gets a
unique SVG ID.
| <video | ||
| class="rounded-xl" | ||
| data-v-baf90ddd="" | ||
| preload="none" | ||
| poster="https://res.cloudinary.com/nuxt/video/upload/so_3.3/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.jpg" | ||
| :controls="true" | ||
| ><source | ||
| data-v-baf90ddd="" | ||
| src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.webm" | ||
| type="video/webm" | ||
| ><source | ||
| data-v-baf90ddd="" | ||
| src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.mp4" | ||
| type="video/mp4" | ||
| ><source | ||
| data-v-baf90ddd="" | ||
| src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.ogg" | ||
| type="video/ogg" | ||
| > | ||
| </video> |
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.
Remove hardcoded scoped style attributes and replace placeholder content.
The template contains several issues:
- The
data-v-baf90ddd=""attributes (lines 9, 14, 18, 22) are Vue's scoped style identifiers that should not be present in the source code—they're added automatically during compilation. - The video sources point to Nuxt UI Pro example content and should be replaced with your actual promotional video.
- Missing accessibility features: no
<track>element for captions/subtitles (required for WCAG compliance).
Apply this diff to fix the scoped attributes and improve accessibility:
<video
class="rounded-xl"
- data-v-baf90ddd=""
preload="none"
poster="https://res.cloudinary.com/nuxt/video/upload/so_3.3/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.jpg"
:controls="true"
><source
- data-v-baf90ddd=""
src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.webm"
type="video/webm"
><source
- data-v-baf90ddd=""
src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.mp4"
type="video/mp4"
><source
- data-v-baf90ddd=""
src="https://res.cloudinary.com/nuxt/video/upload/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.ogg"
type="video/ogg"
>
+ <track
+ kind="captions"
+ src="/captions/promotional-video.vtt"
+ srclang="en"
+ label="English"
+ >
</video>🤖 Prompt for AI Agents
In landing/app/components/PromotionalVideo.vue around lines 7 to 26, remove the
hardcoded scoped attributes (the data-v-baf90ddd="" on the video and source
tags) since those are compiler-generated and must not be in source; replace the
example Nuxt UI Pro poster and source URLs with your actual promotional video
asset URLs (use proper .webm/.mp4/.ogg sources as needed or a single
high-quality mp4) and update the poster attribute accordingly; add a <track>
element pointing to a captions/subtitles VTT file (kind="subtitles", srclang and
label attributes) to provide accessible captions, ensure controls and preload
are set appropriately (e.g., preload="metadata"), and remove any empty
attributes so the template contains only valid, accessible markup referencing
your real assets.
| const props = withDefaults(defineProps<{ | ||
| starCount?: number | ||
| color?: string | ||
| speed?: 'slow' | 'normal' | 'fast' | ||
| size?: { min: number, max: number } | ||
| }>(), { | ||
| starCount: 300, | ||
| color: 'var(--ui-primary)', | ||
| speed: 'normal', | ||
| size: () => ({ | ||
| min: 1, | ||
| max: 2 | ||
| }) | ||
| }) |
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.
Wire the speed prop into the animation.
speed is exposed as part of the public API but never influences the animation, so consumers cannot slow down or speed up the background despite the prop existing. Please multiply the layer durations (or otherwise adjust the animation timing) based on props.speed instead of leaving the prop unused.
-const starLayers = computed(() => [
- { stars: stars.value.fast, ...speedMap.fast },
- { stars: stars.value.normal, ...speedMap.normal },
- { stars: stars.value.slow, ...speedMap.slow }
-])
+const speedMultiplier = computed(() => {
+ switch (props.speed) {
+ case 'slow':
+ return 1.5
+ case 'fast':
+ return 0.75
+ default:
+ return 1
+ }
+})
+
+const starLayers = computed(() => [
+ {
+ stars: stars.value.fast,
+ ...speedMap.fast,
+ duration: speedMap.fast.duration * speedMultiplier.value
+ },
+ {
+ stars: stars.value.normal,
+ ...speedMap.normal,
+ duration: speedMap.normal.duration * speedMultiplier.value
+ },
+ {
+ stars: stars.value.slow,
+ ...speedMap.slow,
+ duration: speedMap.slow.duration * speedMultiplier.value
+ }
+])Committable suggestion skipped: line range outside the PR's diff.
| title: string | ||
| description: string | ||
| date: string | ||
| image?: HTMLImageElement |
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.
Fix incorrect type: image should not be HTMLImageElement.
HTMLImageElement is a DOM element type, not suitable for content metadata. Blog post images are typically objects with src, alt, etc., or could be strings (paths).
Apply this diff to use a proper image type:
export interface BlogPost extends ParsedContent {
title: string
description: string
date: string
- image?: HTMLImageElement
+ image?: { src: string; alt?: string }
badge?: Badge
authors?: ({Or verify the actual image structure used by @nuxt/content and align with that.
📝 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.
| image?: HTMLImageElement | |
| export interface BlogPost extends ParsedContent { | |
| title: string | |
| description: string | |
| date: string | |
| image?: { src: string; alt?: string } | |
| badge?: Badge | |
| authors?: ({ |
🤖 Prompt for AI Agents
In landing/app/types/index.d.ts around line 8, the image property is incorrectly
typed as HTMLImageElement; replace it with a content-appropriate type such as a
string or a plain object (for example: string | { src: string; alt?: string;
caption?: string; width?: number; height?: number }) or the exact image shape
used by @nuxt/content; update the type declaration accordingly and ensure any
code consuming this type is adjusted to the new shape (or import the correct
@nuxt/content image type) so runtime content metadata uses the proper structure.
| ### `CodePreview` | ||
|
|
||
| Use `code-preview` to show code output alongside the code. `code-preview` is ideal for interactive examples and demonstrating code results. | ||
| Write the code to be previewed in a the `default` slot and the actual code in the `code` slot. |
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.
Fix grammar error.
There's a duplicate article: "in a the" should be "in the".
Apply this diff:
-Write the code to be previewed in a the `default` slot and the actual code in the `code` slot.
+Write the code to be previewed in the `default` slot and the actual code in the `code` slot.📝 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.
| Write the code to be previewed in a the `default` slot and the actual code in the `code` slot. | |
| Write the code to be previewed in the `default` slot and the actual code in the `code` slot. |
🧰 Tools
🪛 LanguageTool
[grammar] ~362-~362: Two determiners in a row. Choose either “a” or “the”.
Context: ...ults. Write the code to be previewed in a the default slot and the actual code in t...
(DT_DT)
🤖 Prompt for AI Agents
In landing/content/1.docs/2.essentials/2.code-blocks.md around line 362, fix the
grammar by replacing the phrase "in a the `default` slot" with "in the `default`
slot" so the sentence reads: "Write the code to be previewed in the `default`
slot and the actual code in the `code` slot."
|
|
||
|
|
||
| #code | ||
| ```mdc |
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.
Fix grammar error.
There's a duplicate article: "in a the" should be "in the".
Apply this diff:
-Write the code to be previewed in a the `default` slot and the actual code in the `code` slot.
+Write the code to be previewed in the `default` slot and the actual code in the `code` slot.Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In landing/content/1.docs/2.essentials/3.prose-components.md around line 362,
fix the grammar mistake where the duplicate article "in a the" appears by
removing the extra article so the phrase reads "in the"; update the sentence
accordingly and ensure spacing and punctuation remain correct after the change.
| ## Lion | ||
|
|
||
| ::picture-and-text | ||
| --- | ||
| card: true | ||
| --- | ||
| **Tigers** are dangerous to humans because of their immense strength, powerful jaws, and sharp claws, capable of causing fatal injuries. Additionally, tigers are territorial and can become highly aggressive if they feel threatened or if their territory is encroached upon. | ||
|
|
||
| #image | ||
| {.rounded-lg height="400" width="800"} | ||
| :: |
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.
Fix content mismatch: "Tigers" described under "Lion" heading.
Line 24 describes Tigers, but the section heading on Line 18 says "Lion". This creates confusion for readers.
Either update the heading to "Tiger" or rewrite the content to describe lions instead of tigers.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~19-~19: Loose punctuation mark.
Context: ... the ultimate threat: humans. ## Lion ::picture-and-text --- card: true --- **T...
(UNLIKELY_OPENING_PUNCTUATION)
🪛 markdownlint-cli2 (0.18.1)
22-22: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
26-26: No space after hash on atx style heading
(MD018, no-missing-space-atx)
🤖 Prompt for AI Agents
In landing/content/3.blog/5.animals.md around lines 18 to 28: the section
heading reads "Lion" but the body text on line 24 describes "Tigers", causing a
content mismatch; fix by either (A) change the heading to "Tiger" and update the
image alt/text to match "Tiger", or (B) rewrite the paragraph to describe lions
(mention mane, pride behavior, hunting style, and threats) and update the image
alt/text to "Lion" so heading, content, and image are consistent.
|
|
||
| - **Volatility:** Cryptocurrency markets are characterized by high volatility, subject to speculative trading, market manipulation, and sudden price fluctuations, posing risks to investors and stability. | ||
| - **Regulatory Uncertainty:** Governments and regulatory bodies worldwide are grappling with the regulation of cryptocurrencies, raising concerns about legal compliance, taxation, and investor protection. | ||
| - **Security Concerns:** Cryptocurrency exchanges and wallets are vulnerable to cyber attacks, theft, and fraud, necessitating robust security measures and risk management practices. |
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.
Fix the spelling of "cyberattacks."
The term should be written as one word: "cyberattacks" rather than "cyber attacks."
Apply this diff:
-- **Security Concerns:** Cryptocurrency exchanges and wallets are vulnerable to cyber attacks, theft, and fraud, necessitating robust security measures and risk management practices.
+- **Security Concerns:** Cryptocurrency exchanges and wallets are vulnerable to cyberattacks, theft, and fraud, necessitating robust security measures and risk management practices.📝 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.
| - **Security Concerns:** Cryptocurrency exchanges and wallets are vulnerable to cyber attacks, theft, and fraud, necessitating robust security measures and risk management practices. | |
| - **Security Concerns:** Cryptocurrency exchanges and wallets are vulnerable to cyberattacks, theft, and fraud, necessitating robust security measures and risk management practices. |
🧰 Tools
🪛 LanguageTool
[grammar] ~41-~41: The word “cyberattacks” is spelled as one.
Context: ...exchanges and wallets are vulnerable to cyber attacks, theft, and fraud, necessitating robust...
(CYBER_COMPOUNDS)
🤖 Prompt for AI Agents
In landing/content/3.blog/6.cryptocurrencies.md around line 41, the phrase
"cyber attacks" should be corrected to the single-word spelling "cyberattacks";
update that word in the sentence so it reads "...vulnerable to cyberattacks,
theft, and fraud..." preserving punctuation and spacing.
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: 7
♻️ Duplicate comments (2)
landing/app/components/AppFooter.vue (1)
42-49: Reset loading state and clear email after submission.The
onSubmitfunction setsloading.value = truebut never resets it, leaving the button in a permanent loading state. Additionally, the email field is never cleared after submission.Apply this diff:
function onSubmit() { loading.value = true toast.add({ title: 'Subscribed!', description: 'You\'ve been subscribed to our newsletter.' }) + + loading.value = false + email.value = '' }landing/app/pages/index.vue (1)
2-12: Replaceanytype assertion with proper typing.The type assertion to
anybypasses TypeScript's type safety. Define a proper interface for the page data structure.Consider creating a type definition:
// In landing/app/types/content.d.ts export interface IndexPageData { title: string description: string seo?: { title?: string description?: string } hero?: { links?: Array<{ label: string to: string icon?: string trailing?: boolean size?: string color?: string variant?: string target?: string }> } sections?: Array<{ title: string description: string orientation?: string reverse?: boolean features?: Array<{ name: string description: string icon: string }> }> features?: { title: string description: string items: Array<{ title: string description: string icon: string }> } testimonials?: { headline: string title: string description: string items: Array<{ quote: string user: { name: string description: string avatar: { src: string } } }> } cta?: { title: string description: string links: Array<any> } }Then update the type assertion:
-}) as any +}) as { data: Ref<IndexPageData | null> }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
landing/public/android-chrome-192x192.pngis excluded by!**/*.pnglanding/public/android-chrome-512x512.pngis excluded by!**/*.pnglanding/public/apple-touch-icon.pngis excluded by!**/*.pnglanding/public/favicon-16x16.pngis excluded by!**/*.pnglanding/public/favicon-32x32.pngis excluded by!**/*.pnglanding/public/favicon.icois excluded by!**/*.ico
📒 Files selected for processing (10)
landing/README.md(1 hunks)landing/app/app.vue(1 hunks)landing/app/components/AppFooter.vue(1 hunks)landing/app/components/AppHeader.vue(1 hunks)landing/app/components/AppLogo.vue(1 hunks)landing/app/pages/index.vue(1 hunks)landing/content/0.index.yml(1 hunks)landing/nuxt.config.ts(1 hunks)landing/package.json(1 hunks)landing/public/site.webmanifest(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- landing/app/app.vue
- landing/package.json
🧰 Additional context used
🪛 LanguageTool
landing/README.md
[uncategorized] ~41-~41: Use a comma before ‘and’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...ations/select_target) on your repository and you are good to go.
(COMMA_COMPOUND_SENTENCE)
🔇 Additional comments (6)
landing/README.md (1)
1-41: LGTM!The README provides clear setup and development instructions for the landing page project.
landing/nuxt.config.ts (1)
2-50: Overall configuration looks good.The Nuxt configuration is well-structured with appropriate modules for a SaaS landing page (UI, content, images, OG images, etc.).
landing/app/components/AppHeader.vue (1)
1-86: LGTM!The header component is well-structured with proper responsive design patterns, using horizontal navigation for desktop and a vertical menu in the body slot for mobile.
landing/app/pages/index.vue (1)
29-113: Template structure is well organized.The conditional rendering and debug state provide good developer experience, and the component composition follows Nuxt UI patterns effectively.
landing/public/site.webmanifest (1)
5-16: Icon files verified—no issues found.Both icon files referenced in the manifest exist in the repository:
landing/public/android-chrome-192x192.png✓landing/public/android-chrome-512x512.png✓landing/app/components/AppLogo.vue (1)
2-6: Logo file exists—no action required.The verification confirms that
sendook-logo.svgexists atlanding/public/sendook-logo.svg, which will correctly resolve to/sendook-logo.svgin the component. The original concern is unfounded.Likely an incorrect or invalid review comment.
| const columns = [{ | ||
| label: 'Resources', | ||
| children: [{ | ||
| label: 'Help center' | ||
| }, { | ||
| label: 'Docs' | ||
| }, { | ||
| label: 'Roadmap' | ||
| }, { | ||
| label: 'Changelog' | ||
| }] | ||
| }, { | ||
| label: 'Features', | ||
| children: [{ | ||
| label: 'Affiliates' | ||
| }, { | ||
| label: 'Portal' | ||
| }, { | ||
| label: 'Jobs' | ||
| }, { | ||
| label: 'Sponsors' | ||
| }] | ||
| }, { | ||
| label: 'Company', | ||
| children: [{ | ||
| label: 'About' | ||
| }, { | ||
| label: 'Pricing' | ||
| }, { | ||
| label: 'Careers' | ||
| }, { | ||
| label: 'Blog' | ||
| }] | ||
| }] |
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.
Footer link items are missing destination URLs.
The column items have labels but no to properties, making them non-functional links. Consider adding destination URLs or a note if these are placeholders.
Example fix for making links functional:
const columns = [{
label: 'Resources',
children: [{
- label: 'Help center'
+ label: 'Help center',
+ to: '/help'
}, {
- label: 'Docs'
+ label: 'Docs',
+ to: '/docs'
},
// ... etcCommittable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In landing/app/components/AppFooter.vue around lines 2 to 35, the footer columns
define link labels but omit destination properties so the links are
non-functional; add a `to` (for router-link) or `href` property to each child
item (or explicitly mark them as placeholders with a `disabled` flag or `null`
target) so they render as real navigable links; ensure you use the correct
property expected by the footer component (e.g., `to` for internal routes or
`href` for external URLs), include valid URL strings or route names, and keep
accessibility in mind (provide descriptive link text and avoid empty anchors).
| '/docs': { redirect: '/docs/getting-started', prerender: false } | ||
| }, | ||
|
|
||
| compatibilityDate: '2024-07-11', |
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
Verify the compatibility date is current.
The compatibilityDate is set to '2024-07-11', which is over a year old. For a new Nuxt 4 project, this should typically be set to a more recent date.
🌐 Web query:
What should the compatibilityDate be set to for a new Nuxt 4 project in November 2025?
💡 Result:
Set compatibilityDate to today's date (for a new project in November 2025 use "2025-11-10"). This ensures you opt into the current presets/behaviors; Nuxt docs describe compatibilityDate for controlling preset behavior, and providers (e.g. Netlify) recommend using the current day. [1][2][3]
Sources:
[1] Nuxt config docs — compatibilityDate.
[2] Netlify guide recommending setting compatibilityDate to current day.
[3] Explanation showing a recent default example (2025-07-15) in community write-up.
Update compatibilityDate to '2025-11-10' to reflect current date.
For a new Nuxt 4 project in November 2025, the compatibilityDate should be set to "2025-11-10" to ensure you opt into the current presets and behaviors. The current value of '2024-07-11' is outdated.
🤖 Prompt for AI Agents
In landing/nuxt.config.ts around line 31, update the outdated compatibilityDate
value; change the string '2024-07-11' to '2025-11-10' so the Nuxt config opts
into current presets and behaviors.
| "theme_color": "#080708", | ||
| "background_color": "#ffffff", |
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.
Consider aligning theme_color with background_color.
The theme_color is very dark (#080708) while background_color is white (#ffffff). This contrast may cause a visual flash during app load, particularly noticeable in dark mode.
Consider setting both to similar values or making background_color match your app's initial load state:
"theme_color": "#080708",
- "background_color": "#ffffff",
+ "background_color": "#080708",📝 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.
| "theme_color": "#080708", | |
| "background_color": "#ffffff", | |
| "theme_color": "#080708", | |
| "background_color": "#080708", |
🤖 Prompt for AI Agents
In landing/public/site.webmanifest around lines 17 to 18, the theme_color
(#080708) and background_color (#ffffff) are highly contrasting which can cause
a visual flash on app load; update either theme_color to match the white
background or set background_color to the intended dark theme value so both
reflect the app's initial UI state (e.g., make theme_color and background_color
the same hex or adjust background_color to the dark hex) and ensure the manifest
reflects the actual initial load styling.
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
🧹 Nitpick comments (4)
landing/content/4.changelog/4.integrations.md (1)
43-43: Consider adding "please" for more polite phrasing.The closing line would benefit from a small politeness adjustment to align with professional communication norms.
-More language SDKs coming soon—Go and Ruby are next! Let us know what you need. 📨 +More language SDKs coming soon—Go and Ruby are next! Please let us know what you need. 📨README.md (2)
185-185: Fix compound adjective formatting."Open source software" should use a hyphen when functioning as a compound adjective: "open-source software".
-Sendook is open source software licensed under the [MIT license](./LICENSE). +Sendook is open-source software licensed under the [MIT license](./LICENSE).
179-179: Consider more formal language in contribution guidelines.The word "amazing" is informal for documentation. Consider alternatives like "remarkable", "excellent", or just describe the feature specifically.
-3. Commit your changes (`git commit -m 'Add amazing feature'`) +3. Commit your changes (`git commit -m 'Add excellent feature'`)landing/README.md (1)
46-61: Add language specification to code block.Per markdownlint rules, fenced code blocks should specify a language. For the directory structure, use
bashor plain text (leave empty or use no language):-``` +```bash landing/ ├── app/ │ ├── components/ # Vue components
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
README.md(1 hunks)landing/README.md(1 hunks)landing/content/0.index.yml(1 hunks)landing/content/1.docs/1.getting-started/1.index.md(1 hunks)landing/content/1.docs/1.getting-started/2.installation.md(1 hunks)landing/content/1.docs/1.getting-started/3.usage.md(1 hunks)landing/content/2.pricing.yml(1 hunks)landing/content/3.blog.yml(1 hunks)landing/content/4.changelog.yml(1 hunks)landing/content/4.changelog/1.launch.md(1 hunks)landing/content/4.changelog/4.integrations.md(1 hunks)landing/public/site.webmanifest(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- landing/content/3.blog.yml
🚧 Files skipped from review as they are similar to previous changes (5)
- landing/content/4.changelog.yml
- landing/content/1.docs/1.getting-started/1.index.md
- landing/content/1.docs/1.getting-started/2.installation.md
- landing/public/site.webmanifest
- landing/content/2.pricing.yml
🧰 Additional context used
🪛 LanguageTool
landing/content/4.changelog/4.integrations.md
[style] ~43-~43: Consider using polite language here.
Context: ... SDKs coming soon—Go and Ruby are next! Let us know what you need. 📨
(INSERT_PLEASE)
landing/content/4.changelog/1.launch.md
[style] ~25-~25: Consider using polite language here.
Context: ...AI agents need to communicate at scale. Let us know what you'd like to see next! ✨
(INSERT_PLEASE)
README.md
[uncategorized] ~9-~9: Possible missing article found.
Context: ...PIs and AWS SES setup. Sendook provides simple, powerful email infrastructure designed...
(AI_HYDRA_LEO_MISSING_A)
[grammar] ~135-~135: Possible agreement error. The noun ‘page’ seems to be countable.
Context: ...ts: - API server on port 3000 - Landing page on port 3001 - MongoDB on port 27017 #...
(CD_NN)
[uncategorized] ~136-~136: Possible missing comma found.
Context: ... Landing page on port 3001 - MongoDB on port 27017 ## 📖 Documentation - **[Gettin...
(AI_HYDRA_LEO_MISSING_COMMA)
[style] ~179-~179: Consider using a more formal and expressive alternative to ‘amazing’.
Context: ...azing-feature) 3. Commit your changes (git commit -m 'Add amazing feature') 4. Push to the branch (git ...
(AWESOME)
[uncategorized] ~185-~185: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...Pull Request ## 📝 License Sendook is open source software licensed under the [MIT licens...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
landing/content/1.docs/1.getting-started/3.usage.md
[uncategorized] ~32-~32: It seems likely that a singular genitive (’s) apostrophe is missing.
Context: ...by an inbox. They include: - Sender and recipients - Subject and body (HTML and plain text...
(AI_HYDRA_LEO_APOSTROPHE_S_XS)
[uncategorized] ~56-~56: Loose punctuation mark.
Context: ...e output: agent-abc123@sendook.app ``` ::tip Pro tip: Create separate inboxe...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...ifications) to keep messages organized. :: ### 2. Send an Email Send emails fro...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~140-~140: Loose punctuation mark.
Context: ... res.status(200).send('OK'); }); ``` ::warning Important: Always verify we...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~142-~142: Loose punctuation mark.
Context: ...es to ensure requests are from Sendook. :: ### 5. Search Messages Query your ag...
(UNLIKELY_OPENING_PUNCTUATION)
🪛 markdownlint-cli2 (0.18.1)
landing/README.md
46-46: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (7)
landing/content/4.changelog/4.integrations.md (2)
1-6: Well-structured front matter and metadata.The YAML front matter is properly formatted with appropriate keys (title, description, date, image). The metadata will integrate cleanly with the Nuxt content system.
8-41: Clear, engaging changelog content with well-organized sections.The narrative is well-paced, features are clearly bulleted, the Python SDK example is practical and demonstrates idiomatic async usage, and the behind-the-scenes note provides transparency. The emoji-based visual hierarchy reinforces the content structure and maintains an approachable tone.
landing/content/4.changelog/1.launch.md (3)
1-6: YAML front matter looks good.The metadata is correctly formatted and includes all expected fields for a changelog entry.
8-25: Well-structured launch announcement.The content is clearly written with good use of emoji, logical sections (features, production readiness, call-to-action), and appropriate tone for a landing page. The marketing message is compelling and addresses the core pain point (email infrastructure complexity).
1-5: Verify placeholder assets.The date field is set to
2024-04-01and the image is sourced from Unsplash generic stock photography. Confirm these are intentional or replace with branded assets and the actual launch date if needed.landing/content/1.docs/1.getting-started/3.usage.md (1)
1-343: Comprehensive and well-structured usage documentation—approve with link fixes.The documentation is clearly organized, provides practical code examples, includes helpful callouts (tips/warnings), and covers both common workflows and best practices effectively. The examples are appropriate for a Node.js/JavaScript client library and demonstrate idiomatic usage patterns.
Static analysis flagged several items (loose punctuation on lines 56, 58, 140, 142 and apostrophe on line 32), but these appear to be false positives related to Markdown callout syntax and standard English grammar. Once you fix the links in the Next Steps section, this documentation will be ready to merge.
landing/content/0.index.yml (1)
1-156: Excellent work addressing all previous review feedback.All four previously flagged issues have been resolved:
- ✅ Hero links now correctly point to
/docs/getting-startedand the Sendook repository- ✅ Feature sections rewritten with sendook-specific capabilities (instant inboxes, webhooks, JSON responses, search, threading, etc.)
- ✅ Testimonials updated to focus on email infrastructure benefits and AI agent use cases
- ✅ CTA updated with sendook-specific messaging and proper action links
The content is now fully sendook-focused and marketing-ready. All placeholder/template references have been removed, and the messaging clearly articulates product value propositions specific to AI agent email infrastructure.
| - [API Reference](/docs/essentials/markdown-syntax) - Complete API documentation | ||
| - [Webhooks](/docs/essentials/code-blocks) - Advanced webhook configuration | ||
| - [Code Examples](/docs/essentials/prose-components) - More integration examples |
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.
Fix broken/placeholder documentation links in "Next Steps" section.
The cross-references in the Next Steps section appear to be placeholder/incorrect paths that don't match the link titles:
/docs/essentials/markdown-syntaxis labeled "API Reference" (path doesn't match)/docs/essentials/code-blocksis labeled "Webhooks" (path doesn't match)/docs/essentials/prose-componentsis labeled "Code Examples" (path doesn't match)
Please verify and correct these links to point to the actual documentation pages. For example, they should likely reference paths like /docs/api-reference, /docs/webhooks-guide, and /docs/code-examples (adjust based on your actual documentation structure).
🤖 Prompt for AI Agents
landing/content/1.docs/1.getting-started/3.usage.md lines 344-346: The three
links in the "Next Steps" list are pointing to placeholder/incorrect paths;
update each anchor href to the correct documentation routes (e.g. replace
/docs/essentials/markdown-syntax with the real API reference path such as
/docs/api-reference, replace /docs/essentials/code-blocks with the real webhooks
guide path such as /docs/webhooks-guide, and replace
/docs/essentials/prose-components with the real code examples path such as
/docs/code-examples), verify those target pages exist in the repo/site and
adjust the paths to match their actual locations, and keep the visible link text
unchanged.
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: 2
🧹 Nitpick comments (1)
landing/app/components/AppHeader.vue (1)
4-17: Add active state tracking for all navigation items.Only the "Docs" item tracks active state using
route.path.startsWith('/docs'). The other navigation items (Pricing, Blog, Changelog) lack active state logic, so users won't see visual feedback indicating which page they're currently on.Apply this diff to add consistent active state tracking:
const items = computed(() => [{ label: 'Docs', to: '/docs', active: route.path.startsWith('/docs') }, { label: 'Pricing', - to: '/pricing' + to: '/pricing', + active: route.path.startsWith('/pricing') }, { label: 'Blog', - to: '/blog' + to: '/blog', + active: route.path.startsWith('/blog') }, { label: 'Changelog', - to: '/changelog' + to: '/changelog', + active: route.path.startsWith('/changelog') }])
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
landing/app/components/AppHeader.vue(1 hunks)landing/content/0.index.yml(1 hunks)
🔇 Additional comments (4)
landing/content/0.index.yml (4)
80-144: Excellent testimonial customization.The testimonials have been thoroughly updated to reflect sendook's email infrastructure value proposition for AI agents. Each quote highlights specific, credible benefits (webhooks for real-time response, JSON format, search API, open source transparency, multi-inbox isolation, self-hosting flexibility, TypeScript SDKs, thread management) rather than generic SaaS marketing language. This represents a significant improvement from the previous Nuxt UI template boilerplate.
145-155: CTA section is well-aligned with sendook product.The call-to-action messaging ("give your AI agent email superpowers") and link targets (
/signup,/docs) are appropriate and consistent with the sendook brand voice. This successfully replaces the generic Nuxt UI SaaS messaging.
12-12: All internal routes are properly defined and will resolve.The verification confirms:
/docs/getting-startedresolves via content files (landing/content/1.docs/1.getting-started/1.index.md) routed through pages/docs/[...slug].vue/signupresolves to pages/signup.vue/docsresolves to pages/docs/[...slug].vueNo issues found.
1-1: No issues found. Code is correct as written.The markdown syntax
[AI Agents]{class="text-primary"}on line 1 is valid and properly supported. The page component uses the<MDC>component which renders markdown with attribute syntax, and all referenced routes (/signup,/docs,/docs/getting-started) exist in the codebase. Previous review feedback has been successfully addressed.
| to="https://github.com/getrupt/sendook" | ||
| target="_blank" |
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
Verify external link security.
The GitHub link opens in a new tab with target="_blank". Ensure that the UButton component from @nuxt/ui automatically adds rel="noopener noreferrer" to prevent potential security risks (tabnapping).
🏁 Script executed:
#!/bin/bash
# Description: Check if @nuxt/ui UButton handles rel attributes for external links.
# Search for UButton component implementation or documentation about external link handling
rg -n -C5 'target.*blank|rel.*noopener' --type=vue --type=ts --type=jsLength of output: 27
I'll fix the search approach and verify this concern through both codebase inspection and documentation review.
🏁 Script executed:
#!/bin/bash
# Find Vue files and search for UButton with target="_blank" or rel attributes
fd -e vue -type f --exec grep -l "UButton" {} \; | head -20Length of output: 170
🌐 Web query:
@nuxt/ui UButton target="_blank" rel noopener noreferrer security
💡 Result:
Yes — pass target plus rel to UButton (it forwards Link props). Always add rel="noopener noreferrer" when using target="_blank" to avoid tab‑nabbing and related risks.
Example:
Open
Why: Nuxt UI's UButton accepts link props like target/to. [1] And browsers can expose window.opener to the opened page (tab‑nabbing); adding noopener (and/or noreferrer) isolates the opener and prevents referrer leakage. [2][3]
Sources:
[1] Nuxt UI UButton docs.
[2] Chrome/Lighthouse guidance on rel="noopener".
[3] Static‑analysis / security guidance recommending rel="noopener noreferrer".
🏁 Script executed:
#!/bin/bash
# Inspect the AppHeader.vue file at lines 34-45 to see the exact UButton implementation
sed -n '34,45p' landing/app/components/AppHeader.vueLength of output: 260
Add rel="noopener noreferrer" to prevent tab-nabbing vulnerability.
The UButton component does not automatically add security attributes when using target="_blank". At line 39, add the rel attribute:
to="https://github.com/getrupt/sendook"
target="_blank"
rel="noopener noreferrer"
Without this, the opened page can access window.opener and potentially perform malicious actions in the original tab.
🤖 Prompt for AI Agents
In landing/app/components/AppHeader.vue around lines 38-39, the external link
opens with target="_blank" but lacks rel="noopener noreferrer"; update the
UButton (or anchor) element at these lines to include rel="noopener noreferrer"
alongside target="_blank" so the opened page cannot access window.opener and to
prevent tab-nabbing; ensure the attribute is added to the same element that sets
to="https://github.com/getrupt/sendook".
| <UButton | ||
| icon="i-lucide-log-in" | ||
| color="neutral" | ||
| variant="ghost" | ||
| to="/login" | ||
| class="lg:hidden" | ||
| /> |
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.
Add aria-label to icon-only button.
The mobile sign-in button displays only an icon without a text label, but lacks an aria-label attribute. This creates an accessibility barrier for screen reader users who won't know the button's purpose.
Apply this diff to add the missing aria-label:
<UButton
icon="i-lucide-log-in"
color="neutral"
variant="ghost"
to="/login"
class="lg:hidden"
+ aria-label="Sign in"
/>📝 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.
| <UButton | |
| icon="i-lucide-log-in" | |
| color="neutral" | |
| variant="ghost" | |
| to="/login" | |
| class="lg:hidden" | |
| /> | |
| <UButton | |
| icon="i-lucide-log-in" | |
| color="neutral" | |
| variant="ghost" | |
| to="/login" | |
| class="lg:hidden" | |
| aria-label="Sign in" | |
| /> |
🤖 Prompt for AI Agents
In landing/app/components/AppHeader.vue around lines 45 to 51, the icon-only
mobile sign-in UButton lacks an aria-label; add an aria-label attribute (e.g.,
aria-label="Sign in") to the UButton so screen readers can announce the button's
purpose, ensuring the label is concise and descriptive and placed alongside the
existing props.
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 (1)
landing/app/pages/pricing.vue (1)
2-12: Prefer typeduseAsyncDataoveras any.Casting the fetched content to
anydrops all compile-time guarantees and makes it easy to miss schema regressions.useAsyncDataalready exposes a generic—wire it up to the generated content types (e.g.,type PricingEntry = CollectionEntry<'pricing'>; const { data: page } = await useAsyncData<PricingEntry>(...)). You keep the same runtime behavior while regaining end-to-end type safety for the template and SEO metadata. (nuxt.com)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
landing/app/pages/pricing.vue(1 hunks)landing/content/2.pricing.yml(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- landing/content/2.pricing.yml
Summary by CodeRabbit
New Features
Documentation
Chores