Skip to content

Commit dc49149

Browse files
authored
Merge pull request #20 from ZVN-DEV/claude/fix-syntax-errors-zooln
2 parents 15275a8 + 8fb603d commit dc49149

18 files changed

Lines changed: 2118 additions & 15 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Whenny includes an MCP (Model Context Protocol) server so AI assistants like Cla
135135
"mcpServers": {
136136
"whenny": {
137137
"command": "npx",
138-
"args": ["whenny", "mcp"]
138+
"args": ["create-whenny", "mcp"]
139139
}
140140
}
141141
}

apps/example/app/demo/layout.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { Metadata } from 'next'
2+
3+
export const metadata: Metadata = {
4+
title: 'Interactive Demo - Whenny Date Library',
5+
description: 'Try Whenny live! Interactive examples of smart formatting, relative time, duration formatting, countdown timers, and calendar helpers. See how this modern TypeScript date library handles any date scenario.',
6+
keywords: [
7+
'date library demo',
8+
'typescript date examples',
9+
'relative time demo',
10+
'countdown timer react',
11+
'date formatting examples',
12+
'moment.js alternative demo',
13+
'smart date formatting',
14+
],
15+
openGraph: {
16+
title: 'Interactive Demo - Whenny Date Library',
17+
description: 'Try Whenny live! Interactive examples of smart formatting, relative time, duration formatting, countdown timers, and calendar helpers.',
18+
url: 'https://whenny.dev/demo',
19+
},
20+
}
21+
22+
export default function DemoLayout({
23+
children,
24+
}: {
25+
children: React.ReactNode
26+
}) {
27+
return children
28+
}

apps/example/app/docs/layout.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { Metadata } from 'next'
2+
3+
export const metadata: Metadata = {
4+
title: 'Documentation - Whenny Date Library',
5+
description: 'Complete documentation for Whenny, the modern TypeScript date library. Learn formatting, relative time, timezones, React hooks, and more. API reference with code examples.',
6+
keywords: [
7+
'date library documentation',
8+
'typescript date api',
9+
'date formatting guide',
10+
'timezone handling tutorial',
11+
'react date hooks',
12+
'moment.js migration',
13+
'dayjs alternative docs',
14+
'date-fns comparison',
15+
],
16+
openGraph: {
17+
title: 'Documentation - Whenny Date Library',
18+
description: 'Complete documentation for Whenny. Learn formatting, relative time, timezones, React hooks, and more.',
19+
url: 'https://whenny.dev/docs',
20+
},
21+
}
22+
23+
export default function DocsLayout({
24+
children,
25+
}: {
26+
children: React.ReactNode
27+
}) {
28+
return children
29+
}

apps/example/app/layout.tsx

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,106 @@
11
import type { Metadata } from 'next'
22
import './globals.css'
33

