Skip to content

Commit e715042

Browse files
committed
template tweaks
1 parent 2f3bef5 commit e715042

File tree

6 files changed

+97
-96
lines changed

6 files changed

+97
-96
lines changed

MyApp.Client/components/alert.tsx

Lines changed: 0 additions & 48 deletions
This file was deleted.

MyApp.Client/components/getting-started.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default ({ template }: Props) => {
2929
className="mb-8 sm:text-lg rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 dark:bg-gray-800" />
3030

3131
<section className="w-full flex justify-center text-center">
32-
<div className="mb-2">
32+
<div className="mb-8">
3333
<div className="flex justify-center text-center">
3434
<a className="archive-url hover:no-underline netcoretemplates_empty" href={zipUrl(`NetCoreTemplates/${template}`)}>
3535
<div className="bg-white dark:bg-gray-800 px-4 py-4 mr-4 mb-4 rounded-lg shadow-lg text-center items-center justify-center hover:shadow-2xl dark:border-2 dark:border-pink-600 dark:hover:border-blue-600"

MyApp.Client/components/intro.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { useState } from "react"
22
import { TextInput } from "@servicestack/react"
3-
import { CMS_NAME } from "@/lib/constants"
43
import { swrClient } from "@/lib/gateway"
54
import { Hello } from "@/lib/dtos"
5+
import { CMS_NAME } from "@/lib/constants"
66

77
const HelloApi = ({ name }:any) => {
88
const { data, error } = swrClient.get(() => new Hello({ name }))
99
if (error) return <div className="ml-2 text-red-500 dark:text-red-400">{error.message}</div>
10-
return <div className="ml-3 mt-2 text-2xl text-gray-900 dark:text-gray-100">{data ? data.result : 'loading...'}</div>
10+
return <div className="ml-3 mt-2 text-gray-900 dark:text-gray-100">{data ? data.result : 'loading...'}</div>
1111
}
1212

1313
const Intro = () => {
@@ -20,15 +20,17 @@ const Intro = () => {
2020
</h1>
2121
<div className="flex flex-col">
2222
<h4 className="text-lg mt-5 text-gray-700 dark:text-gray-300">
23-
A statically generated site (SSG) example using{' '}
23+
A statically rendered example using{' '}
2424
<a
2525
href="https://nextjs.org/"
2626
className="underline hover:text-success duration-200 transition-colors"
2727
>
2828
Next.js
29-
</a>,
30-
{' ' + CMS_NAME} &amp; {' '}
31-
<a href="https://servicestack.net" className="underline hover:text-success duration-200 transition-colors">ServiceStack</a>.
29+
</a>
30+
<span className="px-1">&amp;</span>
31+
<a href="https://servicestack.net" className="underline hover:text-success duration-200 transition-colors">
32+
{CMS_NAME}
33+
</a>
3234
</h4>
3335
<div className="flex items-center flex-wrap sm:flex-nowrap">
3436
<TextInput id="name" label="" value={inputValue} onChange={setInputValue} />
Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,94 @@
1-
import { FC, MouseEvent, useState } from "react"
2-
3-
const ShellCommand: FC<any> = ({ className, children }) => {
4-
5-
let [successText, setSuccessText] = useState("")
6-
7-
function copy(e: MouseEvent) {
8-
let $el = document.createElement("input")
9-
let $lbl = (e.target as HTMLElement).parentElement!.querySelector('label')!
10-
11-
$el.setAttribute("value", $lbl.innerText)
12-
document.body.appendChild($el)
13-
$el.select()
14-
document.execCommand("copy")
15-
document.body.removeChild($el);
16-
17-
if (typeof window.getSelection == "function") {
18-
const range = document.createRange()
19-
range.selectNodeContents($lbl)
20-
window.getSelection()?.removeAllRanges()
21-
window.getSelection()?.addRange(range)
22-
}
1+
import { FC, MouseEvent, useState, ReactNode, useRef } from "react"
2+
import { Terminal, Copy, Check } from "lucide-react"
3+
import { cn } from "../lib/utils"
4+
5+
interface ShellCommandProps {
6+
className?: string
7+
children: ReactNode
8+
}
9+
10+
const ShellCommand: FC<ShellCommandProps> = ({ className, children }) => {
11+
const [copied, setCopied] = useState(false)
12+
const commandRef = useRef<HTMLElement>(null)
13+
14+
async function copy(e: MouseEvent) {
15+
e.preventDefault()
16+
17+
// Get the text content from the command element
18+
const textToCopy = commandRef.current?.textContent || ""
19+
20+
try {
21+
// Use modern Clipboard API
22+
await navigator.clipboard.writeText(textToCopy)
23+
24+
setCopied(true)
25+
setTimeout(() => setCopied(false), 2000)
26+
} catch (err) {
27+
// Fallback for older browsers
28+
const $el = document.createElement("textarea")
29+
$el.value = textToCopy
30+
$el.style.position = "fixed"
31+
$el.style.opacity = "0"
32+
document.body.appendChild($el)
33+
$el.select()
34+
document.execCommand("copy")
35+
document.body.removeChild($el)
2336

24-
setSuccessText('copied')
25-
setTimeout(() => setSuccessText(''), 3000)
37+
setCopied(true)
38+
setTimeout(() => setCopied(false), 2000)
39+
}
2640
}
27-
41+
2842
return (
29-
<div className={`${className} lang relative bg-gray-700 text-gray-300 pl-5 py-3 sm:rounded flex`}>
30-
<div className="flex ml-2 w-full justify-between cursor-pointer" onClick={copy}>
31-
<span>$ <label className="">{children}</label></span>
32-
<small className="text-xs text-gray-400 px-3 -mt-1">sh</small>
33-
</div>
34-
{!successText ? null : <div className="-mr-24 right-0 absolute text-md text-gray-200 bg-green-700 px-1 rounded">
35-
<div className="flex pr-1">
36-
<svg className="w-5 h-5 mt-0.5" viewBox="0 0 24 24" fill="currentColor">
37-
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
38-
</svg>
39-
{successText}
43+
<div className={cn(
44+
"group relative overflow-hidden rounded-lg border border-slate-200 dark:border-slate-700",
45+
"bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800",
46+
"shadow-sm hover:shadow-md transition-all duration-200",
47+
className
48+
)}
49+
onClick={copy}
50+
>
51+
{/* Background pattern */}
52+
<div className="absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800 opacity-50"
53+
style={{ backgroundImage: 'radial-gradient(circle, rgba(0,0,0,0.05) 1px, transparent 1px)', backgroundSize: '16px 16px' }} />
54+
55+
<div className="relative flex items-center justify-between px-4 py-3">
56+
{/* Left side - Terminal icon and command */}
57+
<div
58+
className="flex items-center gap-3 flex-1 min-w-0 cursor-pointer"
59+
>
60+
<Terminal className="w-4 h-4 text-slate-500 dark:text-slate-400 flex-shrink-0" />
61+
<div className="flex items-center gap-2 min-w-0 flex-1">
62+
<code ref={commandRef} className="text-sm font-mono text-slate-900 dark:text-slate-100 truncate">
63+
{children}
64+
</code>
65+
</div>
4066
</div>
41-
</div>}
42-
</div>)
67+
68+
{/* Right side - Language badge and copy button */}
69+
<div className="flex items-center gap-2 ml-4">
70+
<button
71+
onClick={copy}
72+
className={cn(
73+
"flex items-center justify-center p-2 rounded-md",
74+
"transition-all duration-200",
75+
"focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2",
76+
copied
77+
? "bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400 border border-green-300 dark:border-green-700"
78+
: "bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300 border border-slate-300 dark:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-700 hover:border-slate-400 dark:hover:border-slate-500"
79+
)}
80+
aria-label={copied ? "Copied!" : "Copy command"}
81+
>
82+
{copied ? (
83+
<Check className="w-4 h-4" />
84+
) : (
85+
<Copy className="w-4 h-4" />
86+
)}
87+
</button>
88+
</div>
89+
</div>
90+
</div>
91+
)
4392
}
4493

4594
export default ShellCommand

MyApp.Client/lib/constants.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export const EXAMPLE_PATH = 'blog-starter-typescript'
2-
export const CMS_NAME = 'Markdown'
1+
export const CMS_NAME = 'ServiceStack'
32
export const HOME_OG_IMAGE_URL =
43
'https://og-image.vercel.app/Next.js%20Blog%20Starter%20Example.png?theme=light&md=1&fontSize=100px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg'

MyApp.Client/pages/shadcn-ui.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react"
21
import Layout from "../components/layout"
32
import { Button } from "../components/ui/button"
43
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../components/ui/card"

0 commit comments

Comments
 (0)