Skip to content

refactor: reorganize components folder structure#1

Merged
suradet-ps merged 2 commits intomainfrom
refactor/organize-components
Dec 7, 2025
Merged

refactor: reorganize components folder structure#1
suradet-ps merged 2 commits intomainfrom
refactor/organize-components

Conversation

@suradet-ps
Copy link
Copy Markdown
Owner

@suradet-ps suradet-ps commented Dec 7, 2025

refactor Folder Structure in component and fix import paths and type definitions

Summary by Sourcery

Restructure the components folder into domain-specific subfolders and update the project to use path aliases and auto-imported Astro components.

New Features:

  • Introduce an Image content component with caption support and styled presentation.
  • Enable auto-import of frequently used blog, content, layout, tools, and UI components via astro-auto-import.

Enhancements:

  • Adopt '@/...' TypeScript path aliases across layouts, pages, components, utilities, and API routes.
  • Organize existing components into blog, content, layout, tools, and UI subdirectories for clearer structure.
  • Inline the view counter script for better bundling behavior and remove redundant file header comments for cleaner code.

Build:

  • Configure Astro integrations to include astro-auto-import and register commonly used components.
  • Update TypeScript configuration with custom baseUrl, path aliases, and JSX settings.
  • Add @astrojs/check and typescript runtime dependencies to support stricter type checking.

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 7, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
rxdevnotes Ready Ready Preview Comment Dec 7, 2025 8:51am

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Dec 7, 2025

Reviewer's Guide

Refactors the Astro project’s components into a domain‑oriented folder structure, introduces path aliases and auto-imported UI/content components, and updates all imports, configs, and a few component implementations to match.

Class diagram for reorganized Astro components and new Image component

classDiagram

  class BaseLayout_astro {
    +string title
    +string description
    +string? ogImage
  }

  class BlogPostLayout_astro {
    +CollectionEntry blogPost
    +MarkdownHeading[] headings
  }

  class Navbar_astro {
  }

  class ProgressBar_astro {
  }

  class BlogPostCard_astro {
    +CollectionEntry post
  }

  class CategoryCard_astro {
    +string category
  }

  class Toc_astro {
    +MarkdownHeading[] headings
  }

  class ViewCounter_astro {
    +string slug
    +updateViewCount() async
  }

  class ToolCard_astro {
    +string title
    +string description
    +string href
    +string icon
  }

  class FeatureCard_astro {
    +string title
    +string description
    +string icon
  }

  class FeatureGrid_astro {
  }

  class Search_astro {
    +string placeholder
  }

  class InfoBox_astro {
    +string title
    +string type
  }

  class CodeExplainer_astro {
    +string title
    +string language
  }

  class GitCommand_astro {
    +string command
    +string description
  }

  class ProsCons_astro {
  }

  class Table_astro {
  }

  class Image_astro {
    +string src
    +string alt
    +string? caption
    +number? width
    +number? height
    +HTMLAttributes figureAttributes
  }

  class Slugify_ts {
    +slugify(text string) string
  }

  %% Layout composition
  BaseLayout_astro --> Navbar_astro : uses
  BaseLayout_astro --> ProgressBar_astro : uses

  BlogPostLayout_astro --> BaseLayout_astro : wraps
  BlogPostLayout_astro --> Toc_astro : uses
  BlogPostLayout_astro --> ViewCounter_astro : uses
  BlogPostLayout_astro --> Slugify_ts : uses

  %% Blog listing and category pages
  BlogPostCard_astro --> Slugify_ts : uses

  %% Content components used inside MDX
  InfoBox_astro --> CodeExplainer_astro : may_coexist
  ProsCons_astro --> InfoBox_astro : may_coexist

  %% New Image component attributes relationship
  Image_astro --> InfoBox_astro : often_coexists_in_content
Loading

File-Level Changes

Change Details Files
Introduce component auto-imports and configure Astro/TypeScript for alias-based imports.
  • Add astro-auto-import integration in astro.config.mjs and register frequently used blog, content, layout, tools, and ui components for automatic import.
  • Update integrations array ordering to include the new autoImport integration alongside mdx, icon, sitemap, and pagefind.
  • Extend tsconfig.json with baseUrl, paths alias '@/' -> 'src/', and JSX settings for Astro components.
  • Add new runtime dependencies @astrojs/check, astro-auto-import, and typescript in package.json.
