-
-
Notifications
You must be signed in to change notification settings - Fork 755
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial CMSUI baseline, for PoCs and testing
- Loading branch information
Showing
27 changed files
with
1,353 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* This is intended to be a basic starting point for linting in your app. | ||
* It relies on recommended configs out of the box for simplicity, but you can | ||
* and should modify this configuration to best suit your team's needs. | ||
*/ | ||
|
||
/** @type {import('eslint').Linter.Config} */ | ||
module.exports = { | ||
root: true, | ||
parserOptions: { | ||
ecmaVersion: 'latest', | ||
sourceType: 'module', | ||
ecmaFeatures: { | ||
jsx: true, | ||
}, | ||
}, | ||
env: { | ||
browser: true, | ||
commonjs: true, | ||
es6: true, | ||
}, | ||
|
||
// Base config | ||
extends: ['eslint:recommended', 'plugin:storybook/recommended'], | ||
|
||
// Ignore Cypress folder | ||
ignorePatterns: ['cypress/', '.react-router/**/*', 'registry.config.ts'], | ||
|
||
overrides: [ | ||
// React | ||
{ | ||
files: ['**/*.{js,jsx,ts,tsx}'], | ||
plugins: ['react', 'jsx-a11y'], | ||
extends: [ | ||
'plugin:react/recommended', | ||
'plugin:react/jsx-runtime', | ||
'plugin:react-hooks/recommended', | ||
'plugin:jsx-a11y/recommended', | ||
], | ||
settings: { | ||
react: { | ||
version: 'detect', | ||
}, | ||
'import/core-modules': ['@plone/registry/addons-loader'], | ||
formComponents: ['Form'], | ||
linkComponents: [ | ||
{ name: 'Link', linkAttribute: 'to' }, | ||
{ name: 'NavLink', linkAttribute: 'to' }, | ||
], | ||
}, | ||
}, | ||
|
||
// Typescript | ||
{ | ||
files: ['**/*.{ts,tsx}'], | ||
plugins: ['@typescript-eslint', 'import'], | ||
parser: '@typescript-eslint/parser', | ||
settings: { | ||
'import/internal-regex': '^~/', | ||
'import/resolver': { | ||
node: { | ||
extensions: ['.ts', '.tsx'], | ||
}, | ||
typescript: { | ||
alwaysTryTypes: true, | ||
}, | ||
}, | ||
}, | ||
extends: [ | ||
'plugin:@typescript-eslint/recommended', | ||
'plugin:import/recommended', | ||
'plugin:import/typescript', | ||
], | ||
}, | ||
|
||
// Node | ||
{ | ||
files: ['.eslintrc.js'], | ||
env: { | ||
node: true, | ||
}, | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.DS_Store | ||
/node_modules/ | ||
|
||
# React Router | ||
/.react-router/ | ||
/build/ | ||
|
||
registry.loader.js | ||
addons.styles.css |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"trailingComma": "all", | ||
"singleQuote": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"extends": ["stylelint-config-idiomatic-order"], | ||
"plugins": ["stylelint-prettier"], | ||
"rules": { | ||
"prettier/prettier": true, | ||
"order/properties-alphabetical-order": null | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# Welcome to React Router! | ||
|
||
A modern, production-ready template for building full-stack React applications using React Router. | ||
|
||
[](https://stackblitz.com/github/remix-run/react-router-templates/tree/main/default) | ||
|
||
## Features | ||
|
||
- 🚀 Server-side rendering | ||
- ⚡️ Hot Module Replacement (HMR) | ||
- 📦 Asset bundling and optimization | ||
- 🔄 Data loading and mutations | ||
- 🔒 TypeScript by default | ||
- 🎉 TailwindCSS for styling | ||
- 📖 [React Router docs](https://reactrouter.com/) | ||
|
||
## Getting Started | ||
|
||
### Installation | ||
|
||
Install the dependencies: | ||
|
||
```bash | ||
npm install | ||
``` | ||
|
||
### Development | ||
|
||
Start the development server with HMR: | ||
|
||
```bash | ||
npm run dev | ||
``` | ||
|
||
Your application will be available at `http://localhost:5173`. | ||
|
||
## Building for Production | ||
|
||
Create a production build: | ||
|
||
```bash | ||
npm run build | ||
``` | ||
|
||
## Deployment | ||
|
||
### Docker Deployment | ||
|
||
This template includes three Dockerfiles optimized for different package managers: | ||
|
||
- `Dockerfile` - for npm | ||
- `Dockerfile.pnpm` - for pnpm | ||
- `Dockerfile.bun` - for bun | ||
|
||
To build and run using Docker: | ||
|
||
```bash | ||
# For npm | ||
docker build -t my-app . | ||
|
||
# For pnpm | ||
docker build -f Dockerfile.pnpm -t my-app . | ||
|
||
# For bun | ||
docker build -f Dockerfile.bun -t my-app . | ||
|
||
# Run the container | ||
docker run -p 3000:3000 my-app | ||
``` | ||
|
||
The containerized application can be deployed to any platform that supports Docker, including: | ||
|
||
- AWS ECS | ||
- Google Cloud Run | ||
- Azure Container Apps | ||
- Digital Ocean App Platform | ||
- Fly.io | ||
- Railway | ||
|
||
### DIY Deployment | ||
|
||
If you're familiar with deploying Node applications, the built-in app server is production-ready. | ||
|
||
Make sure to deploy the output of `npm run build` | ||
|
||
``` | ||
├── package.json | ||
├── package-lock.json (or pnpm-lock.yaml, or bun.lockb) | ||
├── build/ | ||
│ ├── client/ # Static assets | ||
│ └── server/ # Server-side code | ||
``` | ||
|
||
## Styling | ||
|
||
This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever CSS framework you prefer. | ||
|
||
--- | ||
|
||
Built with ❤️ using React Router. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
@layer theme, base, components, plone-components, utilities, custom; /* Add custom layer before tailwind defines them */ | ||
@import 'tailwindcss'; | ||
@import '../addons.styles.css'; | ||
|
||
html, | ||
body { | ||
@apply bg-white dark:bg-gray-950; | ||
|
||
@media (prefers-color-scheme: dark) { | ||
color-scheme: dark; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { createCookie, redirect } from 'react-router'; | ||
import type { Route } from './+types/login'; | ||
|
||
let secret = process.env.COOKIE_SECRET || 'default'; | ||
if (secret === 'default') { | ||
console.warn( | ||
'🚨 No COOKIE_SECRET environment variable set, using default. The app is insecure in production.', | ||
); | ||
secret = 'default-secret'; | ||
} | ||
|
||
const cookie = createCookie('auth_seven', { | ||
secrets: [secret], | ||
// 30 days | ||
maxAge: 30 * 24 * 60 * 60, | ||
httpOnly: true, | ||
secure: process.env.NODE_ENV === 'production', | ||
sameSite: 'lax', | ||
}); | ||
|
||
export async function getAuthFromRequest(request: Request): Promise { | ||
let token; | ||
try { | ||
token = await cookie.parse(request.headers.get('Cookie')); | ||
} catch (error) { | ||
// asd | ||
} | ||
return token ?? null; | ||
} | ||
|
||
export async function setAuthOnResponse( | ||
response: Response, | ||
token: string, | ||
): Promise { | ||
const header = await cookie.serialize(token); | ||
response.headers.append('Set-Cookie', header); | ||
return response; | ||
} | ||
|
||
export async function requireAuthCookie(request: Request) { | ||
const token = await getAuthFromRequest(request); | ||
if (!token) { | ||
throw redirect('/login', { | ||
headers: { | ||
'Set-Cookie': await cookie.serialize('', { | ||
maxAge: 0, | ||
}), | ||
}, | ||
}); | ||
} | ||
return token; | ||
} | ||
|
||
export async function redirectIfLoggedInLoader({ request }: Route.LoaderArgs) { | ||
const token = await getAuthFromRequest(request); | ||
if (token) { | ||
throw redirect('/'); | ||
} | ||
return null; | ||
} | ||
|
||
export async function redirectWithClearedCookie(): Promise { | ||
return redirect('/', { | ||
headers: { | ||
'Set-Cookie': await cookie.serialize(null, { | ||
expires: new Date(0), | ||
}), | ||
}, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import type { Route } from './+types/login'; | ||
import { data, Form, Link, useActionData, redirect } from 'react-router'; | ||
|
||
import { redirectIfLoggedInLoader, setAuthOnResponse } from './auth'; | ||
import { Button, TextField } from '@plone/components'; | ||
|
||
import PloneClient from '@plone/client'; | ||
import config from '@plone/registry'; | ||
|
||
export const loader = redirectIfLoggedInLoader; | ||
|
||
export const meta = () => { | ||
return [{ title: 'Plone Login' }]; | ||
}; | ||
|
||
export async function action({ request }: Route.ActionArgs) { | ||
const formData = await request.formData(); | ||
const username = String(formData.get('username') || ''); | ||
const password = String(formData.get('password') || ''); | ||
|
||
const ploneClient = config | ||
.getUtility({ | ||
name: 'ploneClient', | ||
type: 'client', | ||
}) | ||
.method(); | ||
|
||
const { login } = ploneClient as PloneClient; | ||
|
||
const token = await login({ username, password }); | ||
if (!token) { | ||
return data( | ||
{ ok: false, errors: { password: 'Invalid credentials' } }, | ||
400, | ||
); | ||
} | ||
|
||
const response = redirect('/'); | ||
return setAuthOnResponse(response, token); | ||
} | ||
|
||
export default function Login() { | ||
const actionResult = useActionData<typeof action>(); | ||
|
||
return ( | ||
<div className="mt-20 flex min-h-full flex-1 flex-col sm:px-6 lg:px-8"> | ||
<div className="sm:mx-auto sm:w-full sm:max-w-md"> | ||
<h2 | ||
id="login-header" | ||
className="mt-6 text-center text-2xl leading-9 font-bold tracking-tight text-gray-900" | ||
> | ||
Log in | ||
</h2> | ||
</div> | ||
|
||
<div className="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px]"> | ||
<div className="bg-white px-6 py-12 shadow sm:rounded-lg sm:px-12"> | ||
<Form className="space-y-6" method="post"> | ||
<div> | ||
<TextField | ||
autoFocus | ||
id="username" | ||
name="username" | ||
aria-describedby={ | ||
actionResult?.errors?.email ? 'email-error' : 'login-header' | ||
} | ||
isRequired | ||
/> | ||
</div> | ||
|
||
<div> | ||
<TextField | ||
id="password" | ||
name="password" | ||
type="password" | ||
autoComplete="current-password" | ||
aria-describedby="password-error" | ||
isRequired | ||
/> | ||
</div> | ||
|
||
<div> | ||
<Button type="submit">Sign in</Button> | ||
</div> | ||
</Form> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.