Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/card-variant-and-type-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tiny-design/react": minor
---

Add `variant` prop to Card component (`outlined`, `elevated`, `filled`). Fix NativeSelect children type to accept arrays. Make Table ColumnType `dataIndex` optional for action columns.
8 changes: 8 additions & 0 deletions .github/workflows/deploy-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ jobs:
- name: Copy 404.html for SPA routing
run: cp apps/docs/build/index.html apps/docs/build/404.html

- name: Build pro site
run: pnpm --filter @tiny-design/pro build
env:
NEXT_PUBLIC_BASE_PATH: /tiny-design/pro

- name: Merge pro into docs output
run: cp -r apps/pro/out/ apps/docs/build/pro/

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ export const PreviewPanel = (): React.ReactElement => {
</Flex>
<Table columns={tableColumns} dataSource={tableData} pagination={false} bordered />
<Card title="Card Title" style={{ marginTop: 16 }}>
<p>Card content with some text to show how typography looks in a card component.</p>
<Card.Content>
<p>Card content with some text to show how typography looks in a card component.</p>
<p>Card content with some text to show how typography looks in a card component.</p>
</Card.Content>
</Card>
<Flex gap="sm" wrap="wrap" style={{ marginTop: 16 }}>
<Tag>Default</Tag>
Expand Down
1 change: 1 addition & 0 deletions apps/docs/src/locale/en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const en_US: SiteLocale = {
guide: 'Guide',
theme: 'Theme',
components: 'Components',
pro: 'Pro',
},
home: {
subtitle: 'A Friendly UI Component Set for React',
Expand Down
1 change: 1 addition & 0 deletions apps/docs/src/locale/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type SiteLocale = {
guide: string;
theme: string;
components: string;
pro: string;
};
home: {
subtitle: string;
Expand Down
1 change: 1 addition & 0 deletions apps/docs/src/locale/zh_CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const zh_CN: SiteLocale = {
guide: '指南',
theme: '主题',
components: '组件',
pro: 'Pro',
},
home: {
subtitle: '一套友好的 React UI 组件库',
Expand Down
2 changes: 2 additions & 0 deletions apps/pro/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.next/
out/
6 changes: 6 additions & 0 deletions apps/pro/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
63 changes: 63 additions & 0 deletions apps/pro/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { NextConfig } from 'next';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';

const nextConfig: NextConfig = {
output: 'export',
basePath,
trailingSlash: true,
images: { unoptimized: true },
sassOptions: {
includePaths: [
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, '../../node_modules'),
path.resolve(__dirname, '../../packages/react/src'),
],
},
webpack(config) {
// Source alias: resolve to package source (same pattern as docs app)
config.resolve.alias['@tiny-design/react'] = path.resolve(
__dirname,
'../../packages/react/src'
);
config.resolve.alias['@tiny-design/icons'] = path.resolve(
__dirname,
'../../packages/icons/src'
);

// ?raw imports: embed original file contents as strings at build time.
// We must exclude ?raw from existing oneOf rules so Next.js/SWC doesn't
// compile the TSX before we read it as plain text.
const rawQuery = /raw/;

for (const rule of config.module.rules) {
if (rule && typeof rule === 'object' && rule.oneOf) {
for (const oneOfRule of rule.oneOf) {
if (oneOfRule && typeof oneOfRule === 'object') {
// Add resourceQuery exclusion to each sub-rule
if (!oneOfRule.resourceQuery) {
oneOfRule.resourceQuery = { not: [rawQuery] };
} else if (oneOfRule.resourceQuery instanceof RegExp) {
oneOfRule.resourceQuery = {
and: [oneOfRule.resourceQuery],
not: [rawQuery],
};
}
}
}
}
}

config.module.rules.push({
resourceQuery: rawQuery,
type: 'asset/source',
});

return config;
},
};

export default nextConfig;
28 changes: 28 additions & 0 deletions apps/pro/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@tiny-design/pro",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "next dev --port 3001",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@tiny-design/icons": "workspace:*",
"@tiny-design/react": "workspace:*",
"@tiny-design/tokens": "workspace:*",
"classnames": "^2.5.0",
"next": "^15.3.4",
"prism-react-renderer": "^2.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-runner": "^1.0.5",
"sass": "^1.49.9"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "^5.4.0"
}
}
3 changes: 3 additions & 0 deletions apps/pro/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
plugins: {},
};
33 changes: 33 additions & 0 deletions apps/pro/src/app/blocks/[category]/category-page-client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use client';

