diff --git a/apps/logicsrc-web/src/app/blog/[slug]/page.tsx b/apps/logicsrc-web/src/app/blog/[slug]/page.tsx index 52656ed..76cdc83 100644 --- a/apps/logicsrc-web/src/app/blog/[slug]/page.tsx +++ b/apps/logicsrc-web/src/app/blog/[slug]/page.tsx @@ -3,6 +3,7 @@ import { notFound } from "next/navigation"; import type { ReactNode } from "react"; import type { Metadata } from "next"; import { publicClient } from "@/lib/supabase"; +import { SiteShell } from "@/components/site-shell"; export const dynamic = "force-dynamic"; @@ -65,17 +66,15 @@ export default async function BlogPostPage({ if (!post) notFound(); return ( -
-

- - ← Blog - -

-
-

- {post.title} -

-
+ +
+

+ + ← Blog + +

+

{post.title}

+
{formatDate(post.published_at)}
{post.featured_image?.url ? ( @@ -83,14 +82,15 @@ export default async function BlogPostPage({ {post.title} ) : null}
-
+ ); } diff --git a/apps/logicsrc-web/src/app/blog/page.tsx b/apps/logicsrc-web/src/app/blog/page.tsx index c110816..67a1051 100644 --- a/apps/logicsrc-web/src/app/blog/page.tsx +++ b/apps/logicsrc-web/src/app/blog/page.tsx @@ -2,6 +2,7 @@ import Link from "next/link"; import type { ReactNode } from "react"; import type { Metadata } from "next"; import { publicClient } from "@/lib/supabase"; +import { SiteShell } from "@/components/site-shell"; export const dynamic = "force-dynamic"; @@ -37,48 +38,50 @@ export default async function BlogIndex(): Promise { const posts = (data ?? []) as PostRow[]; return ( -
-

- - ← LogicSRC - -

-

Blog

-

- Project notes for LogicSRC OpenSpec standards, AgentSwarm, AgentByte, - SDKs, MCP, and reference implementations.{" "} - - RSS - -

+ +
+
+

Blog

+

+ Project notes for LogicSRC OpenSpec standards, AgentSwarm, AgentByte, + SDKs, MCP, and reference implementations.{" "} + RSS +

+
- {posts.length === 0 ? ( -

No posts yet.

- ) : ( -
    - {posts.map((post) => ( -
  • - No posts yet.

    + ) : ( +
      + {posts.map((post) => ( +
    • -

      - {post.title} -

      - -
      - {formatDate(post.published_at)} -
      - {post.excerpt ? ( -

      {post.excerpt}

      - ) : null} -
    • - ))} -
    - )} -
+ +

+ {post.title} +

+ +
+ {formatDate(post.published_at)} +
+ {post.excerpt ? ( +

{post.excerpt}

+ ) : null} + + ))} + + )} + + ); } diff --git a/apps/logicsrc-web/src/components/site-shell.tsx b/apps/logicsrc-web/src/components/site-shell.tsx new file mode 100644 index 0000000..271e5b2 --- /dev/null +++ b/apps/logicsrc-web/src/components/site-shell.tsx @@ -0,0 +1,79 @@ +import type { ReactNode } from "react"; + +// Mirrors the rail/nav from page-markup.ts so standalone routes (e.g. /blog) +// share the site chrome. Anchor links point at the homepage sections. +const NAV: Array<{ href: string; label: string }> = [ + { href: "/#overview", label: "Overview" }, + { href: "/#schemas", label: "Schemas" }, + { href: "/agent-swarm", label: "Soon" }, + { href: "/agentbyte", label: "AgentByte" }, + { href: "/credential-sharing", label: "Credentials" }, + { href: "/#cli", label: "CLI" }, + { href: "/docs", label: "Docs" }, + { href: "/blog", label: "Blog" }, + { href: "/openspec", label: "OpenSpec" }, + { href: "/hire-us", label: "Hire Us" }, + { href: "/about", label: "About" }, + { href: "/terms", label: "Terms" }, + { href: "/privacy", label: "Privacy" }, + { href: "/#reference", label: "Reference" }, +]; + +export function SiteShell({ + children, + active, +}: { + children: ReactNode; + active?: string; +}): ReactNode { + return ( +
+ +
+ {children} + +
+
+ ); +} diff --git a/apps/logicsrc-web/src/styles.css b/apps/logicsrc-web/src/styles.css index 1610c83..f35ca96 100644 --- a/apps/logicsrc-web/src/styles.css +++ b/apps/logicsrc-web/src/styles.css @@ -15,10 +15,14 @@ body { } a { - color: inherit; + color: #5ac8a6; text-decoration: none; } +a:hover { + text-decoration: underline; +} + button { border: 0; font: inherit; @@ -75,6 +79,7 @@ nav { } nav a { + color: inherit; min-height: 2.35rem; padding: 0.55rem 0.75rem; border: 1px solid #263039; @@ -85,6 +90,7 @@ nav a.active, nav a:hover { border-color: #3f5049; background: #1b2329; + text-decoration: none; } .workspace { @@ -696,3 +702,49 @@ pre { font-size: 2.4rem; } } + +/* Rendered blog post HTML (autoblog payload) on the dark workspace. */ +.blog-content { + color: #e7ebe4; +} +.blog-content a { + color: #5ac8a6; +} +.blog-content h2, +.blog-content h3, +.blog-content h4 { + margin: 1.75rem 0 0.5rem; + line-height: 1.25; +} +.blog-content p, +.blog-content ul, +.blog-content ol, +.blog-content blockquote { + margin: 0 0 1rem; +} +.blog-content img { + max-width: 100%; + height: auto; + border-radius: 0.5rem; +} +.blog-content pre { + background: rgba(0, 0, 0, 0.32); + padding: 1rem; + border-radius: 0.5rem; + overflow: auto; +} +.blog-content code { + background: rgba(0, 0, 0, 0.32); + padding: 0.1rem 0.35rem; + border-radius: 0.25rem; + font-size: 0.9em; +} +.blog-content pre code { + background: none; + padding: 0; +} +.blog-content blockquote { + border-left: 3px solid rgba(245, 247, 244, 0.2); + padding-left: 1rem; + color: #b5beb2; +}