astro.config.mjs
tsconfig.json
package.json
package-lock.json
Reorganize components into domain-based subfolders and update references to use the new structure and path aliases.
  • Move generic components into namespaced folders: blog (BlogPostCard, CategoryCard, Toc, ViewCounter), content (CodeExplainer, GitCommand, Image, InfoBox, ProsCons, Table), layout (Navbar), tools (ToolCard), and ui (FeatureCard, FeatureGrid, ProgressBar, Search).
  • Adjust intra-component imports (e.g., slugify, supabase) to use the '@/' alias instead of relative paths.
  • Update pages, layouts, and API routes to import components and utilities from the new locations using '@' aliases (e.g., BaseLayout, BlogPostLayout, BlogPostCard, Navbar, ProgressBar, ToolCard, FeatureCard, FeatureGrid, supabase, slugify).
  • Remove now-redundant inline file path comments from component, layout, content, and style files.
src/components/BlogPostCard.astro
src/components/CategoryCard.astro
src/components/Toc.astro
src/components/ViewCounter.astro
src/components/CodeExplainer.astro
src/components/GitCommand.astro
src/components/InfoBox.astro
src/components/ProsCons.astro
src/components/Table.astro
src/components/Navbar.astro
src/components/tools/ToolCard.astro
src/components/FeatureCard.astro
src/components/FeatureGrid.astro
src/components/ProgressBar.astro
src/components/Search.astro
src/components/content/Image.astro
src/pages/blog/index.astro
src/pages/blog/[...slug].astro
src/pages/blog/categories/[category].astro
src/pages/blog/tags/[tag].astro
src/pages/tools/index.astro
src/pages/tools/cupsabot.astro
src/pages/tools/herbs-app.astro
src/pages/about.astro
src/pages/hosxp.astro
src/pages/index.astro
src/pages/api/views/[slug].ts
src/layouts/BaseLayout.astro
src/layouts/BlogPostLayout.astro
src/utils/slugify.ts
src/styles/global.css
Simplify MDX content files by relying on auto-imported components and clean up trailing noise.
  • Remove explicit component imports from blog MDX files (InfoBox, FeatureGrid, FeatureCard, CodeExplainer, ProsCons, Image, GitCommand, Table), so they are resolved via auto-import instead.
  • Trim trailing blank lines and fix missing final newlines in a few MDX articles to keep content tidy.
src/content/blog/git-commit-messages.mdx
src/content/blog/google-app-script.mdx
src/content/blog/frontend-developer-roadmap-part-2.mdx
src/content/blog/rust-variables-and-mutability.mdx
src/content/blog/google-app-script-drug-search-app.mdx
src/content/blog/learn-python-with-ritesh-chauhan.mdx
src/content/blog/web-accessibility-101.mdx
src/content/blog/awesome-warfarin-open-source.mdx
src/content/blog/benefits-of-touch-typing.mdx
src/content/blog/essential-git-commands-guide.mdx
src/content/blog/haskell-ep1.mdx
src/content/blog/frontend-developer-roadmap-part-1.mdx
src/content/blog/haskell-ep2.mdx
src/content/config.ts
Replace the old Image component with a typed, styled content Image component.
  • Remove the legacy src/components/Image.astro file.
  • Add a new src/components/content/Image.astro component that supports HTMLAttributes<'figure'>, optional caption/width/height, and includes figure/img/figcaption styling for consistent presentation.
src/components/Image.astro
src/components/content/Image.astro
Minor behavioral tweak to the view counter script.
  • Mark the ViewCounter component’s script tag as inline (is:inline) while preserving its fetch/update logic, ensuring the script is embedded directly for the provided slug.