import { CategoryNav } from '@/components/layout/category-nav';
import { BlockPreview } from '@/components/block-preview';
import { getCategory } from '../../../utils/blocks';
import styles from './category-page.module.scss';

interface CategoryPageClientProps {
slug: string;
label: string;
}

export function CategoryPageClient({ slug, label }: CategoryPageClientProps) {
const category = getCategory(slug);
const blocks = category?.blocks ?? [];

return (
<div className={styles.layout}>
<CategoryNav />
<main className={styles.content}>
<div className={styles.pageHeader}>
<h1 className={styles.title}>{label}</h1>
<p className={styles.count}>
{blocks.length} {blocks.length === 1 ? 'block' : 'blocks'}
</p>
</div>
{blocks.map((block) => (
<BlockPreview key={block.id} meta={block} />
))}
</main>
</div>
);
}
33 changes: 33 additions & 0 deletions apps/pro/src/app/blocks/[category]/category-page.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.layout {
display: flex;
padding-top: 60px;
min-height: 100vh;
}

.content {
flex: 1;
margin-left: 240px;
padding: 40px 48px 80px;
max-width: calc(100% - 240px);
}

.pageHeader {
margin-bottom: 36px;
padding-bottom: 24px;
border-bottom: 1px solid var(--ty-color-border-secondary);
}

.title {
font-size: 26px;
font-weight: 700;
letter-spacing: -0.025em;
margin: 0 0 6px;
color: var(--ty-color-text);
}

.count {
font-size: 13px;
color: var(--ty-color-text-tertiary);
margin: 0;
font-weight: 500;
}
18 changes: 18 additions & 0 deletions apps/pro/src/app/blocks/[category]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { notFound } from 'next/navigation';
import { getCategorySlugs, getCategoryInfo } from '../../../utils/blocks';
import { CategoryPageClient } from './category-page-client';

export function generateStaticParams() {
return getCategorySlugs().map((slug) => ({ category: slug }));
}

interface PageProps {
params: Promise<{ category: string }>;
}

export default async function CategoryPage({ params }: PageProps) {
const { category: slug } = await params;
const info = getCategoryInfo(slug);
if (!info) notFound();
return <CategoryPageClient slug={slug} label={info.label} />;
}
22 changes: 22 additions & 0 deletions apps/pro/src/app/globals.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@use '@tiny-design/tokens/scss/base' as *;
@use 'style/component' as *;

*,
*::before,
*::after {
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
font-family: var(--font-body), -apple-system, blinkmacsystemfont, 'Segoe UI', roboto,
'Helvetica Neue', arial, 'Noto Sans', sans-serif;
background: var(--ty-color-bg);
color: var(--ty-color-text);
transition:
background-color 0.2s,
color 0.2s;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
36 changes: 36 additions & 0 deletions apps/pro/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Metadata } from 'next';
import { Bricolage_Grotesque, DM_Sans } from 'next/font/google';
import { ThemeScript } from '../components/theme-script';
import { SiteHeader } from '../components/layout/site-header';
import './globals.scss';

const heading = Bricolage_Grotesque({
subsets: ['latin'],
variable: '--font-heading',
display: 'swap',
weight: ['400', '500', '600', '700', '800'],
});

const body = DM_Sans({
subsets: ['latin'],
variable: '--font-body',
display: 'swap',
weight: ['400', '500', '600', '700'],
});

export const metadata: Metadata = {
title: 'Tiny Design Pro',
description: 'Beautiful, ready-to-use UI blocks built with Tiny Design components.',
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={`${heading.variable} ${body.variable}`} suppressHydrationWarning>
<body>
<ThemeScript />
<SiteHeader />
{children}
</body>
</html>
);
}
Loading
Loading