feat: Migrate www to the ui components
This commit is contained in:
19 files changed
+426
-142
No files matched your search
@@ -5,10 +5,6 @@ createdDate: 2026-01-31
|
||||
tags: ['test', 'general']
|
||||
---
|
||||
|
||||
# Hello World
|
||||
|
||||
This is a test article.
|
||||
|
||||
## Section 1
|
||||
|
||||
Some content here.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Header, Paragraph, List, Blockquote, Code, CodeBlock, Container, Text } from '@ermnvldmr/ui';
|
||||
|
||||
import { ArticleLayout } from './ArticleLayout';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
@@ -21,34 +23,36 @@ const meta: Meta<typeof ArticleLayout> = {
|
||||
export default meta;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
type Story = StoryObj<typeof ArticleLayout>;
|
||||
|
||||
/**
|
||||
* Default story showcasing various HTML elements to verify typography.
|
||||
* Default story showcasing various UI components to verify typography in layout.
|
||||
*/
|
||||
export const Default: Story = {
|
||||
render: (args) => (
|
||||
<ArticleLayout {...args}>
|
||||
<h2>Introduction</h2>
|
||||
<p>
|
||||
<Header level={2}>Introduction</Header>
|
||||
<Paragraph>
|
||||
Astro 5 introduces the Content Layer API, a powerful way to fetch content from any source,
|
||||
including local files, remote APIs, and CMSs. In this article, we'll explore how to set
|
||||
up a robust system for articles and projects.
|
||||
</p>
|
||||
</Paragraph>
|
||||
|
||||
<blockquote>
|
||||
"The best way to manage content is to not manage it at all." — Someone, probably.
|
||||
</blockquote>
|
||||
<Blockquote>
|
||||
The best way to manage content is to not manage it at all.
|
||||
<Blockquote.Citation>Someone, probably</Blockquote.Citation>
|
||||
</Blockquote>
|
||||
|
||||
<p>
|
||||
Let's look at some code. Our new <code>content.config.ts</code> uses the{' '}
|
||||
<code>glob</code> loader to pull in MDX files from outside the <code>src</code> directory:
|
||||
</p>
|
||||
<Paragraph>
|
||||
Let's look at some code. Our new <Code>content.config.ts</Code> uses the{' '}
|
||||
<Code>glob</Code> loader to pull in MDX files from outside the <Code>src</Code> directory:
|
||||
</Paragraph>
|
||||
|
||||
<pre>
|
||||
<code>{`// services/www/src/content.config.ts
|
||||
<CodeBlock label="content.config.ts">
|
||||
<Code>
|
||||
{`// services/www/src/content.config.ts
|
||||
import { defineCollection, z } from 'astro:content';
|
||||
import { glob } from 'astro/loaders';
|
||||
|
||||
@@ -63,37 +67,39 @@ const articles = defineCollection({
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = { articles };`}</code>
|
||||
</pre>
|
||||
export const collections = { articles };`}
|
||||
</Code>
|
||||
</CodeBlock>
|
||||
|
||||
<h3>Why Astro 5?</h3>
|
||||
<p>
|
||||
<Header level={3}>Why Astro 5?</Header>
|
||||
<Paragraph>
|
||||
Astro's zero-JS by default approach is perfect for content-heavy sites. By moving our
|
||||
content outside of the <code>src</code> directory, we keep our project clean and organized.
|
||||
</p>
|
||||
content outside of the <Code>src</Code> directory, we keep our project clean and organized.
|
||||
</Paragraph>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Better performance:</strong> Only what you need is shipped.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Improved developer experience:</strong> Fast HMR and great tooling.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Type safety:</strong> Zod schemas validate your frontmatter.
|
||||
</li>
|
||||
</ul>
|
||||
<List spacing="s" variant="unordered">
|
||||
<List.Item>
|
||||
<Text bold>Better performance:</Text> Only what you need is shipped.
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Text bold>Improved developer experience:</Text> Fast HMR and great tooling.
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Text bold>Type safety:</Text> Zod schemas validate your frontmatter.
|
||||
</List.Item>
|
||||
</List>
|
||||
|
||||
<h3>Visual Media</h3>
|
||||
<p>
|
||||
<Header level={3}>Visual Media</Header>
|
||||
<Paragraph>
|
||||
We can also include images and videos. The layout ensures they are responsive and fit the
|
||||
grid.
|
||||
</p>
|
||||
<div className="bg-muted flex aspect-video items-center justify-center rounded-lg border-2 border-dashed">
|
||||
<span className="text-muted-foreground">Placeholder for Image/Video</span>
|
||||
</div>
|
||||
</Paragraph>
|
||||
<Container border bg="muted" className="flex aspect-video items-center justify-center" rounded="lg">
|
||||
<Text color="muted">Placeholder for Image/Video</Text>
|
||||
</Container>
|
||||
|
||||
<p>Conclusion: It's a great time to be a web developer.</p>
|
||||
<Paragraph>Conclusion: It's a great time to be a web developer.</Paragraph>
|
||||
</ArticleLayout>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { cn } from '@ermnvldmr/stl';
|
||||
import { VStack, HStack, Markdown } from '@ermnvldmr/ui';
|
||||
import { VStack, HStack, Markdown, Container, Time, Header, Paragraph, Text } from '@ermnvldmr/ui';
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
@@ -56,51 +56,49 @@ export const ArticleLayout: React.FC<ArticleLayoutProps> = ({
|
||||
children,
|
||||
className,
|
||||
}) => {
|
||||
const formattedDate = createdDate.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
});
|
||||
|
||||
const displayDate = updatedDate
|
||||
? `Updated ${updatedDate.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})}`
|
||||
: formattedDate;
|
||||
const displayDate = updatedDate ? (
|
||||
<Text color="muted" size="s" type="label">
|
||||
Updated <Time date={updatedDate} />
|
||||
</Text>
|
||||
) : (
|
||||
<Time color="muted" date={createdDate} size="s" type="label" />
|
||||
);
|
||||
|
||||
return (
|
||||
<article className={cn('mx-auto max-w-3xl px-6 py-12 md:py-20', className)}>
|
||||
<header className="pb-12">
|
||||
<VStack gap={4}>
|
||||
<HStack className="text-muted-foreground text-sm font-medium" gap={4}>
|
||||
<time dateTime={createdDate.toISOString()}>{displayDate}</time>
|
||||
{tags && tags.length > 0 && (
|
||||
<HStack className="flex-wrap" gap={2}>
|
||||
{tags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="before:text-muted-foreground/50 before:mr-0.5 before:content-['#']"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
<h1 className="leading-tight">{title}</h1>
|
||||
|
||||
{description && (
|
||||
<p className="text-muted-foreground text-l leading-relaxed italic">{description}</p>
|
||||
<Container as="article" className={cn('mx-auto max-w-3xl px-6 py-12 md:py-20', className)}>
|
||||
<VStack as="header" className="pb-12" gap={4}>
|
||||
<HStack align="center" className="flex-wrap" gap={4}>
|
||||
{displayDate}
|
||||
{tags && tags.length > 0 && (
|
||||
<HStack className="flex-wrap" gap={2}>
|
||||
{tags.map((tag) => (
|
||||
<Text
|
||||
key={tag}
|
||||
className="before:text-muted-foreground/50 before:mr-0.5 before:content-['#']"
|
||||
color="muted"
|
||||
size="s"
|
||||
>
|
||||
{tag}
|
||||
</Text>
|
||||
))}
|
||||
</HStack>
|
||||
)}
|
||||
</VStack>
|
||||
</header>
|
||||
</HStack>
|
||||
|
||||
<section className="article-content">
|
||||
<Header className="leading-tight" level={1}>
|
||||
{title}
|
||||
</Header>
|
||||
|
||||
{description && (
|
||||
<Paragraph italic className="leading-relaxed" color="muted" size="l">
|
||||
{description}
|
||||
</Paragraph>
|
||||
)}
|
||||
</VStack>
|
||||
|
||||
<Container as="section" className="article-content">
|
||||
<Markdown>{children}</Markdown>
|
||||
</section>
|
||||
</article>
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
import { Container, Header, Paragraph, Link, VStack, List, Time, Text } from '@ermnvldmr/ui';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
import IndexLayout from '#layouts/IndexLayout/IndexLayout.astro';
|
||||
@@ -11,43 +12,45 @@ const articles = (await getCollection('articles')).sort(
|
||||
---
|
||||
|
||||
<IndexLayout title={`Articles | ${SITE_TITLE}`} description="Browse all articles and projects.">
|
||||
<main class="mx-auto max-w-3xl px-6 py-20">
|
||||
<h1 class="mb-12">Articles</h1>
|
||||
<ul class="space-y-12">
|
||||
<Container as="main" className="mx-auto max-w-3xl px-6 py-20">
|
||||
<Header level={1} className="mb-12">Articles</Header>
|
||||
<List variant="plain" spacing="l">
|
||||
{
|
||||
articles.map((article) => (
|
||||
<li>
|
||||
<a href={`/articles/${article.id}`} class="group block no-underline">
|
||||
<article class="space-y-3">
|
||||
<time class="text-muted-foreground text-sm font-medium">
|
||||
{article.data.createdDate.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})}
|
||||
</time>
|
||||
<h2 class="group-hover:text-primary mt-0 border-none pb-0 text-3xl transition-colors">
|
||||
<List.Item>
|
||||
<Link href={`/articles/${article.id}`} className="group block no-underline!">
|
||||
<VStack gap={3} as="article">
|
||||
<Time
|
||||
date={article.data.createdDate}
|
||||
color="muted"
|
||||
size="s"
|
||||
type="label"
|
||||
/>
|
||||
<Header
|
||||
level={2}
|
||||
className="group-hover:text-primary mt-0 border-none pb-0 text-3xl transition-colors"
|
||||
>
|
||||
{article.data.title}
|
||||
</h2>
|
||||
</Header>
|
||||
{article.data.description && (
|
||||
<p class="text-muted-foreground line-clamp-3 text-lg leading-relaxed">
|
||||
<Paragraph color="muted" size="l" maxLines={3}>
|
||||
{article.data.description}
|
||||
</p>
|
||||
</Paragraph>
|
||||
)}
|
||||
{article.data.tags && (
|
||||
<div class="flex gap-2">
|
||||
{article.data.tags.map((tag) => (
|
||||
<span class="text-muted-foreground text-xs before:content-['#']">
|
||||
<Text color="muted" size="s" className="before:content-['#']">
|
||||
{tag}
|
||||
</span>
|
||||
</Text>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</article>
|
||||
</a>
|
||||
</li>
|
||||
</VStack>
|
||||
</Link>
|
||||
</List.Item>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</main>
|
||||
</List>
|
||||
</Container>
|
||||
</IndexLayout>
|
||||
@@ -1,30 +1,32 @@
|
||||
---
|
||||
import { Container, Header, Paragraph, Link, VStack } from '@ermnvldmr/ui';
|
||||
|
||||
import IndexLayout from '#layouts/IndexLayout/IndexLayout.astro';
|
||||
import { SITE_TITLE, SITE_DESCRIPTION } from '#shared/constants';
|
||||
import '#global.css';
|
||||
---
|
||||
|
||||
<IndexLayout title={SITE_TITLE} description={SITE_DESCRIPTION}>
|
||||
<main class="flex h-full w-full justify-center p-4">
|
||||
<div>
|
||||
<h2>Welcome to my page!</h2>
|
||||
<p>
|
||||
<Container as="main" className="flex h-full w-full justify-center p-4">
|
||||
<VStack gap={4}>
|
||||
<Header level={2}>Welcome to my page!</Header>
|
||||
<Paragraph>
|
||||
If you see this page, my website is successfuly installed and working.
|
||||
<br />
|
||||
It will be further configured.
|
||||
</p>
|
||||
<p>
|
||||
For the source code and support please refer to <a href="https://github.com/deytenit/ermnvldmr.com/"
|
||||
>ermnvldmr.com monorepo</a
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
For the source code and support please refer to <Link href="https://github.com/deytenit/ermnvldmr.com/"
|
||||
>ermnvldmr.com monorepo</Link
|
||||
>.
|
||||
<br />
|
||||
Pictures of mine are available at <a href="https://ermnvldmr.com/instagram">@deytenit</a
|
||||
Pictures of mine are available at <Link href="https://ermnvldmr.com/instagram">@deytenit</Link
|
||||
>.
|
||||
</p>
|
||||
<p>
|
||||
Check out my <a href="/articles">thoughts and articles on various matters</a>.
|
||||
</p>
|
||||
<p><em>Thank you for visiting!</em></p>
|
||||
</div>
|
||||
</main>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
Check out my <Link href="/articles">thoughts and articles on various matters</Link>.
|
||||
</Paragraph>
|
||||
<Paragraph italic>Thank you for visiting!</Paragraph>
|
||||
</VStack>
|
||||
</Container>
|
||||
</IndexLayout>
|
||||
@@ -1,8 +1,8 @@
|
||||
export /**
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
const SITE_TITLE = 'Vladimir Eremin';
|
||||
export /**
|
||||
*
|
||||
*/
|
||||
*
|
||||
*/
|
||||
const SITE_DESCRIPTION = 'Thoughts and creations of mine';
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Container, Header, Paragraph } from '@ermnvldmr/ui';
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
@@ -10,9 +11,9 @@ import React from 'react';
|
||||
*/
|
||||
export const Welcome: React.FC = (): React.JSX.Element => {
|
||||
return (
|
||||
<div className="p-4 bg-gray-100 rounded-lg">
|
||||
<h1 className="text-2xl font-bold">Welcome to WWW Service</h1>
|
||||
<p>This is a placeholder component for Storybook.</p>
|
||||
</div>
|
||||
<Container bg="muted" padding={4} rounded="lg">
|
||||
<Header level={1}>Welcome to WWW Service</Header>
|
||||
<Paragraph>This is a placeholder component for Storybook.</Paragraph>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user