mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-10-26 00:56:09 +02:00
Integrate tailwind css and create new button library (#2098)
Introduce tailwind as new frontend styling library to replace bulma in the longer run. Also create the first new ui library `ui-buttons` which will be the new standard for buttons ins SCM-Manager. In this library we reconsidered which types of buttons should be used to create a clean and consistent ui. Co-authored-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com>
This commit is contained in:
committed by
GitHub
parent
09beb8cd3b
commit
27dbcbf28d
1
.gitignore
vendored
1
.gitignore
vendored
@@ -40,3 +40,4 @@ rebel.xml
|
||||
.cache
|
||||
|
||||
.turbo
|
||||
storybook-static
|
||||
|
||||
@@ -18,20 +18,21 @@
|
||||
"set-version": "ui-scripts version"
|
||||
},
|
||||
"dependencies": {
|
||||
"@scm-manager/eslint-config": "^2.15.1"
|
||||
"@scm-manager/eslint-config": "2.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/remark-preset-lint": "^1.0.0",
|
||||
"babel-plugin-reflow": "^0.2.7",
|
||||
"cross-env": "^7.0.3",
|
||||
"husky": "^4.2.5",
|
||||
"lint-staged": "^10.2.11",
|
||||
"remark-cli": "^9.0.0",
|
||||
"turbo": "^1.2.5",
|
||||
"cross-env": "^7.0.3"
|
||||
"turbo": "^1.2.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"gitdiff-parser": "https://github.com/scm-manager/gitdiff-parser#420d6cfa17a6a8f9bf1a517a2c629dcb332dbe13"
|
||||
"gitdiff-parser": "https://github.com/scm-manager/gitdiff-parser#420d6cfa17a6a8f9bf1a517a2c629dcb332dbe13",
|
||||
"@types/react": "17.0.47"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
|
||||
@@ -10,7 +10,7 @@ com.cloudogu.legman.support:micrometer:2.0.0=testRuntimeClasspath,testRuntimeCla
|
||||
com.cloudogu.legman.support:shiro:2.0.0=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cloudogu.legman:core:2.0.0=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cloudogu.spotter:spotter-core:4.0.0=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cronutils:cron-utils:9.1.6=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cronutils:cron-utils:9.1.8=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.damnhandy:handy-uri-templates:2.1.7=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.3=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.3=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
@@ -34,8 +34,7 @@ com.github.sdorra:web-resources:1.1.1=testRuntimeClasspath,testRuntimeClasspathC
|
||||
com.github.spullara.mustache.java:compiler:0.9.7=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.auto:auto-common:0.11=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.code.findbugs:jsr305:3.0.2=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.code.gson:gson:2.8.6=testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.8.7=testRuntimeClasspathCopy
|
||||
com.google.code.gson:gson:2.8.7=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.errorprone:error_prone_annotations:2.3.4=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.guava:failureaccess:1.0.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.guava:guava:30.1-jre=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
@@ -46,8 +45,7 @@ com.google.inject.extensions:guice-servlet:5.0.1=testCompileClasspath,testCompil
|
||||
com.google.inject.extensions:guice-throwingproviders:5.0.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.inject:guice:5.0.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.google.j2objc:j2objc-annotations:1.3=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.googlecode.javaewah:JavaEWAH:1.1.12=testCompileClasspathCopy,testRuntimeClasspathCopy
|
||||
com.googlecode.javaewah:JavaEWAH:1.1.7=testCompileClasspath,testRuntimeClasspath
|
||||
com.googlecode.javaewah:JavaEWAH:1.1.12=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.ibm.async:asyncutil:0.1.0=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.jcraft:jsch.agentproxy.connector-factory:0.0.7=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.jcraft:jsch.agentproxy.core:0.0.7=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
@@ -147,13 +145,10 @@ org.apache.sling:org.apache.sling.javax.activation:0.1.0=testCompileClasspath,te
|
||||
org.apache.tika:tika-core:1.25=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.apiguardian:apiguardian-api:1.1.0=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.assertj:assertj-core:3.18.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcpg-jdk15on:1.67=testRuntimeClasspath
|
||||
org.bouncycastle:bcpg-jdk15on:1.69=testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcpkix-jdk15on:1.67=testRuntimeClasspath
|
||||
org.bouncycastle:bcpkix-jdk15on:1.69=testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcprov-jdk15on:1.67=testRuntimeClasspath
|
||||
org.bouncycastle:bcprov-jdk15on:1.69=testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcutil-jdk15on:1.69=testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcpg-jdk15on:1.69=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcpkix-jdk15on:1.69=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcprov-jdk15on:1.69=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.bouncycastle:bcutil-jdk15on:1.69=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.ccil.cowan.tagsoup:tagsoup:1.2.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.checkerframework:checker-qual:3.5.0=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.codehaus.groovy:groovy-json:3.0.2=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
@@ -162,6 +157,7 @@ org.codehaus.groovy:groovy:3.0.2=testCompileClasspath,testCompileClasspathCopy,t
|
||||
org.eclipse.microprofile.config:microprofile-config-api:2.0=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.3=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish.jaxb:txw2:2.3.3=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish:jakarta.el:3.0.4=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish:javax.el:3.0.1-b11=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish:javax.json:1.1.4=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.hamcrest:hamcrest-core:2.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
@@ -174,7 +170,6 @@ org.jacoco:org.jacoco.ant:0.8.7=jacocoAntCopy
|
||||
org.jacoco:org.jacoco.core:0.8.7=jacocoAntCopy
|
||||
org.jacoco:org.jacoco.report:0.8.7=jacocoAntCopy
|
||||
org.javahg:javahg:1.0.0=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.javassist:javassist:3.27.0-GA=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.jboss.logging:jboss-logging:3.4.2.Final=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.jboss.resteasy:resteasy-client-api:4.7.5.Final=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.jboss.resteasy:resteasy-client:4.7.5.Final=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
@@ -215,18 +210,12 @@ org.reactivestreams:reactive-streams:1.0.3=testCompileClasspath,testCompileClass
|
||||
org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.slf4j:slf4j-api:1.7.30=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.tmatesoft.sqljet:sqljet:1.1.14=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.gpg.bc:5.11.1.202105131744-r-scm2=testRuntimeClasspath
|
||||
sonia.jgit:org.eclipse.jgit.gpg.bc:5.13.0.202109080827-r-scm1=testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.http.apache:5.11.1.202105131744-r-scm2=testRuntimeClasspath
|
||||
sonia.jgit:org.eclipse.jgit.http.apache:5.13.0.202109080827-r-scm1=testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.http.server:5.11.1.202105131744-r-scm2=testRuntimeClasspath
|
||||
sonia.jgit:org.eclipse.jgit.http.server:5.13.0.202109080827-r-scm1=testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.lfs.server:5.11.1.202105131744-r-scm2=testRuntimeClasspath
|
||||
sonia.jgit:org.eclipse.jgit.lfs.server:5.13.0.202109080827-r-scm1=testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.lfs:5.11.1.202105131744-r-scm2=testRuntimeClasspath
|
||||
sonia.jgit:org.eclipse.jgit.lfs:5.13.0.202109080827-r-scm1=testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit:5.11.1.202105131744-r-scm2=testCompileClasspath,testRuntimeClasspath
|
||||
sonia.jgit:org.eclipse.jgit:5.13.0.202109080827-r-scm1=testCompileClasspathCopy,testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.gpg.bc:5.13.0.202109080827-r-scm1=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.http.apache:5.13.0.202109080827-r-scm1=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.http.server:5.13.0.202109080827-r-scm1=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.lfs.server:5.13.0.202109080827-r-scm1=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit.lfs:5.13.0.202109080827-r-scm1=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.jgit:org.eclipse.jgit:5.13.0.202109080827-r-scm1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.svnkit:svnkit-dav:1.10.3-scm2=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
sonia.svnkit:svnkit:1.10.3-scm2=testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
empty=annotationProcessor,annotationProcessorCopy,archives,archivesCopy,compileClasspath,compileClasspathCopy,corePlugin,corePluginCopy,default,defaultCopy,itPlugin,itPluginCopy,itWebApp,itWebAppCopy,runtimeClasspath,runtimeClasspathCopy,testAnnotationProcessor,testAnnotationProcessorCopy
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/plugin-scripts": "^1.2.2",
|
||||
"@scm-manager/prettier-config": "^2.11.1",
|
||||
@@ -33,4 +33,4 @@
|
||||
"eslintConfig": {
|
||||
"extends": "@scm-manager/eslint-config"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/plugin-scripts": "^1.2.2",
|
||||
"@scm-manager/prettier-config": "^2.11.1",
|
||||
@@ -32,4 +32,4 @@
|
||||
"eslintConfig": {
|
||||
"extends": "@scm-manager/eslint-config"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/plugin-scripts": "^1.2.2",
|
||||
"@scm-manager/prettier-config": "^2.11.1",
|
||||
@@ -32,4 +32,4 @@
|
||||
"eslintConfig": {
|
||||
"extends": "@scm-manager/eslint-config"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/plugin-scripts": "^1.2.2",
|
||||
"@scm-manager/prettier-config": "^2.11.1",
|
||||
@@ -32,4 +32,4 @@
|
||||
"eslintConfig": {
|
||||
"extends": "@scm-manager/eslint-config"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,6 +279,7 @@ license {
|
||||
exclude '**/*.snap'
|
||||
exclude '**/*.iml'
|
||||
exclude '**/.babelrc'
|
||||
exclude '**/storybook-static/**'
|
||||
|
||||
tasks {
|
||||
modules {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"fluent-ffmpeg": "^2.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/eslint-config": "^2.15.1"
|
||||
"@scm-manager/eslint-config": "^2.16.0"
|
||||
},
|
||||
"prettier": "@scm-manager/prettier-config",
|
||||
"eslintConfig": {
|
||||
@@ -26,4 +26,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@scm-manager/tsconfig": "^2.13.0",
|
||||
@@ -52,4 +52,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,15 @@
|
||||
*/
|
||||
|
||||
import { ApiResult, useIndexLink, useRequiredIndexLink } from "./base";
|
||||
import { isPluginCollection, PendingPlugins, Plugin, PluginCollection } from "@scm-manager/ui-types";
|
||||
import type { PendingPlugins, Plugin, PluginCollection, HalRepresentation } from "@scm-manager/ui-types";
|
||||
import { useMutation, useQuery, useQueryClient } from "react-query";
|
||||
import { apiClient } from "./apiclient";
|
||||
import { requiredLink } from "./links";
|
||||
import { BadGatewayError } from "./errors";
|
||||
|
||||
const isPluginCollection = (input: HalRepresentation): input is PluginCollection =>
|
||||
input._embedded ? "plugins" in input._embedded : false;
|
||||
|
||||
type WaitForRestartOptions = {
|
||||
initialDelay?: number;
|
||||
timeout?: number;
|
||||
|
||||
4
scm-ui/ui-buttons/.storybook/.babelrc
Normal file
4
scm-ui/ui-buttons/.storybook/.babelrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["@scm-manager/babel-preset"],
|
||||
"plugins": ["@babel/plugin-syntax-dynamic-import"]
|
||||
}
|
||||
57
scm-ui/ui-buttons/.storybook/RemoveThemesPlugin.js
Normal file
57
scm-ui/ui-buttons/.storybook/RemoveThemesPlugin.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
class RemoveThemesPlugin {
|
||||
apply (compiler) {
|
||||
compiler.hooks.compilation.tap('RemoveThemesPlugin', (compilation) => {
|
||||
|
||||
HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync(
|
||||
'RemoveThemesPlugin',
|
||||
(data, cb) => {
|
||||
|
||||
// remove generated style-loader bundles from the page
|
||||
// there should be a better way, which does not generate the bundles at all
|
||||
// but for now it works
|
||||
if (data.assets.js) {
|
||||
data.assets.js = data.assets.js.filter(bundle => !bundle.startsWith("ui-theme-"))
|
||||
.filter(bundle => !bundle.startsWith("runtime~ui-theme-"))
|
||||
}
|
||||
|
||||
// remove css links to avoid conflicts with the themes
|
||||
// so we remove all and add our own via preview-head.html
|
||||
if (data.assets.css) {
|
||||
data.assets.css = data.assets.css.filter(css => !css.startsWith("ui-theme-"))
|
||||
}
|
||||
|
||||
// Tell webpack to move on
|
||||
cb(null, data)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RemoveThemesPlugin
|
||||
27
scm-ui/ui-buttons/.storybook/index.css
Normal file
27
scm-ui/ui-buttons/.storybook/index.css
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
109
scm-ui/ui-buttons/.storybook/main.js
Normal file
109
scm-ui/ui-buttons/.storybook/main.js
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const RemoveThemesPlugin = require("./RemoveThemesPlugin");
|
||||
const ReactDOM = require("react-dom");
|
||||
|
||||
const root = path.resolve("..");
|
||||
|
||||
const themedir = path.join(root, "ui-styles", "src");
|
||||
|
||||
ReactDOM.createPortal = (node) => node;
|
||||
|
||||
const themes = fs
|
||||
.readdirSync(themedir)
|
||||
.map((filename) => path.parse(filename))
|
||||
.filter((p) => p.ext === ".scss")
|
||||
.reduce((entries, current) => ({ ...entries, [`ui-theme-${current.name}`]: path.join(themedir, current.base) }), {});
|
||||
|
||||
module.exports = {
|
||||
typescript: { reactDocgen: false },
|
||||
core: {
|
||||
builder: "webpack5",
|
||||
},
|
||||
stories: ["../docs/**/*.stories.mdx", "../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||
addons: [
|
||||
"storybook-addon-i18next",
|
||||
"storybook-addon-themes",
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-interactions",
|
||||
"@storybook/addon-a11y",
|
||||
"storybook-addon-pseudo-states"
|
||||
],
|
||||
framework: "@storybook/react",
|
||||
webpackFinal: async (config) => {
|
||||
// add our themes to webpack entry points
|
||||
config.entry = {
|
||||
main: config.entry,
|
||||
...themes,
|
||||
};
|
||||
|
||||
// create separate css files for our themes
|
||||
config.plugins.push(
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
ignoreOrder: false,
|
||||
})
|
||||
);
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.scss$/,
|
||||
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
|
||||
});
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
postcssOptions: {
|
||||
plugins: {
|
||||
tailwindcss: { config: require("./tailwind.config") },
|
||||
autoprefixer: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
include: path.resolve(__dirname, "../"),
|
||||
});
|
||||
|
||||
// the html-webpack-plugin adds the generated css and js files to the iframe,
|
||||
// which overrides our manually loaded css files.
|
||||
// So we use a custom plugin which uses a hook of html-webpack-plugin
|
||||
// to filter our themes from the output.
|
||||
config.plugins.push(new RemoveThemesPlugin());
|
||||
|
||||
// force cjs instead of esm
|
||||
// https://github.com/tannerlinsley/react-query/issues/3513
|
||||
config.resolve.alias["react-query/devtools"] = require.resolve("react-query/devtools");
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
26
scm-ui/ui-buttons/.storybook/preview-head.html
Normal file
26
scm-ui/ui-buttons/.storybook/preview-head.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!--
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-->
|
||||
|
||||
<link id="ui-theme" data-theme="light" rel="stylesheet" type="text/css" href="/ui-theme-light.css">
|
||||
|
||||
97
scm-ui/ui-buttons/.storybook/preview.js
Normal file
97
scm-ui/ui-buttons/.storybook/preview.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import "./index.css";
|
||||
|
||||
import i18next from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import { withI18next } from "storybook-addon-i18next";
|
||||
import React, {useEffect} from "react";
|
||||
import withApiProvider from "./withApiProvider";
|
||||
import { withThemes } from 'storybook-addon-themes/react';
|
||||
|
||||
let i18n = i18next;
|
||||
|
||||
// only use fetch backend for storybook
|
||||
// and not for storyshots
|
||||
if (!process.env.JEST_WORKER_ID) {
|
||||
const Backend = require("i18next-fetch-backend");
|
||||
i18n = i18n.use(Backend.default);
|
||||
}
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
whitelist: ["en", "de", "es"],
|
||||
lng: "en",
|
||||
fallbackLng: "en",
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
backend: {
|
||||
loadPath: "/locales/{{lng}}/{{ns}}.json",
|
||||
init: {
|
||||
credentials: "same-origin",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const decorators = [
|
||||
withI18next({
|
||||
i18n,
|
||||
languages: {
|
||||
en: "English",
|
||||
de: "Deutsch",
|
||||
es: "Spanisch",
|
||||
},
|
||||
}),
|
||||
withApiProvider,
|
||||
withThemes
|
||||
];
|
||||
|
||||
const Decorator = ({children, themeName}) => {
|
||||
useEffect(() => {
|
||||
const link = document.querySelector("#ui-theme");
|
||||
if (link && link["data-theme"] !== themeName) {
|
||||
link.href = `ui-theme-${themeName}.css`;
|
||||
link["data-theme"] = themeName;
|
||||
}
|
||||
}, [themeName]);
|
||||
return <>{children}</>
|
||||
};
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
themes: {
|
||||
Decorator,
|
||||
clearable: false,
|
||||
default: "light",
|
||||
list: [
|
||||
{ name: "light", color: "#fff" },
|
||||
{ name: "highcontrast", color: "#050514" },
|
||||
{ name: "dark", color: "#121212" },
|
||||
],
|
||||
}
|
||||
};
|
||||
33
scm-ui/ui-buttons/.storybook/tailwind.config.js
Normal file
33
scm-ui/ui-buttons/.storybook/tailwind.config.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
// eslint-disable-next-line global-require,import/no-extraneous-dependencies
|
||||
require("@scm-manager/ui-scripts/src/tailwind.config"),
|
||||
],
|
||||
content: [path.join(__dirname, "../{src,docs}/**/*.{tsx,mdx}")],
|
||||
};
|
||||
45
scm-ui/ui-buttons/.storybook/withApiProvider.js
Normal file
45
scm-ui/ui-buttons/.storybook/withApiProvider.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import * as React from "react";
|
||||
import { ApiProvider } from "@scm-manager/ui-api";
|
||||
|
||||
const withApiProvider = (storyFn) => {
|
||||
return React.createElement(ApiProvider, {
|
||||
index: {
|
||||
version: "x.y.z",
|
||||
_links: {}
|
||||
},
|
||||
me: {
|
||||
name: "trillian",
|
||||
displayName: "Trillian McMillan",
|
||||
mail: "trillian@hitchhiker.com",
|
||||
groups: [],
|
||||
_links: {}
|
||||
},
|
||||
devtools: false,
|
||||
children: storyFn()
|
||||
});
|
||||
}
|
||||
|
||||
export default withApiProvider;
|
||||
64
scm-ui/ui-buttons/docs/introduction.stories.mdx
Normal file
64
scm-ui/ui-buttons/docs/introduction.stories.mdx
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Meta } from "@storybook/addon-docs";
|
||||
import { Button } from "../src";
|
||||
|
||||
<Meta title="Introduction"/>
|
||||
|
||||
# Buttons
|
||||
|
||||
The `@scm-manager/ui-buttons` library provides [atoms](https://atomicdesign.bradfrost.com/chapter-2/#atoms) implemented
|
||||
as minimal wrappers around native html elements styled to match the general SCM-Manager aesthetic.
|
||||
|
||||
## Components
|
||||
|
||||
There are three actionable components available. Styling is consistent amongst them and all have the required `variant` property.
|
||||
|
||||
1. [Button](?path=/story/components--button)
|
||||
2. [Link Button](?path=/story/components--link-button)
|
||||
3. [External Link Button](?path=/story/components--external-link-button)
|
||||
|
||||
## Usage
|
||||
|
||||
Actionable components serve a dedicated purpose. It is therefore important to know when and how to use them.
|
||||
|
||||
### Variants
|
||||
|
||||
There are four variants available to each of the three button types, varying in importance.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Emphasis</th>
|
||||
<th>Button Variant</th>
|
||||
<th>Usage Examples</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Very High</td>
|
||||
<td><Button variant="signal" className="w-full">Signal</Button></td>
|
||||
<td>Destructive actions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>High</td>
|
||||
<td><Button variant="primary" className="w-full">Primary</Button></td>
|
||||
<td>Form submit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Normal</td>
|
||||
<td><Button variant="secondary" className="w-full">Secondary</Button></td>
|
||||
<td>Cancel action in dialog</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Low</td>
|
||||
<td><Button variant="tertiary" className="w-full">Tertiary</Button></td>
|
||||
<td>Circumstantially relevant action on page with many actionable elements</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Content
|
||||
|
||||
Buttons exclusively contain text and no icons. Icons tend to be ambiguous and not always applicable which leads to inconsistent
|
||||
and cluttered layouts.
|
||||
|
||||
Button text should be short, concise and describe the action performed.
|
||||
22
scm-ui/ui-buttons/docs/usage.stories.mdx
Normal file
22
scm-ui/ui-buttons/docs/usage.stories.mdx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Meta, Story } from "@storybook/addon-docs";
|
||||
import { Button } from "../src";
|
||||
|
||||
<Meta title="Usage" parameters={{
|
||||
storyshots: { disable: true }
|
||||
}} />
|
||||
|
||||
In confirmation dialogs, there are two actions.<br/>
|
||||
One to cancel the current process and one to confirm it.<br/>
|
||||
Aborting is always the secondary action, confirmation always the primary.
|
||||
Focus is always on the cancelling action.
|
||||
|
||||
<Story name="Confirmation Dialog">
|
||||
<div className="max-w-2xl rounded border p-4">
|
||||
<h4 className="mb-2 font-bold">Delete User</h4>
|
||||
<p>Do you really want to delete this user ?</p>
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant="secondary">Cancel</Button>
|
||||
<Button variant="primary">Delete</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Story>
|
||||
85
scm-ui/ui-buttons/package.json
Normal file
85
scm-ui/ui-buttons/package.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "@scm-manager/ui-buttons",
|
||||
"version": "2.37.3-SNAPSHOT",
|
||||
"private": true,
|
||||
"main": "build/index.js",
|
||||
"module": "build/index.mjs",
|
||||
"types": "build/index.d.ts",
|
||||
"files": [
|
||||
"build"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup ./src/index.ts -d build --format esm,cjs --dts",
|
||||
"dev": "tsup ./src/index.ts -d build --format esm,cjs --dts --watch",
|
||||
"lint": "eslint src",
|
||||
"typecheck": "tsc",
|
||||
"storybook": "start-storybook -p 6006 -s ../ui-webapp/public",
|
||||
"build-storybook": "build-storybook",
|
||||
"image-snapshots": "jest \"image-snapshot.test.ts\"",
|
||||
"a11y-check": "jest \"a11y.test.ts\"",
|
||||
"depcheck": "depcheck --ignores=@scm-manager/prettier-config,@scm-manager/tsconfig,@babel/core,sass-loader,autoprefixer,babel-loader,postcss-loader,tailwindcss,storybook-addon-*,@storybook/*,webpack"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-router-dom": "^5.3.1",
|
||||
"classnames": "^2.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/ui-scripts": "2.37.3-SNAPSHOT",
|
||||
"@scm-manager/ui-styles": "2.37.3-SNAPSHOT",
|
||||
"@scm-manager/ui-api": "2.37.3-SNAPSHOT",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@babel/core": "^7.17.8",
|
||||
"@scm-manager/tsconfig": "^2.12.0",
|
||||
"@storybook/addon-essentials": "^6.4.20",
|
||||
"@storybook/addon-interactions": "^6.4.20",
|
||||
"@storybook/addon-a11y": "^6.4.20",
|
||||
"@storybook/addon-links": "^6.4.20",
|
||||
"@storybook/builder-webpack5": "^6.4.20",
|
||||
"@storybook/manager-webpack5": "^6.4.20",
|
||||
"@storybook/react": "^6.4.20",
|
||||
"@storybook/addon-storyshots-puppeteer": "^6.4.20",
|
||||
"@storybook/addon-storyshots": "^6.4.20",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"jest-transform-css": "^4.0.1",
|
||||
"puppeteer": "^15.5.0",
|
||||
"storybook-addon-pseudo-states": "^1.15.1",
|
||||
"storybook-react-router": "^1.0.8",
|
||||
"@types/storybook-react-router": "^1.0.2",
|
||||
"sass-loader": "^12.3.0",
|
||||
"storybook-addon-themes": "^6.1.0",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"babel-loader": "^8.2.4",
|
||||
"postcss": "^8.4.12",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"webpack": "5",
|
||||
"tsup": "^6.1.2",
|
||||
"mini-css-extract-plugin": "^1.6.2",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"react-query": "^3.25.1",
|
||||
"i18next": "^19.9.2",
|
||||
"react-i18next": "^10.13.2",
|
||||
"i18next-fetch-backend": "^2.3.1"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@scm-manager/babel-preset"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
"^.+\\.[tj]sx?$": "babel-jest",
|
||||
"^.+\\.(css|less|scss)$": "jest-transform-css",
|
||||
"^.+\\.mdx?$": "@storybook/addon-docs/jest-transform-mdx"
|
||||
}
|
||||
},
|
||||
"prettier": "@scm-manager/prettier-config",
|
||||
"eslintConfig": {
|
||||
"extends": "@scm-manager/eslint-config"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "restricted"
|
||||
}
|
||||
}
|
||||
30
scm-ui/ui-buttons/postcss.config.js
Normal file
30
scm-ui/ui-buttons/postcss.config.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
34
scm-ui/ui-buttons/src/a11y.test.ts
Normal file
34
scm-ui/ui-buttons/src/a11y.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import initStoryshots from "@storybook/addon-storyshots";
|
||||
import { axeTest } from "@storybook/addon-storyshots-puppeteer";
|
||||
import path from "path";
|
||||
|
||||
initStoryshots({
|
||||
suite: "A11y checks",
|
||||
test: axeTest({
|
||||
storybookUrl: `file://${path.resolve(__dirname, "../storybook-static")}`,
|
||||
}),
|
||||
storyNameRegex: /High-Contrast States/,
|
||||
});
|
||||
91
scm-ui/ui-buttons/src/button.stories.tsx
Normal file
91
scm-ui/ui-buttons/src/button.stories.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
Button as ButtonComponent,
|
||||
ButtonVariantList,
|
||||
ButtonVariants,
|
||||
ExternalLinkButton as ExternalLinkButtonComponent,
|
||||
LinkButton as LinkButtonComponent,
|
||||
} from "./button";
|
||||
import StoryRouter from "storybook-react-router";
|
||||
import { StoryFn } from "@storybook/react";
|
||||
|
||||
type ExtractProps<T> = T extends React.ComponentType<infer U> ? U : never;
|
||||
|
||||
// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
||||
export default {
|
||||
title: "Components",
|
||||
component: null,
|
||||
subcomponents: {
|
||||
Button: ButtonComponent,
|
||||
LinkButton: LinkButtonComponent,
|
||||
ExternalLinkButton: ExternalLinkButtonComponent,
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
options: ButtonVariantList,
|
||||
control: { type: "select" },
|
||||
},
|
||||
},
|
||||
decorators: [StoryRouter()],
|
||||
parameters: {
|
||||
storyshots: { disable: true },
|
||||
},
|
||||
};
|
||||
|
||||
// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
|
||||
const ButtonTemplate: StoryFn<ExtractProps<typeof ButtonComponent>> = (args) => <ButtonComponent {...args} />;
|
||||
const LinkButtonTemplate: StoryFn<ExtractProps<typeof LinkButtonComponent>> = (args) => (
|
||||
<LinkButtonComponent {...args} />
|
||||
);
|
||||
const ExternalLinkButtonTemplate: StoryFn<ExtractProps<typeof ExternalLinkButtonComponent>> = (args) => (
|
||||
<ExternalLinkButtonComponent {...args} />
|
||||
);
|
||||
|
||||
export const Button = ButtonTemplate.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
Button.args = {
|
||||
children: "Button",
|
||||
variant: ButtonVariants.PRIMARY,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export const LinkButton = LinkButtonTemplate.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
LinkButton.args = {
|
||||
children: "Link Button",
|
||||
to: "/repos",
|
||||
variant: ButtonVariants.PRIMARY,
|
||||
};
|
||||
|
||||
export const ExternalLinkButton = ExternalLinkButtonTemplate.bind({});
|
||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
ExternalLinkButton.args = {
|
||||
children: "External Link Button",
|
||||
href: "https://scm-manager.org",
|
||||
variant: ButtonVariants.PRIMARY,
|
||||
};
|
||||
73
scm-ui/ui-buttons/src/button.test.stories.mdx
Normal file
73
scm-ui/ui-buttons/src/button.test.stories.mdx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { Meta, Story } from "@storybook/addon-docs";
|
||||
import { Button, ButtonVariantList } from "./button";
|
||||
|
||||
<Meta title="Tests"/>
|
||||
|
||||
<Story name="Light States" parameters={{
|
||||
pseudo: {
|
||||
hover: ButtonVariantList.map(variant => `#${variant}-Hover`),
|
||||
focus: ButtonVariantList.map(variant => `#${variant}-Focus`),
|
||||
active: ButtonVariantList.map(variant => `#${variant}-Active`),
|
||||
},
|
||||
themes: {
|
||||
default: 'light',
|
||||
},
|
||||
}}>
|
||||
<table className="border-separate border-spacing-4">
|
||||
<tr>
|
||||
<th>STATE</th>
|
||||
{ButtonVariantList.map(variant => <th>{variant.toUpperCase()}</th>)}
|
||||
</tr>
|
||||
{["Normal", "Hover", "Active", "Focus", "Disabled"].map(state => <tr>
|
||||
<td>{state}</td>
|
||||
{ButtonVariantList.map(variant => <td><Button id={`${variant}-${state}`} disabled={state === "Disabled"}
|
||||
variant={variant}>Button</Button></td>)}
|
||||
</tr>)}
|
||||
</table>
|
||||
</Story>
|
||||
|
||||
<Story name="Dark States" parameters={{
|
||||
pseudo: {
|
||||
hover: ButtonVariantList.map(variant => `#${variant}-Hover`),
|
||||
focus: ButtonVariantList.map(variant => `#${variant}-Focus`),
|
||||
active: ButtonVariantList.map(variant => `#${variant}-Active`),
|
||||
},
|
||||
themes: {
|
||||
default: 'dark',
|
||||
},
|
||||
}}>
|
||||
<table className="border-separate border-spacing-4">
|
||||
<tr>
|
||||
<th>STATE</th>
|
||||
{ButtonVariantList.map(variant => <th>{variant.toUpperCase()}</th>)}
|
||||
</tr>
|
||||
{["Normal", "Hover", "Active", "Focus", "Disabled"].map(state => <tr>
|
||||
<td>{state}</td>
|
||||
{ButtonVariantList.map(variant => <td><Button id={`${variant}-${state}`} disabled={state === "Disabled"}
|
||||
variant={variant}>Button</Button></td>)}
|
||||
</tr>)}
|
||||
</table>
|
||||
</Story>
|
||||
|
||||
<Story name="High-Contrast States" parameters={{
|
||||
pseudo: {
|
||||
hover: ButtonVariantList.map(variant => `#${variant}-Hover`),
|
||||
focus: ButtonVariantList.map(variant => `#${variant}-Focus`),
|
||||
active: ButtonVariantList.map(variant => `#${variant}-Active`),
|
||||
},
|
||||
themes: {
|
||||
default: 'highcontrast',
|
||||
},
|
||||
}}>
|
||||
<table className="border-separate border-spacing-4">
|
||||
<tr>
|
||||
<th>STATE</th>
|
||||
{ButtonVariantList.map(variant => <th>{variant.toUpperCase()}</th>)}
|
||||
</tr>
|
||||
{["Normal", "Hover", "Active", "Focus", "Disabled"].map(state => <tr>
|
||||
<td>{state}</td>
|
||||
{ButtonVariantList.map(variant => <td><Button id={`${variant}-${state}`} disabled={state === "Disabled"}
|
||||
variant={variant}>Button</Button></td>)}
|
||||
</tr>)}
|
||||
</table>
|
||||
</Story>
|
||||
109
scm-ui/ui-buttons/src/button.tsx
Normal file
109
scm-ui/ui-buttons/src/button.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes } from "react";
|
||||
import { Link as ReactRouterLink, LinkProps as ReactRouterLinkProps } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
|
||||
export const ButtonVariants = {
|
||||
PRIMARY: "primary",
|
||||
SECONDARY: "secondary",
|
||||
TERTIARY: "tertiary",
|
||||
SIGNAL: "signal",
|
||||
} as const;
|
||||
|
||||
export const ButtonVariantList = Object.values(ButtonVariants);
|
||||
|
||||
type ButtonVariant = typeof ButtonVariants[keyof typeof ButtonVariants];
|
||||
|
||||
const BASE_BUTTON_CLASSES = classNames(
|
||||
"inline-block whitespace-nowrap rounded border py-2 px-6 text-center font-semibold focus:z-10 focus:outline focus:outline-offset-2 focus:outline-purple-500 disabled:cursor-not-allowed"
|
||||
);
|
||||
const DEFAULT_BUTTON_CLASSES = classNames(
|
||||
"border-gray-200 hover:border-gray-400 active:shadow-inner disabled:hover:border-gray-200 disabled:active:shadow-none"
|
||||
);
|
||||
const PRIMARY_BUTTON_CLASSES = classNames(
|
||||
"border-transparent bg-primary text-primary-contrast hover:bg-primary-hover active:bg-primary-active disabled:bg-primary-disabled disabled:text-primary-disabled-contrast "
|
||||
);
|
||||
const SECONDARY_BUTTON_CLASSES = classNames(
|
||||
"border-primary text-primary hover:border-primary-hover hover:text-primary-hover active:border-primary-active active:text-primary-active disabled:border-primary-disabled disabled:text-primary-disabled"
|
||||
);
|
||||
const TERTIARY_BUTTON_CLASSES = classNames(
|
||||
"border-transparent text-primary hover:text-primary-hover active:text-primary-active disabled:text-primary-disabled"
|
||||
);
|
||||
const SIGNAL_BUTTON_CLASSES = classNames(
|
||||
"border-transparent bg-signal text-signal-contrast hover:bg-signal-hover hover:text-signal-hover-contrast active:bg-signal-active active:text-signal-active-contrast disabled:bg-signal-disabled disabled:text-signal-disabled-contrast"
|
||||
);
|
||||
|
||||
const createButtonClasses = (variant?: ButtonVariant) =>
|
||||
classNames(BASE_BUTTON_CLASSES, {
|
||||
[DEFAULT_BUTTON_CLASSES]: !variant,
|
||||
[PRIMARY_BUTTON_CLASSES]: variant === "primary",
|
||||
[SECONDARY_BUTTON_CLASSES]: variant === "secondary",
|
||||
[TERTIARY_BUTTON_CLASSES]: variant === "tertiary",
|
||||
[SIGNAL_BUTTON_CLASSES]: variant === "signal",
|
||||
});
|
||||
|
||||
type BaseButtonProps = {
|
||||
variant: ButtonVariant;
|
||||
};
|
||||
|
||||
type ButtonProps = BaseButtonProps & ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
/**
|
||||
* Styled html button
|
||||
*/
|
||||
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, children, ...props }, ref) => (
|
||||
<button {...props} className={classNames(createButtonClasses(variant), className)} ref={ref}>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
);
|
||||
|
||||
type LinkButtonProps = BaseButtonProps & ReactRouterLinkProps;
|
||||
|
||||
/**
|
||||
* Styled react router link
|
||||
*/
|
||||
export const LinkButton = React.forwardRef<HTMLAnchorElement, LinkButtonProps>(
|
||||
({ className, variant, children, ...props }, ref) => (
|
||||
<ReactRouterLink {...props} className={classNames(createButtonClasses(variant), className)} ref={ref}>
|
||||
{children}
|
||||
</ReactRouterLink>
|
||||
)
|
||||
);
|
||||
|
||||
type ExternalLinkButtonProps = BaseButtonProps & AnchorHTMLAttributes<HTMLAnchorElement>;
|
||||
|
||||
/**
|
||||
* Styled html anchor
|
||||
*/
|
||||
export const ExternalLinkButton = React.forwardRef<HTMLAnchorElement, ExternalLinkButtonProps>(
|
||||
({ className, variant, children, ...props }, ref) => (
|
||||
<a {...props} className={classNames(createButtonClasses(variant), className)} ref={ref}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
);
|
||||
33
scm-ui/ui-buttons/src/image-snapshot.test.ts
Normal file
33
scm-ui/ui-buttons/src/image-snapshot.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import path from "path";
|
||||
import initStoryshots from "@storybook/addon-storyshots";
|
||||
import { imageSnapshot } from "@storybook/addon-storyshots-puppeteer";
|
||||
|
||||
initStoryshots({
|
||||
suite: "Image snapshots",
|
||||
test: imageSnapshot({
|
||||
storybookUrl: `file://${path.resolve(__dirname, "../storybook-static")}`,
|
||||
})
|
||||
});
|
||||
26
scm-ui/ui-buttons/src/index.css
Normal file
26
scm-ui/ui-buttons/src/index.css
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
27
scm-ui/ui-buttons/src/index.ts
Normal file
27
scm-ui/ui-buttons/src/index.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import "./index.css";
|
||||
|
||||
export { Button, LinkButton, ExternalLinkButton, ButtonVariants } from "./button";
|
||||
34
scm-ui/ui-buttons/tailwind.config.js
Normal file
34
scm-ui/ui-buttons/tailwind.config.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
// eslint-disable-next-line global-require,import/no-extraneous-dependencies
|
||||
require("@scm-manager/ui-styles/src/tailwind.config.preset"),
|
||||
],
|
||||
content: [path.join(__dirname, "src/**/*.tsx")],
|
||||
important: true,
|
||||
};
|
||||
7
scm-ui/ui-buttons/tsconfig.json
Normal file
7
scm-ui/ui-buttons/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "@scm-manager/tsconfig",
|
||||
"include": [
|
||||
"./src",
|
||||
"./docs"
|
||||
]
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@scm-manager/tsconfig": "^2.13.0",
|
||||
@@ -109,4 +109,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
*/
|
||||
import React, { FC, useState } from "react";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
import { Button, urls } from "./index";
|
||||
import { urls } from "./index";
|
||||
import { FilterInput, Select } from "./forms";
|
||||
import { ButtonVariants, LinkButton } from "@scm-manager/ui-buttons";
|
||||
import classNames from "classnames";
|
||||
|
||||
type Props = {
|
||||
showCreateButton: boolean;
|
||||
@@ -54,7 +55,7 @@ const OverviewPageActions: FC<Props> = ({
|
||||
label,
|
||||
testId,
|
||||
searchPlaceholder,
|
||||
groupAriaLabelledby
|
||||
groupAriaLabelledby,
|
||||
}) => {
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
@@ -66,7 +67,7 @@ const OverviewPageActions: FC<Props> = ({
|
||||
<Select
|
||||
ariaLabelledby={groupAriaLabelledby}
|
||||
className="is-fullwidth"
|
||||
options={groups.map(g => ({ value: g, label: g }))}
|
||||
options={groups.map((g) => ({ value: g, label: g }))}
|
||||
value={currentGroup}
|
||||
onChange={groupSelected}
|
||||
/>
|
||||
@@ -76,8 +77,10 @@ const OverviewPageActions: FC<Props> = ({
|
||||
const renderCreateButton = () => {
|
||||
if (showCreateButton) {
|
||||
return (
|
||||
<div className={classNames("input-button", "control", "column")}>
|
||||
<Button label={label} link={createLink || `${link}create/`} color="primary" />
|
||||
<div className={classNames("control", "column")}>
|
||||
<LinkButton variant={ButtonVariants.PRIMARY} to={createLink || `${link}create/`}>
|
||||
{label}
|
||||
</LinkButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,6 @@ import Button from "../buttons/Button";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { SubmitButton } from "../buttons";
|
||||
import { Person } from "@scm-manager/ui-types";
|
||||
|
||||
const Decorator = styled.div`
|
||||
padding: 2rem;
|
||||
@@ -74,9 +73,9 @@ const ReactHookForm: FC = () => {
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<Name>();
|
||||
const [stored, setStored] = useState<Person>();
|
||||
const [stored, setStored] = useState<Name>();
|
||||
|
||||
const onSubmit = (person: Person) => {
|
||||
const onSubmit = (person: Name) => {
|
||||
setStored(person);
|
||||
};
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
import { nameRegex } from "../validation";
|
||||
import { TFunction } from "i18next";
|
||||
import { AstPlugin } from "./PluginApi";
|
||||
import { Node, Parent } from "unist";
|
||||
import { Literal, Node, Parent } from "unist";
|
||||
|
||||
const namePartRegex = nameRegex.source.substring(1, nameRegex.source.length - 1).replace(/\[\^([^\]s]+)\]/, "[^$1\\s]");
|
||||
|
||||
@@ -45,11 +45,11 @@ function match(value: string): RegExpMatchArray[] {
|
||||
export const createTransformer = (t: TFunction): AstPlugin => {
|
||||
return ({ visit }) => {
|
||||
visit("text", (node: Node, index: number, parent?: Parent) => {
|
||||
if (!parent || parent.type === "link" || !node.value) {
|
||||
if (!parent || parent.type === "link" || !(node as Literal).value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let nodeText = node.value as string;
|
||||
let nodeText = (node as Literal).value as string;
|
||||
const matches = match(nodeText);
|
||||
|
||||
if (matches.length > 0) {
|
||||
@@ -92,7 +92,7 @@ export const createTransformer = (t: TFunction): AstPlugin => {
|
||||
parent.children[index] = {
|
||||
type: "text",
|
||||
children,
|
||||
};
|
||||
} as Node;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
import { AstPlugin } from "./PluginApi";
|
||||
import { Node, Parent } from "unist";
|
||||
import { Literal, Node, Parent } from "unist";
|
||||
|
||||
/**
|
||||
* Some existing remark plugins (e.g. changesetShortLinkParser or the plugin for issue tracker links) create
|
||||
@@ -54,8 +54,8 @@ import { Node, Parent } from "unist";
|
||||
export const createTransformer = (): AstPlugin => {
|
||||
return ({ visit }) => {
|
||||
visit("text", (node: Node, index: number, parent?: Parent) => {
|
||||
if (node.value === undefined && Array.isArray(node.children) && node.children.length > 0) {
|
||||
const children = node.children;
|
||||
if ((node as Literal).value === undefined && Array.isArray((node as Parent).children) && (node as Parent).children.length > 0) {
|
||||
const children = (node as Parent).children;
|
||||
const preChildren = parent?.children.slice(0, index) || [];
|
||||
const postChildren = parent?.children.slice(index + 1) || [];
|
||||
parent!.children = [...preChildren, ...children, ...postChildren];
|
||||
|
||||
@@ -50,8 +50,8 @@ const Table: FC<Props> = ({ data, sortable, children, emptyMessage, className })
|
||||
|
||||
const sortFunctions: Comparator | undefined[] = [];
|
||||
React.Children.forEach(children, (child, index) => {
|
||||
if (child && isSortable(child)) {
|
||||
sortFunctions.push(child.props.createComparator(child.props, index));
|
||||
if (child && isSortable(child as ReactElement)) {
|
||||
sortFunctions.push((child as ReactElement).props.createComparator((child as ReactElement).props, index));
|
||||
} else {
|
||||
sortFunctions.push(undefined);
|
||||
}
|
||||
@@ -61,9 +61,9 @@ const Table: FC<Props> = ({ data, sortable, children, emptyMessage, className })
|
||||
return (
|
||||
<tr key={rowIndex}>
|
||||
{React.Children.map(children, (child, columnIndex) => {
|
||||
const { className: columnClassName, ...childProperties } = child.props;
|
||||
const { className: columnClassName, ...childProperties } = (child as ReactElement).props;
|
||||
return (
|
||||
<td className={columnClassName}>{React.cloneElement(child, { ...childProperties, columnIndex, row })}</td>
|
||||
<td className={columnClassName}>{React.cloneElement((child as ReactElement), { ...childProperties, columnIndex, row })}</td>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
@@ -112,14 +112,14 @@ const Table: FC<Props> = ({ data, sortable, children, emptyMessage, className })
|
||||
<tr>
|
||||
{React.Children.map(children, (child, index) => (
|
||||
<th
|
||||
className={isSortable(child) && "is-clickable"}
|
||||
onClick={isSortable(child) ? () => tableSort(index) : undefined}
|
||||
className={isSortable((child as ReactElement)) && "is-clickable"}
|
||||
onClick={isSortable((child as ReactElement)) ? () => tableSort(index) : undefined}
|
||||
onMouseEnter={() => setHoveredColumnIndex(index)}
|
||||
onMouseLeave={() => setHoveredColumnIndex(undefined)}
|
||||
key={index}
|
||||
>
|
||||
{child.props.header}
|
||||
{isSortable(child) && renderSortIcon(child, ascending, shouldShowIcon(index))}
|
||||
{(child as ReactElement).props.header}
|
||||
{isSortable((child as ReactElement)) && renderSortIcon((child as ReactElement), ascending, shouldShowIcon(index))}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@scm-manager/tsconfig": "^2.13.0",
|
||||
@@ -46,4 +46,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@types/react": "^17.0.1",
|
||||
@@ -43,4 +43,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"tsup": "^5.12.6"
|
||||
},
|
||||
"babel": {
|
||||
@@ -36,4 +36,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/plugin-scripts": "^1.2.2",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
@@ -43,4 +43,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"ui-scripts": "./bin/ui-scripts.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@scm-manager/ui-styles": "2.37.3-SNAPSHOT",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
|
||||
"babel-loader": "^8.2.3",
|
||||
"css-loader": "^6.5.0",
|
||||
@@ -24,11 +25,15 @@
|
||||
"style-loader": "^3.3.1",
|
||||
"webpack": "^5.60.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-dev-server": "^4.4.0"
|
||||
"webpack-dev-server": "^4.4.0",
|
||||
"tailwindcss": "^3.0.23",
|
||||
"postcss": "^8.4.12",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"autoprefixer": "^10.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"webpack-bundle-analyzer": "^4.5.0"
|
||||
},
|
||||
@@ -41,4 +46,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
41
scm-ui/ui-scripts/src/tailwind.config.js
Normal file
41
scm-ui/ui-scripts/src/tailwind.config.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
|
||||
const root = path.resolve(process.cwd(), "scm-ui");
|
||||
|
||||
const sizes = [0, 1, 2, 3, 4, 5, 6, "auto"];
|
||||
const helpers = ["m", "p"];
|
||||
const variants = ["", "x", "y", "t", "r", "l", "b"];
|
||||
const bulmaHelpers = helpers
|
||||
.map((helper) => sizes.map((size) => variants.map((variant) => `${helper}${variant}-${size}`)))
|
||||
.flat(3);
|
||||
|
||||
module.exports = {
|
||||
// eslint-disable-next-line global-require
|
||||
presets: [require("@scm-manager/ui-styles/src/tailwind.config.preset")],
|
||||
content: [path.join(root, "ui-webapp", "src", "**", "*.tsx")],
|
||||
safelist: bulmaHelpers,
|
||||
};
|
||||
27
scm-ui/ui-scripts/src/tailwind.css
Normal file
27
scm-ui/ui-scripts/src/tailwind.css
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -33,7 +33,13 @@ const isDevelopment = process.env.NODE_ENV === "development";
|
||||
const root = path.resolve(process.cwd(), "..");
|
||||
|
||||
const babelPlugins = [];
|
||||
const webpackPlugins = [];
|
||||
const webpackPlugins = [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "webapp.tailwind.css",
|
||||
chunkFilename: "webapp.tailwind.css",
|
||||
ignoreOrder: false,
|
||||
}),
|
||||
];
|
||||
|
||||
if (process.env.ANALYZE_BUNDLES === "true") {
|
||||
// it is ok to use require here, because we want to load the package conditionally
|
||||
@@ -82,6 +88,7 @@ module.exports = [
|
||||
// enable async/await
|
||||
"regenerator-runtime/runtime",
|
||||
"./ui-webapp/src/index.tsx",
|
||||
"./ui-scripts/src/tailwind.css",
|
||||
],
|
||||
},
|
||||
devtool: "eval-cheap-module-source-map",
|
||||
@@ -101,8 +108,40 @@ module.exports = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /tailwind\.css$/i,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
},
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
postcssOptions: {
|
||||
plugins: [
|
||||
[
|
||||
"tailwindcss",
|
||||
{
|
||||
config: path.join(root, "ui-scripts", "src", "tailwind.config.js"),
|
||||
},
|
||||
],
|
||||
["autoprefixer", {}],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(css|scss|sass)$/i,
|
||||
exclude: /tailwind\.css$/i,
|
||||
use: [
|
||||
// Creates `style` nodes from JS strings
|
||||
"style-loader",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"react-diff-view": "^2.4.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/prettier-config": "^2.11.1",
|
||||
"css-loader": "^6.5.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
@@ -31,4 +31,4 @@
|
||||
"eslintConfig": {
|
||||
"extends": "@scm-manager/eslint-config"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,6 +229,23 @@ $danger-25: scale-color($danger, $lightness: -75%);
|
||||
--diff-code-delete-edit-background-color: #{desaturate(#000, 20%)};
|
||||
--diff-code-selected-background-color: #{desaturate(#fffce0, 20%)};
|
||||
--diff-omit-gutter-line-color: #cb2a1d;
|
||||
|
||||
// Tailwind
|
||||
--scm-primary-contrast-color: #{lighten($text-strong, 2.5%)};
|
||||
--scm-primary-hover-color: #{darken($primary, 5%)};
|
||||
--scm-primary-hover-contrast-color: #{lighten($text-strong, 2.5%)};
|
||||
--scm-primary-active-color: #{darken($primary, 10%)};
|
||||
--scm-primary-active-contrast-color: #{lighten($text-strong, 2.5%)};
|
||||
--scm-primary-disabled-color: #{rgba($primary, 0.5)};
|
||||
--scm-primary-disabled-contrast-color: #{rgba(lighten($text-strong, 2.5%), 0.5)};
|
||||
|
||||
--scm-warning-contrast-color: #88550D;
|
||||
--scm-warning-hover-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
--scm-warning-hover-color: #{darken($warning, 10%)};
|
||||
--scm-warning-active-color: #{darken($warning, 20%)};
|
||||
--scm-warning-active-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
--scm-warning-disabled-color: #{rgba($warning, 0.5)};
|
||||
--scm-warning-disabled-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
|
||||
@@ -127,6 +127,23 @@ $tooltip-color: $scheme-main;
|
||||
--diff-code-delete-edit-background-color: #000;
|
||||
--diff-code-selected-background-color: #fffce0;
|
||||
--diff-omit-gutter-line-color: #cb2a1d;
|
||||
|
||||
// Tailwind
|
||||
--scm-primary-contrast-color: #{$black-ter};
|
||||
--scm-primary-hover-color: #{darken($primary, 5%)};
|
||||
--scm-primary-hover-contrast-color: #{$black-ter};
|
||||
--scm-primary-active-color: #{darken($primary, 10%)};
|
||||
--scm-primary-active-contrast-color: #{$black-ter};
|
||||
--scm-primary-disabled-color: #006970;
|
||||
--scm-primary-disabled-contrast-color: #{$black-ter};
|
||||
|
||||
--scm-warning-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
--scm-warning-hover-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
--scm-warning-hover-color: #{darken($warning, 5%)};
|
||||
--scm-warning-active-color: #{darken($warning, 10%)};
|
||||
--scm-warning-active-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
--scm-warning-disabled-color: #{darken($warning, 50%)};
|
||||
--scm-warning-disabled-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
}
|
||||
|
||||
.button {
|
||||
|
||||
@@ -78,6 +78,23 @@ $popover-background-color: $grey-light;
|
||||
--sh-selected-color: #{$warning-25};
|
||||
--sh-highlight-background: #f5f5f5;
|
||||
--sh-highlight-accent: #99d8f3;
|
||||
|
||||
// Tailwind
|
||||
--scm-primary-contrast-color: #{$white};
|
||||
--scm-primary-hover-color: #{darken($primary, 10%)};
|
||||
--scm-primary-hover-contrast-color: #{$white};
|
||||
--scm-primary-active-color: #{darken($primary, 20%)};
|
||||
--scm-primary-active-contrast-color: #{$white};
|
||||
--scm-primary-disabled-color: #bff3f7;
|
||||
--scm-primary-disabled-contrast-color: #{$white};
|
||||
|
||||
--scm-warning-contrast-color: #88550D;
|
||||
--scm-warning-hover-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
--scm-warning-hover-color: #{darken($warning, 10%)};
|
||||
--scm-warning-active-color: #{darken($warning, 20%)};
|
||||
--scm-warning-active-contrast-color: #{rgba(0,0,0,0.7)};
|
||||
--scm-warning-disabled-color: #fff6d5;
|
||||
--scm-warning-disabled-contrast-color: #e1d4c2;
|
||||
}
|
||||
|
||||
.button {
|
||||
|
||||
55
scm-ui/ui-styles/src/tailwind.config.preset.js
Normal file
55
scm-ui/ui-styles/src/tailwind.config.preset.js
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
DEFAULT: "var(--scm-primary-color)",
|
||||
contrast: "var(--scm-primary-contrast-color)",
|
||||
hover: "var(--scm-primary-hover-color)",
|
||||
"hover-contrast": "var(--scm-primary-hover-contrast-color)",
|
||||
active: "var(--scm-primary-active-color)",
|
||||
"active-contrast": "var(--scm-primary-active-contrast-color)",
|
||||
disabled: "var(--scm-primary-disabled-color)",
|
||||
"disabled-contrast": "var(--scm-primary-disabled-contrast-color)",
|
||||
},
|
||||
signal: {
|
||||
DEFAULT: "var(--scm-warning-color)",
|
||||
contrast: "var(--scm-warning-contrast-color)",
|
||||
hover: "var(--scm-warning-hover-color)",
|
||||
"hover-contrast": "var(--scm-warning-hover-contrast-color)",
|
||||
active: "var(--scm-warning-active-color)",
|
||||
"active-contrast": "var(--scm-warning-active-contrast-color)",
|
||||
disabled: "var(--scm-warning-disabled-color)",
|
||||
"disabled-contrast": "var(--scm-warning-disabled-contrast-color)",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
important: true,
|
||||
corePlugins: {
|
||||
preflight: false,
|
||||
}
|
||||
};
|
||||
@@ -21,7 +21,21 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
@import "bulma/bulma";
|
||||
@import "bulma/sass/utilities/_all";
|
||||
@import "bulma/sass/base/_all";
|
||||
@import "bulma/sass/elements/_all";
|
||||
@import "bulma/sass/form/_all";
|
||||
@import "bulma/sass/components/_all";
|
||||
@import "bulma/sass/grid/_all";
|
||||
@import "bulma/sass/helpers/color";
|
||||
@import "bulma/sass/helpers/flexbox";
|
||||
@import "bulma/sass/helpers/float";
|
||||
@import "bulma/sass/helpers/other";
|
||||
@import "bulma/sass/helpers/overflow";
|
||||
@import "bulma/sass/helpers/position";
|
||||
@import "bulma/sass/helpers/typography";
|
||||
@import "bulma/sass/helpers/visibility";
|
||||
@import "bulma/sass/layout/_all";
|
||||
@import "../variables/_derived.scss";
|
||||
@import "bulma-popover/css/bulma-popover";
|
||||
@import "../components/_main.scss";
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@scm-manager/tsconfig": "^2.13.0",
|
||||
@@ -54,4 +54,4 @@
|
||||
"publishConfig": {
|
||||
"access": "restricted"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import type {
|
||||
TokenizeSuccessResponse,
|
||||
} from "../types";
|
||||
import { isRefractorElement } from "../types";
|
||||
import type { RefractorElement } from "refractor";
|
||||
|
||||
// the WorkerGlobalScope is assigned to self
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/self
|
||||
@@ -91,7 +92,7 @@ const countChildrenAndApplyMarkers = (node: RefractorNode, markedTexts?: string[
|
||||
}
|
||||
|
||||
if (newChildren.length > 0) {
|
||||
const el = node as RefractorNode;
|
||||
const el = node as unknown as RefractorElement;
|
||||
el.type = "element";
|
||||
el.tagName = "span";
|
||||
el.children = newChildren;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/babel-preset": "^2.13.1",
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/prettier-config": "^2.10.1",
|
||||
"@scm-manager/tsconfig": "^2.13.0",
|
||||
@@ -51,4 +51,4 @@
|
||||
"publishConfig": {
|
||||
"access": "restricted"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"lint": "eslint src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/tsconfig": "^2.13.0"
|
||||
},
|
||||
"babel": {
|
||||
@@ -30,4 +30,4 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"@scm-manager/ui-modules": "2.37.3-SNAPSHOT",
|
||||
"@scm-manager/ui-syntaxhighlighting": "2.37.3-SNAPSHOT",
|
||||
"@scm-manager/ui-text": "2.37.3-SNAPSHOT",
|
||||
"@scm-manager/ui-buttons": "2.37.3-SNAPSHOT",
|
||||
"@scm-manager/ui-legacy": "2.37.3-SNAPSHOT",
|
||||
"classnames": "^2.2.5",
|
||||
"history": "^4.10.1",
|
||||
@@ -35,7 +36,7 @@
|
||||
"build": "webpack-cli --mode=production --config=../ui-scripts/src/webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scm-manager/eslint-config": "^2.15.1",
|
||||
"@scm-manager/eslint-config": "^2.16.0",
|
||||
"@scm-manager/jest-preset": "^2.13.0",
|
||||
"@scm-manager/ui-tests": "2.37.3-SNAPSHOT",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
@@ -49,7 +50,8 @@
|
||||
"@types/styled-components": "^5.1.25",
|
||||
"@types/systemjs": "^0.20.6",
|
||||
"fetch-mock": "^7.5.1",
|
||||
"react-test-renderer": "^17.0.1"
|
||||
"react-test-renderer": "^17.0.1",
|
||||
"tailwindcss": "^3.0.23"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
@@ -66,4 +68,5 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
}
|
||||
document.head.appendChild(linkElement);
|
||||
</script>
|
||||
<link rel="stylesheet" href="{{ contextPath }}/styles.bundle.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
||||
@@ -37,6 +37,9 @@ import ChangesetShortLink from "./repos/components/changesets/ChangesetShortLink
|
||||
import "./tokenExpired";
|
||||
import { ApiProvider } from "@scm-manager/ui-api";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import "@scm-manager/ui-buttons/build/index.css";
|
||||
|
||||
binder.bind<extensionPoints.ChangesetDescriptionTokens>("changeset.description.tokens", ChangesetShortLink);
|
||||
|
||||
const root = document.getElementById("root");
|
||||
|
||||
@@ -8,7 +8,8 @@ com.cloudogu.legman.support:micrometer:2.0.0=compileClasspath,compileClasspathCo
|
||||
com.cloudogu.legman.support:shiro:2.0.0=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cloudogu.legman:core:2.0.0=annotationProcessor,annotationProcessorCopy,compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cloudogu.spotter:spotter-core:4.0.0=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cronutils:cron-utils:9.1.6=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.cronutils:cron-utils:9.1.6=default
|
||||
com.cronutils:cron-utils:9.1.8=compileClasspath,compileClasspathCopy,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.damnhandy:handy-uri-templates:2.1.7=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.1=swaggerDeps,swaggerDepsCopy
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.3=default
|
||||
@@ -146,7 +147,8 @@ org.checkerframework:checker-qual:3.5.0=annotationProcessor,annotationProcessorC
|
||||
org.eclipse.microprofile.config:microprofile-config-api:2.0=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.3=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish.jaxb:txw2:2.3.3=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish:javax.el:3.0.1-b11=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish:jakarta.el:3.0.4=compileClasspath,compileClasspathCopy,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.glassfish:javax.el:3.0.1-b11=default,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.hamcrest:hamcrest-core:2.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.hamcrest:hamcrest-library:2.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.hamcrest:hamcrest:2.1=testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
@@ -156,8 +158,8 @@ org.jacoco:org.jacoco.agent:0.8.7=jacocoAgentCopy,jacocoAntCopy
|
||||
org.jacoco:org.jacoco.ant:0.8.7=jacocoAntCopy
|
||||
org.jacoco:org.jacoco.core:0.8.7=jacocoAntCopy
|
||||
org.jacoco:org.jacoco.report:0.8.7=jacocoAntCopy
|
||||
org.javassist:javassist:3.25.0-GA=swaggerDeps,swaggerDepsCopy
|
||||
org.javassist:javassist:3.27.0-GA=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.javassist:javassist:3.25.0-GA=compileClasspath,compileClasspathCopy,swaggerDeps,swaggerDepsCopy
|
||||
org.javassist:javassist:3.27.0-GA=default
|
||||
org.jboss.logging:jboss-logging:3.4.2.Final=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.jboss.resteasy:resteasy-client-api:4.7.5.Final=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
org.jboss.resteasy:resteasy-client:4.7.5.Final=compileClasspath,compileClasspathCopy,default,defaultCopy,runtimeClasspath,runtimeClasspathCopy,testCompileClasspath,testCompileClasspathCopy,testRuntimeClasspath,testRuntimeClasspathCopy
|
||||
|
||||
@@ -40,7 +40,7 @@ import javax.inject.Provider;
|
||||
public class PushStateDispatcherProvider implements Provider<PushStateDispatcher> {
|
||||
|
||||
@VisibleForTesting
|
||||
static final String PROPERTY_TARGET = "sonia.scm.ui.proxy";
|
||||
public static final String PROPERTY_TARGET = "sonia.scm.ui.proxy";
|
||||
|
||||
private Provider<TemplatingPushStateDispatcher> templatingPushStateDispatcherProvider;
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.web.tailwind;
|
||||
|
||||
import com.github.sdorra.webresources.CacheControl;
|
||||
import com.github.sdorra.webresources.WebResourceSender;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.filter.WebElement;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.plugin.UberWebResourceLoader;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import static sonia.scm.PushStateDispatcherProvider.PROPERTY_TARGET;
|
||||
|
||||
@Singleton
|
||||
@WebElement(value = "/styles.bundle.css")
|
||||
public class StylesServlet extends HttpServlet {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StylesServlet.class);
|
||||
private final UberWebResourceLoader webResourceLoader;
|
||||
private final String target = System.getProperty(PROPERTY_TARGET);
|
||||
|
||||
private final WebResourceSender sender = WebResourceSender.create()
|
||||
.withGZIP()
|
||||
.withGZIPMinLength(512)
|
||||
.withBufferSize(16384)
|
||||
.withCacheControl(CacheControl.create().noCache());
|
||||
|
||||
@Inject
|
||||
public StylesServlet(PluginLoader pluginLoader) {
|
||||
this.webResourceLoader = pluginLoader.getUberWebResourceLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
try {
|
||||
URL url = webResourceLoader.getResource("/assets/webapp.tailwind.css");
|
||||
if (url != null) {
|
||||
// TODO: Merge css
|
||||
sender.resource(url).get(request, response);
|
||||
} else {
|
||||
getLocally(createProxyUrl("/assets/webapp.tailwind.css"), request, response);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Error on getting the tailwind stylesheet", ex);
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private void getLocally(URL url, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
HttpURLConnection connection = openConnection(url);
|
||||
connection.setRequestMethod(request.getMethod());
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
response.setStatus(responseCode);
|
||||
try (InputStream input = getConnectionInput(connection); OutputStream output = response.getOutputStream()) {
|
||||
ByteStreams.copy(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getConnectionInput(HttpURLConnection connection) throws IOException {
|
||||
if (connection.getErrorStream() != null) {
|
||||
return connection.getErrorStream();
|
||||
}
|
||||
return connection.getInputStream();
|
||||
}
|
||||
|
||||
private URL createProxyUrl(String uri) throws MalformedURLException {
|
||||
return new URL(target + uri);
|
||||
}
|
||||
|
||||
private static HttpURLConnection openConnection(URL url) throws IOException {
|
||||
return (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user