4+
const title = 'Whenny - The Modern TypeScript Date Library for the AI Era'
5+
const description = 'A modern date library that makes dates just work. Zero-config timezone handling, AI-friendly API, shadcn-style code ownership. The friendly alternative to Moment.js, Day.js, and date-fns for TypeScript developers.'
6+
const url = 'https://whenny.dev'
7+
48
export const metadata: Metadata = {
5-
title: 'Whenny - Date Library Example',
6-
description: 'A modern date library for the AI era',
9+
metadataBase: new URL(url),
10+
title: {
11+
default: title,
12+
template: '%s | Whenny',
13+
},
14+
description,
15+
keywords: [
16+
'typescript date library',
17+
'javascript date library',
18+
'date formatting',
19+
'timezone handling',
20+
'moment.js alternative',
21+
'dayjs alternative',
22+
'date-fns alternative',
23+
'relative time',
24+
'time ago',
25+
'countdown timer',
26+
'duration formatting',
27+
'natural language dates',
28+
'business days calculator',
29+
'shadcn components',
30+
'AI-friendly dates',
31+
'MCP server',
32+
'date parser',
33+
'smart date formatting',
34+
'i18n dates',
35+
'internationalization',
36+
'TypeScript',
37+
'React hooks',
38+
'server client sync',
39+
'timezone transfer',
40+
],
41+
authors: [{ name: 'Whenny Contributors' }],
42+
creator: 'Whenny',
43+
publisher: 'Whenny',
44+
robots: {
45+
index: true,
46+
follow: true,
47+
googleBot: {
48+
index: true,
49+
follow: true,
50+
'max-video-preview': -1,
51+
'max-image-preview': 'large',
52+
'max-snippet': -1,
53+
},
54+
},
55+
openGraph: {
56+
type: 'website',
57+
locale: 'en_US',
58+
url,
59+
title,
60+
description,
61+
siteName: 'Whenny',
62+
images: [
63+
{
64+
url: '/og-image.png',
65+
width: 1200,
66+
height: 630,
67+
alt: 'Whenny - The Modern TypeScript Date Library',
68+
},
69+
],
70+
},
71+
twitter: {
72+
card: 'summary_large_image',
73+
title,
74+
description,
75+
images: ['/og-image.png'],
76+
},
77+
alternates: {
78+
canonical: url,
79+
},
80+
category: 'technology',
81+
classification: 'Software Development',
82+
}
83+
84+
// JSON-LD Structured Data for rich search results
85+
const jsonLd = {
86+
'@context': 'https://schema.org',
87+
'@type': 'SoftwareApplication',
88+
name: 'Whenny',
89+
applicationCategory: 'DeveloperApplication',
90+
operatingSystem: 'Cross-platform',
91+
offers: {
92+
'@type': 'Offer',
93+
price: '0',
94+
priceCurrency: 'USD',
95+
},
96+
description,
97+
url,
98+
author: {
99+
'@type': 'Organization',
100+
name: 'Whenny Contributors',
101+
},
102+
programmingLanguage: ['TypeScript', 'JavaScript'],
103+
keywords: 'date library, typescript, timezone, moment.js alternative, AI-friendly',
7104
}
8105

