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
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client'

import { SecondaryButton } from "@servicestack/react"
import Page from "@/components/layout-page"
import { ValidateAuth, appAuth } from "@/lib/auth"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use client'

import Link from "next/link"
import { AutoQueryGrid } from "@servicestack/react"
import Page from "@/components/layout-page"
import { ValidateAuth } from "@/lib/auth"
import SrcPage from "@/components/src-page"

function Index() {


function BookingsAuto() {
return (<Page title="Bookings CRUD (Auto Columns)">

<div className="mb-4 flex justify-end">
Expand All @@ -26,5 +26,4 @@ function Index() {
</Page>)
}

export default ValidateAuth(Index, {role: 'Employee'})

export default ValidateAuth(BookingsAuto, {role: 'Employee'})
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useState, useEffect } from "react"
'use client'

import { useState } from "react"
import Link from "next/link"
import { useFormatters, AutoQueryGrid, TextLink, PreviewFormat, AutoEditForm, Icon } from "@servicestack/react"
import Page from "@/components/layout-page"
import { ValidateAuth } from "@/lib/auth"
import SrcPage from "@/components/src-page"

function Index() {
function BookingsCustom() {
const { currency } = useFormatters()
const [coupon, setCoupon] = useState<any>(null)

Expand Down Expand Up @@ -76,7 +78,7 @@ function Index() {
onSave={() => setCoupon(null)}
/>
)}

<div className="mt-4 text-center text-gray-400 flex justify-center -ml-6">
<SrcPage path="bookings-custom.tsx" />
</div>
Expand All @@ -85,5 +87,4 @@ function Index() {
</Page>)
}

export default ValidateAuth(Index, {role: 'Employee'})

export default ValidateAuth(BookingsCustom, {role: 'Employee'})
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Layout from "../components/layout-article"
import Layout from "@/components/layout-article"

export const meta = {
title: 'Template Features'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
export default () => {
return (<>
export default function Forbidden() {
return (
<div className="text-black bg-white h-screen text-center flex flex-col items-center justify-center">
<div>
<h1 className="inline-block border-gray-300 border-r m-0 mr-5 py-2 pr-4 text-2xl font-medium align-top">403</h1>
<div className="inline-block text-left h-8 align-middle">
<h2 className="text-sm leading-10 font-normal m-0 p-0">You do not have access to this page.</h2>
</div>
</div>
</div>
</>
</div>
)
}
42 changes: 42 additions & 0 deletions MyApp.Client/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import "../styles/index.css"
import "../styles/main.css"
import "../styles/prism-dark-blue.css"
import type { Metadata } from 'next'
import Providers from './providers'

export const metadata: Metadata = {
title: 'Next.js Example',
description: 'Next.js App Router Example',
}

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className="h-full">
<head />
<body className="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 transition-colors duration-200">
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
function getTheme() {
const theme = localStorage.getItem('color-scheme');
if (theme) return theme;
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
const theme = getTheme();
if (theme === 'dark') {
document.documentElement.classList.add('dark');
}
})();
`,
}}
/>
<Providers>{children}</Providers>
</body>
</html>
)
}
71 changes: 71 additions & 0 deletions MyApp.Client/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Container from "@/components/container"
import MoreStories from "@/components/more-stories"
import HeroPost from "@/components/hero-post"
import Intro from "@/components/intro"
import Layout from "@/components/layout"
import { getAllPosts } from "@/lib/api"
import { CMS_NAME } from "@/lib/constants"
import Post from "@/types/post"
import GettingStarted from "@/components/getting-started"
import BuiltInUis from "@/components/builtin-uis"
import type { Metadata } from 'next'

export const metadata: Metadata = {
title: `Next.js Example with ${CMS_NAME}`,
}

export default function Index() {
const allPosts = getAllPosts([
'title',
'date',
'slug',
'author',
'coverImage',
'excerpt',
]) as unknown as Post[]

const heroPost = allPosts[0]
const morePosts = allPosts.slice(1)

return (
<Layout>
<Container>
<Intro />
<div className="mb-32 flex justify-center">
<GettingStarted template="nextjs" />
</div>


<div className="flex justify-center my-20 py-20 bg-slate-100 dark:bg-slate-800">
<div className="text-center">
<svg className="text-link-dark w-36 h-36 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m8.58 17.25l.92-3.89l-3-2.58l3.95-.37L12 6.8l1.55 3.65l3.95.33l-3 2.58l.92 3.89L12 15.19zM12 2a10 10 0 0 1 10 10a10 10 0 0 1-10 10A10 10 0 0 1 2 12A10 10 0 0 1 12 2m0 2a8 8 0 0 0-8 8a8 8 0 0 0 8 8a8 8 0 0 0 8-8a8 8 0 0 0-8-8"/></svg>
<h1 className="text-6xl md:text-7xl lg:text-8xl font-bold tracking-tighter leading-tight md:leading-none mb-12 text-center md:text-left">
Built-in UIs
</h1>
</div>
</div>

<div className="mb-40">
<p className="mt-4 mb-10 text-xl text-gray-600 dark:text-gray-400">
Manage your ServiceStack App and explore, discover, query and call APIs instantly with
built-in Auto UIs dynamically generated from the rich metadata of your App's typed C# APIs &amp; DTOs
</p>

<BuiltInUis />
</div>

{heroPost && (
<HeroPost
title={heroPost.title}
coverImage={heroPost.coverImage}
date={heroPost.date}
author={heroPost.author}
slug={heroPost.slug}
excerpt={heroPost.excerpt}
/>
)}
{morePosts.length > 0 && <MoreStories posts={morePosts} />}
</Container>
</Layout>
)
}
75 changes: 75 additions & 0 deletions MyApp.Client/app/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { notFound } from "next/navigation"
import Container from "@/components/container"
import PostBody from "@/components/post-body"
import Header from "@/components/header"
import PostHeader from "@/components/post-header"
import Layout from "@/components/layout"
import { getPostBySlug, getAllPosts } from "@/lib/api"
import PostTitle from "@/components/post-title"
import { CMS_NAME } from "@/lib/constants"
import markdownToHtml from "@/lib/markdownToHtml"
import type { Metadata } from 'next'
import PostType from "@/types/post"

type Props = {
params: Promise<{
slug: string
}>
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const post = getPostBySlug(slug, ['title', 'ogImage']) as unknown as PostType
const title = `${post.title} | Next.js Example with ${CMS_NAME}`

return {
title,
openGraph: {
images: [post.ogImage.url],
},
}
}

export async function generateStaticParams() {
const posts = getAllPosts(['slug'])

return posts.map((post) => ({
slug: post.slug,
}))
}

export default async function Post({ params }: Props) {
const { slug } = await params
const post = getPostBySlug(slug, [
'title',
'date',
'slug',
'author',
'content',
'ogImage',
'coverImage',
]) as unknown as PostType

if (!post?.slug) {
notFound()
}

const content = await markdownToHtml(post.content || '')

return (
<Layout>
<Container>
<Header />
<article className="prose lg:prose-xl max-w-none mb-32">
<PostHeader
title={post.title}
coverImage={post.coverImage}
date={post.date}
author={post.author}
/>
<PostBody content={content} />
</article>
</Container>
</Layout>
)
}
38 changes: 38 additions & 0 deletions MyApp.Client/app/posts/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react"
import Layout from "@/components/layout"
import { getAllPosts } from "@/lib/api"
import type { Metadata } from 'next'

export const metadata: Metadata = {
title: 'Markdown Posts',
}

export default function Posts() {
const allPosts = getAllPosts([
'title',
'slug',
'excerpt',
])

return (
<Layout>
<main>
<div className="max-w-7xl mx-auto px-5">
<h1 className="text-4xl font-bold my-8 text-gray-900 dark:text-gray-100">Markdown Posts</h1>
<h3 className="text-lg mb-8">
List of Markdown Posts in <span
className="bg-blue-50 text-blue-500 dark:bg-blue-900 dark:text-blue-200 py-1 px-2 rounded">/pages</span>
</h3>
{allPosts.map((post) => (
<div className="mb-8" key={post.slug}>
<a className="text-2xl hover:text-green-600" href={`/posts/${post.slug}`}>{post.title}</a>
{!post.excerpt ? null : <p className="text-gray-500">
{post.excerpt}
</p>}
</div>
))}
</div>
</main>
</Layout>
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client'

import React from "react"
import Page from "../components/layout-page"
import Page from "@/components/layout-page"
import {SecondaryButton} from "@servicestack/react"
import {appAuth, ValidateAuth} from "@/lib/auth"

Expand Down
23 changes: 23 additions & 0 deletions MyApp.Client/app/providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client'

import { useEffect } from "react"
import Link from 'next/link'
import { setLinkComponent, ClientContext } from '@servicestack/react'
import { client, init } from "@/lib/gateway"

// Adapter component to convert react-router 'to' prop to Next.js 'href' prop
const NextLink = ({ to, ...props }: any) => <Link href={to || props.href} {...props} />

setLinkComponent(NextLink)

export default function Providers({ children }: { children: React.ReactNode }) {
useEffect(() => {
(async () => init())()
}, [])

return (
<ClientContext.Provider value={client}>
{children}
</ClientContext.Provider>
)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Layout from "../components/layout"
import { Button } from "../components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../components/ui/card"
import { Badge } from "../components/ui/badge"
import { Alert, AlertDescription, AlertTitle } from "../components/ui/alert"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../components/ui/tabs"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../components/ui/accordion"
import Layout from "@/components/layout"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
import { Terminal, Rocket, Package, ExternalLink, Info, Download, Code2 } from "lucide-react"

const ShadcnUiDemo = () => {
Expand Down Expand Up @@ -216,7 +216,7 @@ const ShadcnUiDemo = () => {
<h4 className="font-semibold text-sm text-slate-900 dark:text-slate-100">Basic Example:</h4>
<div className="bg-slate-100 dark:bg-slate-900 p-4 rounded-lg border border-slate-200 dark:border-slate-700">
<code className="text-sm text-slate-900 dark:text-slate-200 font-mono">
<div>import &#123; Button &#125; from "../components/ui/button"</div>
<div>import &#123; Button &#125; from "@/components/ui/button"</div>
<div className="mt-2">export default function Page() &#123;</div>
<div className="ml-4">return &lt;Button&gt;Click me&lt;/Button&gt;</div>
<div>&#125;</div>
Expand Down Expand Up @@ -314,4 +314,3 @@ const ShadcnUiDemo = () => {
}

export default ShadcnUiDemo

Loading
Loading