|
1 | | -import React from 'react' |
| 1 | +import React, { useState, useMemo } from 'react' |
2 | 2 | import GalleryLayout from '../components/GalleryLayout' |
3 | 3 | import CodeBlock from '../components/CodeBlock' |
4 | 4 |
|
| 5 | +function ProjectTemplateSelector() { |
| 6 | + const [project, setProject] = useState('MyApp') |
| 7 | + |
| 8 | + const projectZip = useMemo(() => (project || 'MyApp') + '.zip', [project]) |
| 9 | + |
| 10 | + const zipUrl = (template: string) => |
| 11 | + `https://account.servicestack.net/archive/${template}?Name=${project || 'MyApp'}` |
| 12 | + |
| 13 | + const isAlphaNumeric = (e: React.KeyboardEvent<HTMLInputElement>) => { |
| 14 | + const key = e.key |
| 15 | + // Allow alphanumeric characters and underscore |
| 16 | + if (key.length === 1 && !/^[A-Za-z0-9_]$/.test(key)) { |
| 17 | + e.preventDefault() |
| 18 | + } |
| 19 | + } |
| 20 | + |
| 21 | + return ( |
| 22 | + <section className="not-prose w-full flex flex-col justify-center text-center"> |
| 23 | + <div id="empty" className="mt-4 mb-2"> |
| 24 | + <div className="flex justify-center mb-16"> |
| 25 | + <div className="w-70"> |
| 26 | + <input |
| 27 | + value={project} |
| 28 | + onChange={(e) => setProject(e.target.value)} |
| 29 | + type="text" |
| 30 | + placeholder="Project Name" |
| 31 | + autoCorrect="off" |
| 32 | + spellCheck={false} |
| 33 | + onKeyDown={isAlphaNumeric} |
| 34 | + className="mt-1 text-lg block w-full px-3 py-2 bg-white dark:bg-black border border-slate-300 dark:border-slate-700 rounded-md text-sm shadow-sm placeholder-slate-400 |
| 35 | + focus:outline-none focus:border-sky-500 focus:ring-1 focus:ring-sky-500" |
| 36 | + /> |
| 37 | + </div> |
| 38 | + </div> |
| 39 | + <div id="ssg" className="mt-4 mb-2"> |
| 40 | + <h3 className="text-gray-400 text-xl mb-2">React Templates</h3> |
| 41 | + <div className="flex flex-wrap justify-center"> |
| 42 | + <div> |
| 43 | + <a className="archive-url hover:no-underline" href={zipUrl('NetCoreTemplates/react-vite')}> |
| 44 | + <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" style={{ minWidth: '150px' }}> |
| 45 | + <div className="text-center font-extrabold flex items-center justify-center mb-2"> |
| 46 | + <div className="text-4xl text-blue-400 my-3"> |
| 47 | + <svg className="w-14 h-14" xmlns="http://www.w3.org/2000/svg" viewBox="-10.5 -9.45 21 18.9" fill="none"> |
| 48 | + <circle cx="0" cy="0" r="2" fill="currentColor"></circle> |
| 49 | + <g stroke="currentColor" strokeWidth="1" fill="none"> |
| 50 | + <ellipse rx="10" ry="4.5"></ellipse> |
| 51 | + <ellipse rx="10" ry="4.5" transform="rotate(60)"></ellipse> |
| 52 | + <ellipse rx="10" ry="4.5" transform="rotate(120)"></ellipse> |
| 53 | + </g> |
| 54 | + </svg> |
| 55 | + </div> |
| 56 | + </div> |
| 57 | + <div className="text-xl font-medium text-gray-700 dark:text-gray-200">React Vite</div> |
| 58 | + <div className="flex justify-center h-8"></div> |
| 59 | + <span className="archive-name px-4 pb-2 text-blue-600 dark:text-indigo-400">{projectZip}</span> |
| 60 | + <div className="count mt-1 text-gray-400 text-sm"></div> |
| 61 | + </div> |
| 62 | + </a> |
| 63 | + <a className="text-sm text-center mr-4" href="https://react-vite.web-templates.io">react-vite.web-templates.io</a> |
| 64 | + </div> |
| 65 | + <div> |
| 66 | + <a className="archive-url hover:no-underline" href={zipUrl('NetCoreTemplates/nextjs')}> |
| 67 | + <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" style={{ minWidth: '150px' }}> |
| 68 | + <div className="text-center font-extrabold flex items-center justify-center mb-2"> |
| 69 | + <div className="text-4xl text-blue-400 my-3"> |
| 70 | + <svg className="w-14 h-14 bg-white text-gray-900 rounded-full" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"> |
| 71 | + <path fill="currentColor" d="M386.399 35.508C217.06-64.061 1.885 57.55.012 253.882c-1.828 191.716 201.063 315.545 370.02 231.163L185.56 213.636v167.997c0 18.614-35.619 18.614-35.619 0V156.421c0-14.776 27.448-15.989 35.226-3.145L395.43 470.572c157.95-101.737 155.817-338.136-9.031-435.064zm-23.756 317.939L326.91 298.87V149.458c0-13.932 35.732-13.932 35.732 0v203.989z"/> |
| 72 | + </svg> |
| 73 | + </div> |
| 74 | + </div> |
| 75 | + <div className="text-xl font-medium text-gray-700 dark:text-gray-200">Next.js</div> |
| 76 | + <div className="flex justify-center h-8"></div> |
| 77 | + <span className="archive-name px-4 pb-2 text-blue-600 dark:text-indigo-400">{projectZip}</span> |
| 78 | + <div className="count mt-1 text-gray-400 text-sm"></div> |
| 79 | + </div> |
| 80 | + </a> |
| 81 | + <a className="text-sm text-center mr-4" href="https://nextjs.web-templates.io">nextjs.web-templates.io</a> |
| 82 | + </div> |
| 83 | + <div> |
| 84 | + <a className="archive-url hover:no-underline" href={zipUrl('NetCoreTemplates/react-spa')}> |
| 85 | + <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" style={{ minWidth: '150px' }}> |
| 86 | + <div className="text-center font-extrabold flex items-center justify-center mb-2"> |
| 87 | + <div className="text-4xl text-blue-400 my-3"> |
| 88 | + <svg className="w-14 h-14" xmlns="http://www.w3.org/2000/svg" viewBox="-10.5 -9.45 21 18.9" fill="none"> |
| 89 | + <circle cx="0" cy="0" r="2" fill="currentColor"></circle> |
| 90 | + <g stroke="currentColor" strokeWidth="1" fill="none"> |
| 91 | + <ellipse rx="10" ry="4.5"></ellipse> |
| 92 | + <ellipse rx="10" ry="4.5" transform="rotate(60)"></ellipse> |
| 93 | + <ellipse rx="10" ry="4.5" transform="rotate(120)"></ellipse> |
| 94 | + </g> |
| 95 | + </svg> |
| 96 | + </div> |
| 97 | + </div> |
| 98 | + <div className="text-xl font-medium text-gray-700 dark:text-gray-200">React SPA</div> |
| 99 | + <div className="flex justify-center h-8"></div> |
| 100 | + <span className="archive-name px-4 pb-2 text-blue-600 dark:text-indigo-400">{projectZip}</span> |
| 101 | + <div className="count mt-1 text-gray-400 text-sm"></div> |
| 102 | + </div> |
| 103 | + </a> |
| 104 | + <a className="text-sm text-center mr-4" href="https://react-spa.web-templates.io">react-spa.web-templates.io</a> |
| 105 | + </div> |
| 106 | + </div> |
| 107 | + </div> |
| 108 | + </div> |
| 109 | + </section> |
| 110 | + ) |
| 111 | +} |
| 112 | + |
5 | 113 | export default function InstallPage() { |
6 | 114 | return ( |
7 | 115 | <GalleryLayout title="Installation"> |
| 116 | + <h2>Starting Project Templates</h2> |
| 117 | + <p> |
| 118 | + The fastest way to get started is to use one of our pre-configured project templates. |
| 119 | + These templates come with ServiceStack and <code>@servicestack/react</code> already configured with |
| 120 | + best practices, authentication, and example components to help you hit the ground running. |
| 121 | + </p> |
| 122 | + |
| 123 | + <ProjectTemplateSelector /> |
| 124 | + |
8 | 125 | <h2>NPM Installation</h2> |
9 | 126 | <p> |
10 | 127 | <strong>@servicestack/react</strong> can be added to existing React Apps by installing via npm: |
@@ -89,7 +206,7 @@ export default { |
89 | 206 | import { JsonServiceClient } from '@servicestack/client' |
90 | 207 | import { ClientContext, AutoQueryGrid } from '@servicestack/react' |
91 | 208 |
|
92 | | -const client = new JsonServiceClient('https://blazor-gallery.jamstacks.net') |
| 209 | +const client = new JsonServiceClient('https://blazor-gallery.web-templates.io') |
93 | 210 |
|
94 | 211 | function App() { |
95 | 212 | return ( |
|
0 commit comments