9106
export default function RootLayout({
@@ -13,6 +110,12 @@ export default function RootLayout({
13110
}) {
14111
return (
15112
<html lang="en">
113+
<head>
114+
<script
115+
type="application/ld+json"
116+
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
117+
/>
118+
</head>
16119
<body className="font-sans">{children}</body>
17120
</html>
18121
)

apps/example/app/robots.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { MetadataRoute } from 'next'
2+
3+
export default function robots(): MetadataRoute.Robots {
4+
return {
5+
rules: {
6+
userAgent: '*',
7+
allow: '/',
8+
disallow: ['/api/', '/_next/'],
9+
},
10+
sitemap: 'https://whenny.dev/sitemap.xml',
11+
}
12+
}

apps/example/app/sitemap.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { MetadataRoute } from 'next'
2+
3+
export default function sitemap(): MetadataRoute.Sitemap {
4+
const baseUrl = 'https://whenny.dev'
5+
6+
return [
7+
{
8+
url: baseUrl,
9+
lastModified: new Date(),
10+
changeFrequency: 'weekly',
11+
priority: 1,
12+
},
13+
{
14+
url: `${baseUrl}/demo`,
15+
lastModified: new Date(),
16+
changeFrequency: 'weekly',
17+
priority: 0.9,
18+
},
19+
{
20+
url: `${baseUrl}/docs`,
21+
lastModified: new Date(),
22+
changeFrequency: 'weekly',
23+
priority: 0.9,
24+
},
25+
{
26+
url: `${baseUrl}/server`,
27+
lastModified: new Date(),
28+
changeFrequency: 'monthly',
29+
priority: 0.7,
30+
},
31+
{
32+
url: `${baseUrl}/sanity-test.html`,
33+
lastModified: new Date(),
34+
changeFrequency: 'monthly',
35+
priority: 0.5,
36+
},
37+
]
38+
}

apps/example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "whenny-example",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"private": true,
55
"scripts": {
66
"dev": "next dev",

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/create-whenny/package.json

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
11
{
22
"name": "create-whenny",
3-
"version": "1.0.7",
3+
"version": "1.0.8",
44
"description": "CLI for adding Whenny date utilities to your project",
55
"keywords": [
66
"whenny",
77
"date",
88
"time",
9+
"datetime",
910
"cli",
1011
"scaffolding",
11-
"shadcn"
12+
"shadcn",
13+
"shadcn-style",
14+
"create",
15+
"init",
16+
"generator",
17+
"code-generator",
18+
"typescript",
19+
"typescript-date",
20+
"moment",
21+
"moment-alternative",
22+
"dayjs",
23+
"date-fns",
24+
"date-library",
25+
"timezone",
26+
"mcp",
27+
"mcp-server",
28+
"ai-tools",
29+
"claude-mcp",
30+
"model-context-protocol"
1231
],
1332
"author": "Whenny Contributors",
1433
"license": "MIT",

packages/create-whenny/src/commands/add.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,40 @@ import ora from 'ora'
1111
import prompts from 'prompts'
1212
import { MODULES, getModuleTemplate } from '../templates/index.js'
1313
import { detectWhennyPath } from '../utils/detect.js'
14+
import { writeDocsFile, getInstalledModules } from '../utils/docs-generator.js'
15+
16+
/**
17+
* Resolve all dependencies for the given modules
18+
*/
19+
function resolveAllDependencies(modules: string[]): string[] {
20+
const resolved = new Set<string>()
21+
22+
function addWithDeps(moduleName: string) {
23+
if (resolved.has(moduleName)) return
24+
const module = MODULES.find(m => m.name === moduleName)
25+
if (!module) return
26+
27+
// Add dependencies first
28+
if (module.dependencies) {
29+
for (const dep of module.dependencies) {
30+
addWithDeps(dep)
31+
}
32+
}
33+
34+
resolved.add(moduleName)
35+
}
36+
37+
for (const mod of modules) {
38+
addWithDeps(mod)
39+
}
40+
41+
// Sort: core first, then alphabetically
42+
return Array.from(resolved).sort((a, b) => {
43+
if (a === 'core') return -1
44+
if (b === 'core') return 1
45+
return a.localeCompare(b)
46+
})
47+
}
1448

1549
interface AddOptions {
1650
path?: string
@@ -61,6 +95,16 @@ export async function add(
6195
return
6296
}
6397

98+
// Resolve all dependencies
99+
const originalModules = [...modules]
100+
modules = resolveAllDependencies(modules)
101+
102+
// Show which dependencies will be added
103+
const addedDeps = modules.filter(m => !originalModules.includes(m))
104+
if (addedDeps.length > 0) {
105+
console.log(chalk.cyan(` Adding dependencies: ${addedDeps.join(', ')}`))
106+
}
107+
64108
// Detect whenny path
65109
let targetPath: string | undefined = options.path
66110
if (!targetPath) {
@@ -121,13 +165,19 @@ export async function add(
121165
spinner.text = 'Updating index.ts...'
122166
await updateIndexFile(fullPath, modules)
123167

168+
// Regenerate documentation
169+
spinner.text = 'Updating documentation...'
170+
const allModules = await getInstalledModules(fullPath)
171+
await writeDocsFile(fullPath, allModules)
172+
124173
spinner.succeed(`Added ${modules.length} module(s)`)
125174

126175
console.log()
127176
console.log(chalk.green(' Added:'))
128177
modules.forEach(m => {
129178
console.log(chalk.gray(` - ${targetPath}/${m}.ts`))
130179
})
180+
console.log(chalk.gray(` Updated: Whenny-Dates-Agents.md`))
131181
console.log()
132182
} catch (error) {
133183
spinner.fail('Failed to add modules')

0 commit comments

Comments
 (0)