diff --git a/app/monitor/page.tsx b/app/(admin)/monitor/page.tsx
similarity index 97%
rename from app/monitor/page.tsx
rename to app/(admin)/monitor/page.tsx
index 08edfcc..0082f3d 100644
--- a/app/monitor/page.tsx
+++ b/app/(admin)/monitor/page.tsx
@@ -1,11 +1,11 @@
-import WebVitalsDashboard from "../components/WebVitalsDashboard";
-import Header from "../components/Header";
-import Footer from "../components/Footer";
+import WebVitalsDashboard from "../../components/WebVitalsDashboard";
+import TopNav from "../../components/navigation/TopNav";
+import Footer from "../../components/navigation/Footer";
export default function MonitorPage() {
return (
-
+
diff --git a/app/components-preview/page.tsx b/app/(dev)/components-preview/page.tsx
similarity index 99%
rename from app/components-preview/page.tsx
rename to app/(dev)/components-preview/page.tsx
index 315a6f5..f653013 100644
--- a/app/components-preview/page.tsx
+++ b/app/(dev)/components-preview/page.tsx
@@ -1,11 +1,11 @@
"use client";
import { useState } from "react";
-import RuleCard from "../components/RuleCard";
-import Chip from "../components/Chip";
-import MultiSelect from "../components/MultiSelect";
+import RuleCard from "../components/cards/RuleCard";
+import Chip from "../components/controls/Chip";
+import MultiSelect from "../components/controls/MultiSelect";
import Image from "next/image";
-import { getAssetPath } from "../../lib/assetUtils";
+import { getAssetPath } from "../../../lib/assetUtils";
interface ChipData {
id: string;
diff --git a/app/blog/[slug]/page.tsx b/app/(marketing)/blog/[slug]/page.tsx
similarity index 96%
rename from app/blog/[slug]/page.tsx
rename to app/(marketing)/blog/[slug]/page.tsx
index 82d3263..bdd91e2 100644
--- a/app/blog/[slug]/page.tsx
+++ b/app/(marketing)/blog/[slug]/page.tsx
@@ -5,16 +5,16 @@ import {
getBlogPostBySlug,
getAllBlogPosts as getAllPosts,
type BlogPost,
-} from "../../../lib/content";
-import { logger } from "../../../lib/logger";
-import ContentBanner from "../../components/ContentBanner";
-import AskOrganizer from "../../components/AskOrganizer";
-import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
+} from "../../../../lib/content";
+import { logger } from "../../../../lib/logger";
+import ContentBanner from "../../../components/sections/ContentBanner";
+import AskOrganizer from "../../../components/sections/AskOrganizer";
+import { getAssetPath, ASSETS } from "../../../../lib/assetUtils";
import "../blog.css";
// Code split RelatedArticles - blog-specific, below the fold
const RelatedArticles = dynamic(
- () => import("../../components/RelatedArticles"),
+ () => import("../../../components/sections/RelatedArticles"),
{
loading: () => (
diff --git a/app/blog/blog.css b/app/(marketing)/blog/blog.css
similarity index 100%
rename from app/blog/blog.css
rename to app/(marketing)/blog/blog.css
diff --git a/app/blog/page.tsx b/app/(marketing)/blog/page.tsx
similarity index 92%
rename from app/blog/page.tsx
rename to app/(marketing)/blog/page.tsx
index 0cc02c4..62c0ad8 100644
--- a/app/blog/page.tsx
+++ b/app/(marketing)/blog/page.tsx
@@ -1,5 +1,5 @@
-import { getAllBlogPosts } from "../../lib/content";
-import ContentThumbnailTemplate from "../components/ContentThumbnailTemplate";
+import { getAllBlogPosts } from "../../../lib/content";
+import ContentThumbnailTemplate from "../../../components/content/ContentThumbnailTemplate";
import type { Metadata } from "next";
export const metadata: Metadata = {
diff --git a/app/learn/page.tsx b/app/(marketing)/learn/page.tsx
similarity index 87%
rename from app/learn/page.tsx
rename to app/(marketing)/learn/page.tsx
index 750d8a9..1644679 100644
--- a/app/learn/page.tsx
+++ b/app/(marketing)/learn/page.tsx
@@ -1,9 +1,9 @@
-import messages from "../../messages/en/index";
-import { getTranslation } from "../../lib/i18n/getTranslation";
-import ContentThumbnailTemplate from "../components/ContentThumbnailTemplate";
-import ContentLockup from "../components/ContentLockup";
-import AskOrganizer from "../components/AskOrganizer";
-import { getAllBlogPosts } from "../../lib/content";
+import messages from "../../../messages/en/index";
+import { getTranslation } from "../../../lib/i18n/getTranslation";
+import ContentThumbnailTemplate from "../../components/content/ContentThumbnailTemplate";
+import ContentLockup from "../../components/type/ContentLockup";
+import AskOrganizer from "../../components/sections/AskOrganizer";
+import { getAllBlogPosts } from "../../../lib/content";
export default function LearnPage() {
// Get real blog posts from the content system
diff --git a/app/page.tsx b/app/(marketing)/page.tsx
similarity index 78%
rename from app/page.tsx
rename to app/(marketing)/page.tsx
index b85e238..525b6ef 100644
--- a/app/page.tsx
+++ b/app/(marketing)/page.tsx
@@ -1,39 +1,39 @@
import dynamic from "next/dynamic";
-import messages from "../messages/en/index";
-import { getTranslation } from "../lib/i18n/getTranslation";
-import HeroBanner from "./components/HeroBanner";
-import AskOrganizer from "./components/AskOrganizer";
+import messages from "../../messages/en/index";
+import { getTranslation } from "../../lib/i18n/getTranslation";
+import HeroBanner from "../components/sections/HeroBanner";
+import AskOrganizer from "../components/sections/AskOrganizer";
// Code split below-the-fold components to reduce initial bundle size
-const LogoWall = dynamic(() => import("./components/LogoWall"), {
+const LogoWall = dynamic(() => import("../components/sections/LogoWall"), {
loading: () => (
),
ssr: true,
});
-const NumberedCards = dynamic(() => import("./components/NumberedCards"), {
+const NumberedCards = dynamic(() => import("../components/sections/NumberedCards"), {
loading: () => (
),
ssr: true,
});
-const RuleStack = dynamic(() => import("./components/RuleStack"), {
+const RuleStack = dynamic(() => import("../components/sections/RuleStack"), {
loading: () => (
),
ssr: true,
});
-const FeatureGrid = dynamic(() => import("./components/FeatureGrid"), {
+const FeatureGrid = dynamic(() => import("../components/sections/FeatureGrid"), {
loading: () => (
),
ssr: true,
});
-const QuoteBlock = dynamic(() => import("./components/QuoteBlock"), {
+const QuoteBlock = dynamic(() => import("../components/sections/QuoteBlock"), {
loading: () => (
),
diff --git a/app/components/ConditionalHeader/ConditionalHeader.container.tsx b/app/components/ConditionalHeader/ConditionalHeader.container.tsx
deleted file mode 100644
index 5f006f1..0000000
--- a/app/components/ConditionalHeader/ConditionalHeader.container.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-"use client";
-
-import { memo } from "react";
-import { usePathname } from "next/navigation";
-import { ConditionalHeaderView } from "./ConditionalHeader.view";
-import type { ConditionalHeaderProps } from "./ConditionalHeader.types";
-
-const ConditionalHeaderContainer = memo(() => {
- const pathname = usePathname();
- const isHomePage = pathname === "/";
-
- return ;
-});
-
-ConditionalHeaderContainer.displayName = "ConditionalHeader";
-
-export default ConditionalHeaderContainer;
diff --git a/app/components/ConditionalHeader/ConditionalHeader.types.ts b/app/components/ConditionalHeader/ConditionalHeader.types.ts
deleted file mode 100644
index 61af22a..0000000
--- a/app/components/ConditionalHeader/ConditionalHeader.types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export interface ConditionalHeaderProps {
- // Currently no props, but keeping interface for future extensibility
-}
-
-export interface ConditionalHeaderViewProps {
- isHomePage: boolean;
-}
diff --git a/app/components/ConditionalHeader/ConditionalHeader.view.tsx b/app/components/ConditionalHeader/ConditionalHeader.view.tsx
deleted file mode 100644
index ff36612..0000000
--- a/app/components/ConditionalHeader/ConditionalHeader.view.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import HomeHeader from "../HomeHeader";
-import Header from "../Header";
-import type { ConditionalHeaderViewProps } from "./ConditionalHeader.types";
-
-export function ConditionalHeaderView({
- isHomePage,
-}: ConditionalHeaderViewProps) {
- if (isHomePage) {
- return ;
- }
- return ;
-}
diff --git a/app/components/ConditionalHeader/index.tsx b/app/components/ConditionalHeader/index.tsx
deleted file mode 100644
index a05fd67..0000000
--- a/app/components/ConditionalHeader/index.tsx
+++ /dev/null
@@ -1,2 +0,0 @@
-export { default } from "./ConditionalHeader.container";
-export type { ConditionalHeaderProps } from "./ConditionalHeader.types";
diff --git a/app/components/ContextMenu.tsx b/app/components/ContextMenu/ContextMenu.tsx
similarity index 100%
rename from app/components/ContextMenu.tsx
rename to app/components/ContextMenu/ContextMenu.tsx
diff --git a/app/components/ContextMenuDivider.tsx b/app/components/ContextMenu/ContextMenuDivider.tsx
similarity index 100%
rename from app/components/ContextMenuDivider.tsx
rename to app/components/ContextMenu/ContextMenuDivider.tsx
diff --git a/app/components/ContextMenuItem/ContextMenuItem.container.tsx b/app/components/ContextMenu/ContextMenuItem/ContextMenuItem.container.tsx
similarity index 96%
rename from app/components/ContextMenuItem/ContextMenuItem.container.tsx
rename to app/components/ContextMenu/ContextMenuItem/ContextMenuItem.container.tsx
index 6b524dc..23beff6 100644
--- a/app/components/ContextMenuItem/ContextMenuItem.container.tsx
+++ b/app/components/ContextMenu/ContextMenuItem/ContextMenuItem.container.tsx
@@ -3,7 +3,7 @@
import { forwardRef, memo, useCallback } from "react";
import { ContextMenuItemView } from "./ContextMenuItem.view";
import type { ContextMenuItemProps } from "./ContextMenuItem.types";
-import { normalizeContextMenuItemSize } from "../../../lib/propNormalization";
+import { normalizeContextMenuItemSize } from "../../../../lib/propNormalization";
const ContextMenuItemContainer = forwardRef<
HTMLDivElement,
diff --git a/app/components/ContextMenuItem/ContextMenuItem.types.ts b/app/components/ContextMenu/ContextMenuItem/ContextMenuItem.types.ts
similarity index 100%
rename from app/components/ContextMenuItem/ContextMenuItem.types.ts
rename to app/components/ContextMenu/ContextMenuItem/ContextMenuItem.types.ts
diff --git a/app/components/ContextMenuItem/ContextMenuItem.view.tsx b/app/components/ContextMenu/ContextMenuItem/ContextMenuItem.view.tsx
similarity index 100%
rename from app/components/ContextMenuItem/ContextMenuItem.view.tsx
rename to app/components/ContextMenu/ContextMenuItem/ContextMenuItem.view.tsx
diff --git a/app/components/ContextMenuItem/index.tsx b/app/components/ContextMenu/ContextMenuItem/index.tsx
similarity index 100%
rename from app/components/ContextMenuItem/index.tsx
rename to app/components/ContextMenu/ContextMenuItem/index.tsx
diff --git a/app/components/ContextMenuSection.tsx b/app/components/ContextMenu/ContextMenuSection.tsx
similarity index 100%
rename from app/components/ContextMenuSection.tsx
rename to app/components/ContextMenu/ContextMenuSection.tsx
diff --git a/app/components/Header/Header.container.tsx b/app/components/Header/Header.container.tsx
deleted file mode 100644
index 52f6990..0000000
--- a/app/components/Header/Header.container.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-"use client";
-
-import { memo } from "react";
-import { usePathname } from "next/navigation";
-import { useTranslation } from "../../contexts/MessagesContext";
-import MenuBarItem from "../MenuBarItem";
-import Button from "../Button";
-import AvatarContainer from "../AvatarContainer";
-import Avatar from "../Avatar";
-import Logo from "../Logo";
-import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
-import { HeaderView } from "./Header.view";
-import type { HeaderProps, NavSize } from "./Header.types";
-
-export const avatarImages = [
- { src: getAssetPath(ASSETS.AVATAR_1), alt: "Avatar 1" },
- { src: getAssetPath(ASSETS.AVATAR_2), alt: "Avatar 2" },
- { src: getAssetPath(ASSETS.AVATAR_3), alt: "Avatar 3" },
-];
-
-export const logoConfig = [
- { breakpoint: "block sm:hidden", size: "header" as const, showText: false },
- {
- breakpoint: "hidden sm:block md:hidden",
- size: "header" as const,
- showText: true,
- },
- {
- breakpoint: "hidden md:block lg:hidden",
- size: "headerMd" as const,
- showText: true,
- },
- {
- breakpoint: "hidden lg:block xl:hidden",
- size: "headerLg" as const,
- showText: true,
- },
- { breakpoint: "hidden xl:block", size: "headerXl" as const, showText: true },
-];
-
-const HeaderContainer = memo(() => {
- const pathname = usePathname();
- const t = useTranslation("header");
-
- // Schema markup for site navigation
- const schemaData = {
- "@context": "https://schema.org",
- "@type": "WebSite",
- name: "CommunityRule",
- url: "https://communityrule.com",
- potentialAction: {
- "@type": "SearchAction",
- target: "https://communityrule.com/search?q={search_term_string}",
- "query-input": "required name=search_term_string",
- },
- };
-
- // Navigation items with translations
- const navigationItems = [
- { href: "#", text: t("navigation.useCases"), extraPadding: true },
- { href: "/learn", text: t("navigation.learn") },
- { href: "#", text: t("navigation.about") },
- ];
-
- const renderNavigationItems = (size: NavSize) => {
- return navigationItems.map((item, index) => (
-
- {item.text}
-
- ));
- };
-
- const renderAvatarGroup = (
- containerSize: "small" | "medium" | "large" | "xlarge",
- avatarSize: "small" | "medium" | "large" | "xlarge",
- ) => {
- return (
-
- {avatarImages.map((avatar, index) => (
-
- ))}
-
- );
- };
-
- const renderLoginButton = (size: NavSize) => {
- return (
-
- {t("buttons.logIn")}
-
- );
- };
-
- const renderCreateRuleButton = (
- buttonSize: "xsmall" | "small" | "medium" | "large" | "xlarge",
- containerSize: "small" | "medium" | "large" | "xlarge",
- avatarSize: "small" | "medium" | "large" | "xlarge",
- ) => {
- return (
-
- );
- };
-
- const renderLogo = (
- size:
- | "default"
- | "homeHeaderXsmall"
- | "homeHeaderSm"
- | "homeHeaderMd"
- | "homeHeaderLg"
- | "homeHeaderXl"
- | "header"
- | "headerMd"
- | "headerLg"
- | "headerXl"
- | "footer"
- | "footerLg",
- showText: boolean,
- ) => {
- return ;
- };
-
- return (
-
- );
-});
-
-HeaderContainer.displayName = "Header";
-
-export default HeaderContainer;
diff --git a/app/components/Header/Header.view.tsx b/app/components/Header/Header.view.tsx
deleted file mode 100644
index 780c7b2..0000000
--- a/app/components/Header/Header.view.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-"use client";
-
-import { useTranslation } from "../../contexts/MessagesContext";
-import MenuBar from "../MenuBar";
-import type { HeaderViewProps } from "./Header.types";
-
-export function HeaderView({
- schemaData,
- logoConfig,
- renderNavigationItems,
- renderLoginButton,
- renderCreateRuleButton,
- renderLogo,
-}: HeaderViewProps) {
- const t = useTranslation("header");
-
- return (
- <>
-
-
-
-
- >
- );
-}
diff --git a/app/components/Header/index.tsx b/app/components/Header/index.tsx
deleted file mode 100644
index 71dbfdb..0000000
--- a/app/components/Header/index.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export { default } from "./Header.container";
-export type { HeaderProps } from "./Header.types";
-export { avatarImages, logoConfig } from "./Header.container";
diff --git a/app/components/HeaderTab.tsx b/app/components/HeaderTab.tsx
deleted file mode 100644
index 8afe968..0000000
--- a/app/components/HeaderTab.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { memo } from "react";
-import { getAssetPath } from "../../lib/assetUtils";
-
-interface HeaderTabProps extends React.HTMLAttributes {
- children?: React.ReactNode;
- className?: string;
- stretch?: boolean;
-}
-
-const HeaderTab = memo(
- ({ children, className = "", stretch = false, ...props }) => {
- const stretchClasses = stretch
- ? "flex-1 sm:mr-[var(--spacing-scale-008)] md:mr-[185px] lg:mr-[var(--spacing-scale-024)] xl:mr-[var(--spacing-scale-032)]"
- : "";
-
- return (
-