src/components/blog/ViewCounter.astro

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • The new ViewCounter still uses a hard-coded id="view-count-value", which will be duplicated if multiple counters render on the same page; consider scoping the element lookup (e.g. via a ref, data- attribute, or this container) instead of a global ID.
  • The Image component currently forwards extra props only to the <figure>; if you expect callers to pass image-specific attributes (e.g. loading, sizes, srcset, aria-* for the <img>), you may want to split and forward relevant attributes to the <img> element as well for better flexibility.
  • With the introduction of the @/* path alias and astro-auto-import configuration, it may be worth checking that your non-Astro tooling (ESLint, IDE TypeScript config, tests) are aligned with these aliases and auto-imported components to avoid mismatches between build-time and editor behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `ViewCounter` still uses a hard-coded `id="view-count-value"`, which will be duplicated if multiple counters render on the same page; consider scoping the element lookup (e.g. via a `ref`, `data-` attribute, or `this` container) instead of a global ID.
- The `Image` component currently forwards extra props only to the `<figure>`; if you expect callers to pass image-specific attributes (e.g. `loading`, `sizes`, `srcset`, `aria-*` for the `<img>`), you may want to split and forward relevant attributes to the `<img>` element as well for better flexibility.
- With the introduction of the `@/*` path alias and `astro-auto-import` configuration, it may be worth checking that your non-Astro tooling (ESLint, IDE TypeScript config, tests) are aligned with these aliases and auto-imported components to avoid mismatches between build-time and editor behavior.

## Individual Comments

### Comment 1
<location> `src/components/content/Image.astro:23-32` </location>
<code_context>
+} = Astro.props;
+---
+
+<figure class:list={['image-wrapper', className]} {...attrs}>
+  <img
+    src={src}
+    alt={alt}
+    width={width}
+    height={height}
+    loading="lazy"
+    decoding="async"
+  />
+  {caption && <figcaption>{caption}</figcaption>}
+</figure>
+
</code_context>

<issue_to_address>
**suggestion:** Image-specific attributes like `loading`/`decoding` can’t currently be overridden per-usage.

`loading="lazy"` and `decoding="async"` are hardcoded on `<img>`, and the rest of the passed HTML attributes are applied to `<figure>`, so callers can’t override these or pass `sizes`, `srcset`, or `fetchpriority` to the image. Consider adding an `imgProps` bag, or separating known figure props from image-level props and spreading the latter on `<img>` to allow overrides while keeping the current defaults.

Suggested implementation:

```
  class: className,
  imgProps = {},
  ...figureAttrs
} = Astro.props;
---



```

```
<figure class:list={['image-wrapper', className]} {...figureAttrs}>
  <img
    src={src}
    alt={alt}
    width={width}
    height={height}
    {...imgProps}
    loading={imgProps?.loading ?? 'lazy'}
    decoding={imgProps?.decoding ?? 'async'}
  />
  {caption && <figcaption>{caption}</figcaption>}
</figure>

```

```
import type { HTMLAttributes } from 'astro/types';

type Props = {
  src: string;
  alt: string;
  caption?: string;
  width?: number;
  height?: number;
  imgProps?: HTMLAttributes<'img'>;
} & HTMLAttributes<'figure'>;

```
</issue_to_address>

### Comment 2
<location> `src/components/blog/ViewCounter.astro:10-13` </location>
<code_context>
   <span id="view-count-value">...</span> views
 </span>

-<script define:vars={{ slug }}>
+<script is:inline define:vars={{ slug }}>
   const viewCountElement = document.getElementById('view-count-value');

</code_context>

<issue_to_address>
**issue:** Using a fixed `id` in a reusable component can break when multiple instances are rendered.

Here `id="view-count-value"` is shared across all instances, and `document.getElementById` will only ever return the first one. If `ViewCounter` appears multiple times on a page, the others won’t update. Use a per-instance selector instead (e.g. a unique ID derived from `slug`, a `data-*` attribute, or querying relative to a container) so multiple counters work correctly.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +23 to +32
<figure class:list={['image-wrapper', className]} {...attrs}>
<img
src={src}
alt={alt}
width={width}
height={height}
loading="lazy"
decoding="async"
/>
{caption && <figcaption>{caption}</figcaption>}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: Image-specific attributes like loading/decoding can’t currently be overridden per-usage.

loading="lazy" and decoding="async" are hardcoded on <img>, and the rest of the passed HTML attributes are applied to <figure>, so callers can’t override these or pass sizes, srcset, or fetchpriority to the image. Consider adding an imgProps bag, or separating known figure props from image-level props and spreading the latter on <img> to allow overrides while keeping the current defaults.

Suggested implementation:

  class: className,
  imgProps = {},
  ...figureAttrs
} = Astro.props;
---



<figure class:list={['image-wrapper', className]} {...figureAttrs}>
  <img
    src={src}
    alt={alt}
    width={width}
    height={height}
    {...imgProps}
    loading={imgProps?.loading ?? 'lazy'}
    decoding={imgProps?.decoding ?? 'async'}
  />
  {caption && <figcaption>{caption}</figcaption>}
</figure>

import type { HTMLAttributes } from 'astro/types';

type Props = {
  src: string;
  alt: string;
  caption?: string;
  width?: number;
  height?: number;
  imgProps?: HTMLAttributes<'img'>;
} & HTMLAttributes<'figure'>;

Comment on lines 10 to +13
<span id="view-count-value">...</span> views
</span>

<script define:vars={{ slug }}>
<script is:inline define:vars={{ slug }}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue: Using a fixed id in a reusable component can break when multiple instances are rendered.

Here id="view-count-value" is shared across all instances, and document.getElementById will only ever return the first one. If ViewCounter appears multiple times on a page, the others won’t update. Use a per-instance selector instead (e.g. a unique ID derived from slug, a data-* attribute, or querying relative to a container) so multiple counters work correctly.

@suradet-ps suradet-ps merged commit 1e91aa0 into main Dec 7, 2025
5 checks passed
@suradet-ps suradet-ps deleted the refactor/organize-components branch December 7, 2025 08:55
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 1.0.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant