https://github.com/keycloakify/keycloakify-starter/pull/6 https://github.com/keycloakify/keycloakify/pull/324 https://github.com/keycloakify/keycloakify-starter/pull/5 https://github.com/keycloakify/keycloakify/issues/271
This commit is contained in:
parent
a41354b740
commit
8e0c62cf84
29
.eslintrc.cjs
Normal file
29
.eslintrc.cjs
Normal file
|
@ -0,0 +1,29 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
'react-hooks/exhaustive-deps': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'off',
|
||||
'no-labels': 'off',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.stories.*'],
|
||||
rules: {
|
||||
'import/no-anonymous-default-export': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
module.exports = {
|
||||
"stories": [
|
||||
"../src/**/*.stories.tsx",
|
||||
],
|
||||
"addons": [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-interactions",
|
||||
"@storybook/preset-create-react-app"
|
||||
],
|
||||
"framework": "@storybook/react",
|
||||
"core": {
|
||||
"builder": "@storybook/builder-webpack5"
|
||||
},
|
||||
"staticDirs": ['../public']
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
export const parameters = {
|
||||
actions: {argTypesRegex: "^on[A-Z].*"},
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
options: {
|
||||
storySort: (a, b) =>
|
||||
a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, undefined, {numeric: true}),
|
||||
},
|
||||
}
|
|
@ -8,6 +8,6 @@ RUN yarn build
|
|||
|
||||
# production environment
|
||||
FROM nginx:stable-alpine
|
||||
COPY --from=build /app/build /usr/share/nginx/html
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
COPY --from=build /app/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
CMD nginx -g 'daemon off;'
|
|
@ -14,9 +14,6 @@ This repo constitutes an easily reusable setup for a Keycloak theme project OR f
|
|||
Keycloak theme that goes along with it.
|
||||
If you are only looking to create a Keycloak theme (and not a Keycloak theme and an App that share the same codebase) there are a lot of things that you can remove from this starter: [Please read this section of the README](#standalone-keycloak-theme).
|
||||
|
||||
> ❗️ WARNING ❗️: Don't waste time trying to port this setup to [Vite](https://vitejs.dev/).
|
||||
> Currently Keycloakify only works collocated with Webpack projects but [we are working toward enabling collocation with Vite](https://github.com/keycloakify/keycloakify/pull/275)!
|
||||
|
||||
# Quick start
|
||||
|
||||
```bash
|
||||
|
@ -32,7 +29,7 @@ yarn storybook # Start Storybook
|
|||
# You can create stories even for pages that you haven't explicitly overloaded. See src/keycloak-theme/login/pages/LoginResetPassword.stories.tsx
|
||||
# See Keycloakify's storybook for if you need a starting point for your stories: https://github.com/keycloakify/keycloakify/tree/main/stories
|
||||
|
||||
yarn start # See the Hello World app
|
||||
yarn dev # See the Hello World app
|
||||
# Uncomment line 97 of src/keycloak-theme/login/kcContext where it reads: `mockPageId: "login.ftl"`, reload https://localhost:3000
|
||||
# You can now see the login.ftl page with the mock data. (Don't forget to comment it back when you're done)
|
||||
|
||||
|
|
76
index.html
Normal file
76
index.html
Normal file
|
@ -0,0 +1,76 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<!--
|
||||
Notice the use of %BASE_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%BASE_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
-->
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="%BASE_URL%/favicon-32x32.png">
|
||||
|
||||
<title>Keycloakify starter</title>
|
||||
|
||||
<link rel="preload" href="%BASE_URL%/fonts/WorkSans/worksans-bold-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<link rel="preload" href="%BASE_URL%/fonts/WorkSans/worksans-medium-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<link rel="preload" href="%BASE_URL%/fonts/WorkSans/worksans-regular-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<link rel="preload" href="%BASE_URL%/fonts/WorkSans/worksans-semibold-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<!-- SEE: https://docs.keycloakify.dev/limitations#self-hosted-fonts -->
|
||||
<!-- Don't forget to import your custom fonts in Storybook as well: https://github.com/keycloakify/keycloakify-starter/blob/bb019e66fb09166cb9af1e24e230994f59daa420/src/keycloak-theme/login/createPageStory.tsx#L21 -->
|
||||
<style>
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
/*400*/
|
||||
font-display: swap;
|
||||
src: url("%BASE_URL%/fonts/WorkSans/worksans-regular-webfont.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("%BASE_URL%/fonts/WorkSans/worksans-medium-webfont.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("%BASE_URL%/fonts/WorkSans/worksans-semibold-webfont.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
/*700*/
|
||||
font-display: swap;
|
||||
src: url("%BASE_URL%/fonts/WorkSans/worksans-bold-webfont.woff2") format("woff2");
|
||||
}
|
||||
</style>
|
||||
|
||||
<meta name="keycloakify-ignore-start">
|
||||
<script>console.log("This is logged Only in the main app, stripped out in the theme")</script>
|
||||
<meta name="keycloakify-ignore-end">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
72
package.json
72
package.json
|
@ -9,10 +9,9 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "copy-keycloak-resources-to-public",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"build-keycloak-theme": "yarn build && keycloakify",
|
||||
"storybook": "start-storybook -p 6006"
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"build-keycloak-theme": "yarn build && keycloakify"
|
||||
},
|
||||
"keycloakify": {
|
||||
"themeName": "keycloakify-starter",
|
||||
|
@ -28,59 +27,22 @@
|
|||
"oidc-spa": "^4.0.0",
|
||||
"keycloakify": "^9.2.0",
|
||||
"powerhooks": "^1.0.8",
|
||||
"react": "18.1.0",
|
||||
"react-dom": "18.1.0",
|
||||
"tsafe": "^1.6.6",
|
||||
"zod": "^3.22.4"
|
||||
"zod": "^3.22.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^15.3.1",
|
||||
"@types/react": "18.0.9",
|
||||
"@types/react-dom": "18.0.4",
|
||||
"react-scripts": "5.0.1",
|
||||
"typescript": "~4.7.0",
|
||||
"@storybook/addon-actions": "^6.5.16",
|
||||
"@storybook/addon-essentials": "^6.5.16",
|
||||
"@storybook/addon-interactions": "^6.5.16",
|
||||
"@storybook/addon-links": "^6.5.16",
|
||||
"@storybook/builder-webpack5": "^6.5.16",
|
||||
"@storybook/manager-webpack5": "^6.5.16",
|
||||
"@storybook/node-logger": "^6.5.16",
|
||||
"@storybook/preset-create-react-app": "^4.1.2",
|
||||
"@storybook/react": "^6.5.16",
|
||||
"@storybook/testing-library": "^0.0.13"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
],
|
||||
"rules": {
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"@typescript-eslint/no-redeclare": "off",
|
||||
"no-labels": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"**/*.stories.*"
|
||||
],
|
||||
"rules": {
|
||||
"import/no-anonymous-default-export": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
"@types/react": "^18.2.43",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||
"@typescript-eslint/parser": "^6.14.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.0.8",
|
||||
"vite-plugin-commonjs": "^0.10.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png">
|
||||
|
||||
<title>Keycloakify starter</title>
|
||||
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/WorkSans/worksans-bold-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/WorkSans/worksans-medium-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/WorkSans/worksans-regular-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<link rel="preload" href="%PUBLIC_URL%/fonts/WorkSans/worksans-semibold-webfont.woff2" as="font" crossorigin="anonymous">
|
||||
<!-- SEE: https://docs.keycloakify.dev/limitations#self-hosted-fonts -->
|
||||
<!-- Don't forget to import your custom fonts in Storybook as well: https://github.com/keycloakify/keycloakify-starter/blob/bb019e66fb09166cb9af1e24e230994f59daa420/src/keycloak-theme/login/createPageStory.tsx#L21 -->
|
||||
<style>
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
/*400*/
|
||||
font-display: swap;
|
||||
src: url("%PUBLIC_URL%/fonts/WorkSans/worksans-regular-webfont.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("%PUBLIC_URL%/fonts/WorkSans/worksans-medium-webfont.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("%PUBLIC_URL%/fonts/WorkSans/worksans-semibold-webfont.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Work Sans';
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
/*700*/
|
||||
font-display: swap;
|
||||
src: url("%PUBLIC_URL%/fonts/WorkSans/worksans-bold-webfont.woff2") format("woff2");
|
||||
}
|
||||
</style>
|
||||
|
||||
<meta name="keycloakify-ignore-start">
|
||||
<script>console.log("This is logged Only in the main app, stripped out in the theme")</script>
|
||||
<meta name="keycloakify-ignore-end">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -3,12 +3,12 @@ import { kcContext as kcLoginThemeContext } from "keycloak-theme/login/kcContext
|
|||
import { kcContext as kcAccountThemeContext } from "keycloak-theme/login/kcContext";
|
||||
|
||||
/**
|
||||
* If you need to use process.env.PUBLIC_URL, use this variable instead.
|
||||
* If you need to use import.meta.env.BASE_URL, use this variable instead.
|
||||
* If you can, import your assets using the import statement.
|
||||
*
|
||||
* See: https://docs.keycloakify.dev/importing-assets#importing-custom-assets-that-arent-fonts
|
||||
*/
|
||||
export const PUBLIC_URL = (()=>{
|
||||
export const BASE_URL = (()=>{
|
||||
|
||||
const kcContext = (()=>{
|
||||
|
||||
|
@ -25,7 +25,7 @@ export const PUBLIC_URL = (()=>{
|
|||
})();
|
||||
|
||||
return (kcContext === undefined || process.env.NODE_ENV === "development")
|
||||
? process.env.PUBLIC_URL
|
||||
? import.meta.env.BASE_URL
|
||||
: `${kcContext.url.resourcesPath}/build`;
|
||||
|
||||
})();
|
|
@ -32,3 +32,4 @@ createRoot(document.getElementById("root")!).render(
|
|||
</Suspense>
|
||||
</StrictMode>
|
||||
);
|
||||
|
3
src/react-app-env.d.ts → src/vite-env.d.ts
vendored
3
src/react-app-env.d.ts → src/vite-env.d.ts
vendored
|
@ -1,4 +1,5 @@
|
|||
/// <reference types="react-scripts" />
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module "*.md" {
|
||||
const src: string;
|
||||
export default src;
|
|
@ -1,21 +1,25 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"baseUrl": "src",
|
||||
"allowJs": true,
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
|
|
10
tsconfig.node.json
Normal file
10
tsconfig.node.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
10
vite.config.ts
Normal file
10
vite.config.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
// NOTE: This is just for the Keycloakify core contributors to be able to dynamically link
|
||||
// to a local version of the keycloakify package. This is not needed for normal usage.
|
||||
import commonjs from "vite-plugin-commonjs";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react(), commonjs()],
|
||||
})
|
Loading…
Reference in a new issue