@nrwl/remix 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +7 -0
  2. package/generators.json +13 -0
  3. package/package.json +12 -0
  4. package/src/generators/application/application.impl.d.ts +3 -0
  5. package/src/generators/application/application.impl.js +45 -0
  6. package/src/generators/application/application.impl.js.map +1 -0
  7. package/src/generators/application/lib/normalize-options.d.ts +8 -0
  8. package/src/generators/application/lib/normalize-options.js +17 -0
  9. package/src/generators/application/lib/normalize-options.js.map +1 -0
  10. package/src/generators/application/schema.d.ts +5 -0
  11. package/src/generators/application/schema.json +28 -0
  12. package/src/generators/preset/files/README.md +53 -0
  13. package/src/generators/preset/files/app/entry.client.tsx__tmpl__ +4 -0
  14. package/src/generators/preset/files/app/entry.server.tsx__tmpl__ +21 -0
  15. package/src/generators/preset/files/app/root.tsx__tmpl__ +178 -0
  16. package/src/generators/preset/files/app/routes/demos/about/index.tsx__tmpl__ +17 -0
  17. package/src/generators/preset/files/app/routes/demos/about/whoa.tsx__tmpl__ +20 -0
  18. package/src/generators/preset/files/app/routes/demos/about.tsx__tmpl__ +44 -0
  19. package/src/generators/preset/files/app/routes/demos/actions.tsx__tmpl__ +101 -0
  20. package/src/generators/preset/files/app/routes/demos/correct.tsx__tmpl__ +3 -0
  21. package/src/generators/preset/files/app/routes/demos/params/$id.tsx__tmpl__ +110 -0
  22. package/src/generators/preset/files/app/routes/demos/params/index.tsx__tmpl__ +40 -0
  23. package/src/generators/preset/files/app/routes/demos/params.tsx__tmpl__ +43 -0
  24. package/src/generators/preset/files/app/routes/index.tsx__tmpl__ +100 -0
  25. package/src/generators/preset/files/app/styles/dark.css +7 -0
  26. package/src/generators/preset/files/app/styles/demos/about.css +26 -0
  27. package/src/generators/preset/files/app/styles/global.css +216 -0
  28. package/src/generators/preset/files/package.json__tmpl__ +29 -0
  29. package/src/generators/preset/files/public/favicon.ico +0 -0
  30. package/src/generators/preset/files/remix.config.js__tmpl__ +10 -0
  31. package/src/generators/preset/files/remix.env.d.ts__tmpl__ +2 -0
  32. package/src/generators/preset/files/tsconfig.json__tmpl__ +16 -0
  33. package/src/generators/preset/lib/normalize-options.d.ts +8 -0
  34. package/src/generators/preset/lib/normalize-options.js +17 -0
  35. package/src/generators/preset/lib/normalize-options.js.map +1 -0
  36. package/src/generators/preset/preset.impl.d.ts +3 -0
  37. package/src/generators/preset/preset.impl.js +28 -0
  38. package/src/generators/preset/preset.impl.js.map +1 -0
  39. package/src/generators/preset/schema.d.ts +4 -0
  40. package/src/generators/preset/schema.json +23 -0
  41. package/src/index.d.ts +0 -0
  42. package/src/index.js +1 -0
  43. package/src/index.js.map +1 -0
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # nx-remix
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Running unit tests
6
+
7
+ Run `nx test nx-remix` to execute the unit tests via [Jest](https://jestjs.io).
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "name": "NxRemix",
4
+ "version": "0.0.1",
5
+ "extends": ["@nrwl/react"],
6
+ "generators": {
7
+ "preset": {
8
+ "factory": "./src/generators/preset/preset.impl",
9
+ "schema": "./src/generators/preset/schema.json",
10
+ "description": "Generate a new remix workspace"
11
+ }
12
+ }
13
+ }
package/package.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@nrwl/remix",
3
+ "version": "1.0.0-alpha.1",
4
+ "main": "src/index.js",
5
+ "generators": "./generators.json",
6
+ "dependencies": {
7
+ "@nrwl/devkit": "^13.3.9",
8
+ "@nrwl/react": "^13.3.9",
9
+ "tslib": "^2.3.1"
10
+ },
11
+ "typings": "./src/index.d.ts"
12
+ }
@@ -0,0 +1,3 @@
1
+ import { GeneratorCallback, Tree } from '@nrwl/devkit';
2
+ import { NxRemixGeneratorSchema } from './schema';
3
+ export default function (tree: Tree, _options: NxRemixGeneratorSchema): Promise<GeneratorCallback>;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const devkit_1 = require("@nrwl/devkit");
5
+ const normalize_options_1 = require("./lib/normalize-options");
6
+ const run_tasks_in_serial_1 = require("@nrwl/workspace/src/utilities/run-tasks-in-serial");
7
+ const child_process_1 = require("child_process");
8
+ function default_1(tree, _options) {
9
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
10
+ const options = (0, normalize_options_1.normalizeOptions)(tree, _options);
11
+ const tasks = [];
12
+ (0, devkit_1.addProjectConfiguration)(tree, options.projectName, {
13
+ root: options.projectRoot,
14
+ projectType: 'library',
15
+ sourceRoot: `${options.projectRoot}/src`,
16
+ tags: options.parsedTags,
17
+ });
18
+ const installTask = (0, devkit_1.addDependenciesToPackageJson)(tree, {
19
+ '@remix-run/react': '^1.0.6',
20
+ react: '^17.0.2',
21
+ 'react-dom': '^17.0.2',
22
+ remix: '^1.0.6',
23
+ '@remix-run/serve': '^1.0.6',
24
+ }, {
25
+ '@remix-run/dev': '^1.0.6',
26
+ '@types/react': '^17.0.24',
27
+ '@types/react-dom': '^17.0.9',
28
+ typescript: '~4.4.3',
29
+ });
30
+ tasks.push(installTask);
31
+ (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files'), options.projectRoot, Object.assign(Object.assign({}, options), { tmpl: '' }));
32
+ tasks.push(() => {
33
+ (0, child_process_1.execSync)('npx remix setup', {
34
+ cwd: options.projectRoot,
35
+ stdio: [0, 1, 2],
36
+ });
37
+ });
38
+ if (!options.skipFormat) {
39
+ yield (0, devkit_1.formatFiles)(tree);
40
+ }
41
+ return (0, run_tasks_in_serial_1.runTasksInSerial)(...tasks);
42
+ });
43
+ }
44
+ exports.default = default_1;
45
+ //# sourceMappingURL=application.impl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"application.impl.js","sourceRoot":"","sources":["../../../../../../packages/nx-remix/src/generators/application/application.impl.ts"],"names":[],"mappings":";;;AAAA,yCAQsB;AAEtB,+DAA2D;AAC3D,2FAAqF;AACrF,iDAAyC;AAEzC,mBAA+B,IAAU,EAAE,QAAgC;;QACzE,MAAM,OAAO,GAAG,IAAA,oCAAgB,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACjD,MAAM,KAAK,GAAwB,EAAE,CAAC;QAEtC,IAAA,gCAAuB,EAAC,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE;YACjD,IAAI,EAAE,OAAO,CAAC,WAAW;YACzB,WAAW,EAAE,SAAS;YACtB,UAAU,EAAE,GAAG,OAAO,CAAC,WAAW,MAAM;YACxC,IAAI,EAAE,OAAO,CAAC,UAAU;SACzB,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,IAAA,qCAA4B,EAC9C,IAAI,EACJ;YACE,kBAAkB,EAAE,QAAQ;YAC5B,KAAK,EAAE,SAAS;YAChB,WAAW,EAAE,SAAS;YACtB,KAAK,EAAE,QAAQ;YACf,kBAAkB,EAAE,QAAQ;SAC7B,EACD;YACE,gBAAgB,EAAE,QAAQ;YAC1B,cAAc,EAAE,UAAU;YAC1B,kBAAkB,EAAE,SAAS;YAC7B,UAAU,EAAE,QAAQ;SACrB,CACF,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAExB,IAAA,sBAAa,EACX,IAAI,EACJ,IAAA,0BAAiB,EAAC,SAAS,EAAE,OAAO,CAAC,EACrC,OAAO,CAAC,WAAW,kCAEd,OAAO,KACV,IAAI,EAAE,EAAE,IAEX,CAAC;QAEF,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YACd,IAAA,wBAAQ,EAAC,iBAAiB,EAAE;gBAC1B,GAAG,EAAE,OAAO,CAAC,WAAW;gBACxB,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;aACjB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;YACvB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;SACzB;QAED,OAAO,IAAA,sCAAgB,EAAC,GAAG,KAAK,CAAC,CAAC;IACpC,CAAC;CAAA;AAnDD,4BAmDC"}
@@ -0,0 +1,8 @@
1
+ import { NxRemixGeneratorSchema } from '../schema';
2
+ import { Tree } from '@nrwl/devkit';
3
+ export interface NormalizedSchema extends NxRemixGeneratorSchema {
4
+ projectName: string;
5
+ projectRoot: string;
6
+ parsedTags: string[];
7
+ }
8
+ export declare function normalizeOptions(tree: Tree, options: NxRemixGeneratorSchema): NormalizedSchema;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeOptions = void 0;
4
+ const devkit_1 = require("@nrwl/devkit");
5
+ function normalizeOptions(tree, options) {
6
+ const name = (0, devkit_1.names)(options.name).fileName;
7
+ const projectName = name;
8
+ const projectRoot = `packages/${name}`;
9
+ const parsedTags = options.tags
10
+ ? options.tags.split(',').map((s) => s.trim())
11
+ : [];
12
+ return Object.assign(Object.assign({}, options), { projectName,
13
+ projectRoot,
14
+ parsedTags });
15
+ }
16
+ exports.normalizeOptions = normalizeOptions;
17
+ //# sourceMappingURL=normalize-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-options.js","sourceRoot":"","sources":["../../../../../../../packages/nx-remix/src/generators/application/lib/normalize-options.ts"],"names":[],"mappings":";;;AACA,yCAA2C;AAQ3C,SAAgB,gBAAgB,CAC9B,IAAU,EACV,OAA+B;IAE/B,MAAM,IAAI,GAAG,IAAA,cAAK,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC;IACzB,MAAM,WAAW,GAAG,YAAY,IAAI,EAAE,CAAC;IACvC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI;QAC7B,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,CAAC,CAAC,EAAE,CAAC;IAEP,uCACK,OAAO,KACV,WAAW;QACX,WAAW;QACX,UAAU,IACV;AACJ,CAAC;AAjBD,4CAiBC"}
@@ -0,0 +1,5 @@
1
+ export interface NxRemixGeneratorSchema {
2
+ name: string;
3
+ tags?: string;
4
+ skipFormat?: boolean;
5
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "cli": "nx",
4
+ "$id": "NxRemix",
5
+ "title": "",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "",
11
+ "$default": {
12
+ "$source": "argv",
13
+ "index": 0
14
+ },
15
+ "x-prompt": "What is the name of the application?"
16
+ },
17
+ "tags": {
18
+ "type": "string",
19
+ "description": "Add tags to the project (used for linting)",
20
+ "alias": "t"
21
+ },
22
+ "skipFormat": {
23
+ "type": "boolean",
24
+ "description": "Skip formatting files",
25
+ "default": "false"
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,53 @@
1
+ # Welcome to Remix!
2
+
3
+ - [Remix Docs](https://remix.run/docs)
4
+
5
+ ## Development
6
+
7
+ From your terminal:
8
+
9
+ ```sh
10
+ npm run dev
11
+ ```
12
+
13
+ This starts your app in development mode, rebuilding assets on file changes.
14
+
15
+ ## Deployment
16
+
17
+ First, build your app for production:
18
+
19
+ ```sh
20
+ npm run build
21
+ ```
22
+
23
+ Then run the app in production mode:
24
+
25
+ ```sh
26
+ npm start
27
+ ```
28
+
29
+ Now you'll need to pick a host to deploy it to.
30
+
31
+ ### DIY
32
+
33
+ If you're familiar with deploying node applications, the built-in Remix app server is production-ready.
34
+
35
+ Make sure to deploy the output of `remix build`
36
+
37
+ - `build/`
38
+ - `public/build/`
39
+
40
+ ### Using a Template
41
+
42
+ When you ran `npx create-remix@latest` there were a few choices for hosting. You can run that again to create a new project, then copy over your `app/` folder to the new project that's pre-configured for your target server.
43
+
44
+ ```sh
45
+ cd ..
46
+ # create a new project, and pick a pre-configured host
47
+ npx create-remix@latest
48
+ cd my-new-remix-app
49
+ # remove the new project's app (not the old one!)
50
+ rm -rf app
51
+ # copy your app over
52
+ cp -R ../my-old-remix-app/app app
53
+ ```
@@ -0,0 +1,4 @@
1
+ import { hydrate } from "react-dom";
2
+ import { RemixBrowser } from "remix";
3
+
4
+ hydrate(<RemixBrowser />, document);
@@ -0,0 +1,21 @@
1
+ import { renderToString } from "react-dom/server";
2
+ import { RemixServer } from "remix";
3
+ import type { EntryContext } from "remix";
4
+
5
+ export default function handleRequest(
6
+ request: Request,
7
+ responseStatusCode: number,
8
+ responseHeaders: Headers,
9
+ remixContext: EntryContext
10
+ ) {
11
+ let markup = renderToString(
12
+ <RemixServer context={remixContext} url={request.url} />
13
+ );
14
+
15
+ responseHeaders.set("Content-Type", "text/html");
16
+
17
+ return new Response("<!DOCTYPE html>" + markup, {
18
+ status: responseStatusCode,
19
+ headers: responseHeaders
20
+ });
21
+ }
@@ -0,0 +1,178 @@
1
+ import {
2
+ Link,
3
+ Links,
4
+ LiveReload,
5
+ Meta,
6
+ Outlet,
7
+ Scripts,
8
+ ScrollRestoration,
9
+ useCatch
10
+ } from "remix";
11
+ import type { LinksFunction } from "remix";
12
+
13
+ import globalStylesUrl from "./styles/global.css";
14
+ import darkStylesUrl from "./styles/dark.css";
15
+
16
+ // https://remix.run/api/app#links
17
+ export let links: LinksFunction = () => {
18
+ return [
19
+ { rel: "stylesheet", href: globalStylesUrl },
20
+ {
21
+ rel: "stylesheet",
22
+ href: darkStylesUrl,
23
+ media: "(prefers-color-scheme: dark)"
24
+ }
25
+ ];
26
+ };
27
+
28
+ // https://remix.run/api/conventions#default-export
29
+ // https://remix.run/api/conventions#route-filenames
30
+ export default function App() {
31
+ return (
32
+ <Document>
33
+ <Layout>
34
+ <Outlet />
35
+ </Layout>
36
+ </Document>
37
+ );
38
+ }
39
+
40
+ // https://remix.run/docs/en/v1/api/conventions#errorboundary
41
+ export function ErrorBoundary({ error }: { error: Error }) {
42
+ console.error(error);
43
+ return (
44
+ <Document title="Error!">
45
+ <Layout>
46
+ <div>
47
+ <h1>There was an error</h1>
48
+ <p>{error.message}</p>
49
+ <hr />
50
+ <p>
51
+ Hey, developer, you should replace this with what you want your
52
+ users to see.
53
+ </p>
54
+ </div>
55
+ </Layout>
56
+ </Document>
57
+ );
58
+ }
59
+
60
+ // https://remix.run/docs/en/v1/api/conventions#catchboundary
61
+ export function CatchBoundary() {
62
+ let caught = useCatch();
63
+
64
+ let message;
65
+ switch (caught.status) {
66
+ case 401:
67
+ message = (
68
+ <p>
69
+ Oops! Looks like you tried to visit a page that you do not have access
70
+ to.
71
+ </p>
72
+ );
73
+ break;
74
+ case 404:
75
+ message = (
76
+ <p>Oops! Looks like you tried to visit a page that does not exist.</p>
77
+ );
78
+ break;
79
+
80
+ default:
81
+ throw new Error(caught.data || caught.statusText);
82
+ }
83
+
84
+ return (
85
+ <Document title={`${caught.status} ${caught.statusText}`}>
86
+ <Layout>
87
+ <h1>
88
+ {caught.status}: {caught.statusText}
89
+ </h1>
90
+ {message}
91
+ </Layout>
92
+ </Document>
93
+ );
94
+ }
95
+
96
+ function Document({
97
+ children,
98
+ title
99
+ }: {
100
+ children: React.ReactNode;
101
+ title?: string;
102
+ }) {
103
+ return (
104
+ <html lang="en">
105
+ <head>
106
+ <meta charSet="utf-8" />
107
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
108
+ {title ? <title>{title}</title> : null}
109
+ <Meta />
110
+ <Links />
111
+ </head>
112
+ <body>
113
+ {children}
114
+ <ScrollRestoration />
115
+ <Scripts />
116
+ {process.env.NODE_ENV === "development" && <LiveReload />}
117
+ </body>
118
+ </html>
119
+ );
120
+ }
121
+
122
+ function Layout({ children }: { children: React.ReactNode }) {
123
+ return (
124
+ <div className="remix-app">
125
+ <header className="remix-app__header">
126
+ <div className="container remix-app__header-content">
127
+ <Link to="/" title="Remix" className="remix-app__header-home-link">
128
+ <RemixLogo />
129
+ </Link>
130
+ <nav aria-label="Main navigation" className="remix-app__header-nav">
131
+ <ul>
132
+ <li>
133
+ <Link to="/">Home</Link>
134
+ </li>
135
+ <li>
136
+ <a href="https://remix.run/docs">Remix Docs</a>
137
+ </li>
138
+ <li>
139
+ <a href="https://github.com/remix-run/remix">GitHub</a>
140
+ </li>
141
+ </ul>
142
+ </nav>
143
+ </div>
144
+ </header>
145
+ <div className="remix-app__main">
146
+ <div className="container remix-app__main-content">{children}</div>
147
+ </div>
148
+ <footer className="remix-app__footer">
149
+ <div className="container remix-app__footer-content">
150
+ <p>&copy; You!</p>
151
+ </div>
152
+ </footer>
153
+ </div>
154
+ );
155
+ }
156
+
157
+ function RemixLogo() {
158
+ return (
159
+ <svg
160
+ viewBox="0 0 659 165"
161
+ version="1.1"
162
+ xmlns="http://www.w3.org/2000/svg"
163
+ xmlnsXlink="http://www.w3.org/1999/xlink"
164
+ aria-labelledby="remix-run-logo-title"
165
+ role="img"
166
+ width="106"
167
+ height="30"
168
+ fill="currentColor"
169
+ >
170
+ <title id="remix-run-logo-title">Remix Logo</title>
171
+ <path d="M0 161V136H45.5416C53.1486 136 54.8003 141.638 54.8003 145V161H0Z M133.85 124.16C135.3 142.762 135.3 151.482 135.3 161H92.2283C92.2283 158.927 92.2653 157.03 92.3028 155.107C92.4195 149.128 92.5411 142.894 91.5717 130.304C90.2905 111.872 82.3473 107.776 67.7419 107.776H54.8021H0V74.24H69.7918C88.2407 74.24 97.4651 68.632 97.4651 53.784C97.4651 40.728 88.2407 32.816 69.7918 32.816H0V0H77.4788C119.245 0 140 19.712 140 51.2C140 74.752 125.395 90.112 105.665 92.672C122.32 96 132.057 105.472 133.85 124.16Z" />
172
+ <path d="M229.43 120.576C225.59 129.536 218.422 133.376 207.158 133.376C194.614 133.376 184.374 126.72 183.35 112.64H263.478V101.12C263.478 70.1437 243.254 44.0317 205.11 44.0317C169.526 44.0317 142.902 69.8877 142.902 105.984C142.902 142.336 169.014 164.352 205.622 164.352C235.83 164.352 256.822 149.76 262.71 123.648L229.43 120.576ZM183.862 92.6717C185.398 81.9197 191.286 73.7277 204.598 73.7277C216.886 73.7277 223.542 82.4317 224.054 92.6717H183.862Z" />
173
+ <path d="M385.256 66.5597C380.392 53.2477 369.896 44.0317 349.672 44.0317C332.52 44.0317 320.232 51.7117 314.088 64.2557V47.1037H272.616V161.28H314.088V105.216C314.088 88.0638 318.952 76.7997 332.52 76.7997C345.064 76.7997 348.136 84.9917 348.136 100.608V161.28H389.608V105.216C389.608 88.0638 394.216 76.7997 408.04 76.7997C420.584 76.7997 423.4 84.9917 423.4 100.608V161.28H464.872V89.5997C464.872 65.7917 455.656 44.0317 424.168 44.0317C404.968 44.0317 391.4 53.7597 385.256 66.5597Z" />
174
+ <path d="M478.436 47.104V161.28H519.908V47.104H478.436ZM478.18 36.352H520.164V0H478.18V36.352Z" />
175
+ <path d="M654.54 47.1035H611.788L592.332 74.2395L573.388 47.1035H527.564L568.78 103.168L523.98 161.28H566.732L589.516 130.304L612.3 161.28H658.124L613.068 101.376L654.54 47.1035Z" />
176
+ </svg>
177
+ );
178
+ }
@@ -0,0 +1,17 @@
1
+ import { Link } from "remix";
2
+
3
+ export default function AboutIndex() {
4
+ return (
5
+ <div>
6
+ <p>
7
+ You are looking at the index route for the <code>/about</code> URL
8
+ segment, but there are nested routes as well!
9
+ </p>
10
+ <p>
11
+ <strong>
12
+ <Link to="whoa">Check out one of them here.</Link>
13
+ </strong>
14
+ </p>
15
+ </div>
16
+ );
17
+ }
@@ -0,0 +1,20 @@
1
+ import { Link } from "remix";
2
+
3
+ export default function AboutIndex() {
4
+ return (
5
+ <div>
6
+ <p>
7
+ Whoa, this is a nested route! We render the <code>/about</code> layout
8
+ route component, and its <code>Outlet</code> renders our route
9
+ component. 🤯
10
+ </p>
11
+ <p>
12
+ <strong>
13
+ <Link to="..">
14
+ Go back to the <code>/about</code> index.
15
+ </Link>
16
+ </strong>
17
+ </p>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,44 @@
1
+ import { Outlet } from "remix";
2
+ import type { MetaFunction, LinksFunction } from "remix";
3
+
4
+ import stylesUrl from "../../styles/demos/about.css";
5
+
6
+ export let meta: MetaFunction = () => {
7
+ return {
8
+ title: "About Remix"
9
+ };
10
+ };
11
+
12
+ export let links: LinksFunction = () => {
13
+ return [{ rel: "stylesheet", href: stylesUrl }];
14
+ };
15
+
16
+ export default function Index() {
17
+ return (
18
+ <div className="about">
19
+ <div className="about__intro">
20
+ <h2>About Us</h2>
21
+ <p>
22
+ Ok, so this page isn't really <em>about us</em>, but we did want to
23
+ show you a few more things Remix can do.
24
+ </p>
25
+ <p>
26
+ Did you notice that things look a little different on this page? The
27
+ CSS that we import in the route file and include in its{" "}
28
+ <code>links</code> export is only included on this route and its
29
+ children.
30
+ </p>
31
+ <p>
32
+ Wait a sec...<em>its children</em>? To understand what we mean by
33
+ this,{" "}
34
+ <a href="https://remix.run/tutorial/4-nested-routes-params">
35
+ read all about nested routes in the docs
36
+ </a>
37
+ .
38
+ </p>
39
+ <hr />
40
+ <Outlet />
41
+ </div>
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,101 @@
1
+ import { useEffect, useRef } from "react";
2
+ import type { ActionFunction } from "remix";
3
+ import { Form, json, useActionData, redirect } from "remix";
4
+
5
+ export function meta() {
6
+ return { title: "Actions Demo" };
7
+ }
8
+
9
+ // When your form sends a POST, the action is called on the server.
10
+ // - https://remix.run/api/conventions#action
11
+ // - https://remix.run/guides/data-updates
12
+ export let action: ActionFunction = async ({ request }) => {
13
+ let formData = await request.formData();
14
+ let answer = formData.get("answer");
15
+
16
+ // Typical action workflows start with validating the form data that just came
17
+ // over the network. Clientside validation is fine, but you definitely need it
18
+ // server side. If there's a problem, return the the data and the component
19
+ // can render it.
20
+ if (typeof answer !== "string") {
21
+ return json("Come on, at least try!", { status: 400 });
22
+ }
23
+
24
+ if (answer !== "egg") {
25
+ return json(`Sorry, ${answer} is not right.`, { status: 400 });
26
+ }
27
+
28
+ // Finally, if the data is valid, you'll typically write to a database or send or
29
+ // email or log the user in, etc. It's recommended to redirect after a
30
+ // successful action, even if it's to the same place so that non-JavaScript workflows
31
+ // from the browser doesn't repost the data if the user clicks back.
32
+ return redirect("/demos/correct");
33
+ };
34
+
35
+ export default function ActionsDemo() {
36
+ // https://remix.run/api/remix#useactiondata
37
+ let actionMessage = useActionData<string>();
38
+ let answerRef = useRef<HTMLInputElement>(null);
39
+
40
+ // This form works without JavaScript, but when we have JavaScript we can make
41
+ // the experience better by selecting the input on wrong answers! Go ahead, disable
42
+ // JavaScript in your browser and see what happens.
43
+ useEffect(() => {
44
+ if (actionMessage && answerRef.current) {
45
+ answerRef.current.select();
46
+ }
47
+ }, [actionMessage]);
48
+
49
+ return (
50
+ <div className="remix__page">
51
+ <main>
52
+ <h2>Actions!</h2>
53
+ <p>
54
+ This form submission will send a post request that we handle in our
55
+ `action` export. Any route can export an action to handle data
56
+ mutations.
57
+ </p>
58
+ <Form method="post" className="remix__form">
59
+ <h3>Post an Action</h3>
60
+ <p>
61
+ <i>What is more useful when it is broken?</i>
62
+ </p>
63
+ <label>
64
+ <div>Answer:</div>
65
+ <input ref={answerRef} name="answer" type="text" />
66
+ </label>
67
+ <div>
68
+ <button>Answer!</button>
69
+ </div>
70
+ {actionMessage ? (
71
+ <p>
72
+ <b>{actionMessage}</b>
73
+ </p>
74
+ ) : null}
75
+ </Form>
76
+ </main>
77
+
78
+ <aside>
79
+ <h3>Additional Resources</h3>
80
+ <ul>
81
+ <li>
82
+ Guide:{" "}
83
+ <a href="https://remix.run/guides/data-writes">Data Writes</a>
84
+ </li>
85
+ <li>
86
+ API:{" "}
87
+ <a href="https://remix.run/api/conventions#action">
88
+ Route Action Export
89
+ </a>
90
+ </li>
91
+ <li>
92
+ API:{" "}
93
+ <a href="https://remix.run/api/remix#useactiondata">
94
+ <code>useActionData</code>
95
+ </a>
96
+ </li>
97
+ </ul>
98
+ </aside>
99
+ </div>
100
+ );
101
+ }
@@ -0,0 +1,3 @@
1
+ export default function NiceWork() {
2
+ return <h1>You got it right!</h1>;
3
+ }