Compare commits

...

65 Commits

Author SHA1 Message Date
be724ecf0d v0.8.3 2021-04-04 21:57:44 +02:00
58d1db14ae Fixed Error color not set
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-04-04 21:57:27 +02:00
7000d3ebac v0.8.2 2021-04-04 18:50:11 +02:00
3bde426325 Fixed Checkbox
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-04-04 18:47:49 +02:00
b13a40ef18 Fixed Color changing while input is disabled
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-04-02 00:50:34 +02:00
e481160528 Fixed padding being added to block Inputs
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-04-02 00:48:20 +02:00
a0342050db Removed Margin from the UserMenu if it's the Navbar
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-04-01 23:44:44 +02:00
c1f37b6e7c body will not display if there is no body to display
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-04-01 23:41:40 +02:00
d2fbe42db8 Updated Navbar storybook to include an Image
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-04-01 23:34:37 +02:00
031971b859 v0.8.1 2021-04-01 23:34:02 +02:00
1488386e1d Merge branch 'master' of github.com:dzeiocom/components 2021-04-01 20:43:51 +02:00
26c2c50f23 v0.8.0 2021-04-01 10:19:52 +02:00
c591c2f0a8 Made Loader Stable
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-04-01 10:19:32 +02:00
7fe816c997 v0.7.6 2021-04-01 10:09:59 +02:00
7e28baf2aa Fixed Text
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-04-01 10:09:26 +02:00
b19992b57c v0.7.5 2021-04-01 09:57:32 +02:00
0bb84f9946 Fixed rollup config
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-04-01 09:57:08 +02:00
8cddeab594 v0.7.4 2021-03-31 14:40:22 +02:00
68939d8390 Fixed External link
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-31 14:38:33 +02:00
8186284ded GradientBackground is now stable
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-31 13:51:04 +02:00
e173bd2a37 Changed generated classes names to be shorter
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-31 10:48:48 +02:00
754da58a68 v0.7.3 2021-03-31 10:41:12 +02:00
3b314d5307 Fixed missing global file
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-31 10:40:45 +02:00
4a55f00ff0 v0.7.2 2021-03-31 10:17:23 +02:00
d30ae95a0d Fixed everything :D
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-31 10:16:46 +02:00
264e9a4cad v0.7.1 2021-03-31 09:55:47 +02:00
6a8fb50b0e Made Logo optionnal
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-31 09:54:20 +02:00
8c64a57a16 Merge branch 'master' of github.com:dzeiocom/components
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-03-30 21:33:54 +02:00
d2b5181a60 v0.7.0 2021-03-30 17:04:37 +02:00
95657b147a Finalised Navbar
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 17:04:16 +02:00
2bfcc6f4ad Misc changes to Link
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 16:59:04 +02:00
40ce098d63 Removed SidebarContainer
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 16:57:57 +02:00
b35ab42cc5 v0.6.4 2021-03-30 15:43:02 +02:00
c7487f27b8 Finally Fixed normaly
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 15:42:46 +02:00
dd179edc2a v0.6.3 2021-03-30 15:38:45 +02:00
c6436d0914 Try to fix compilation errors
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 15:38:29 +02:00
847f7f2649 v0.6.2 2021-03-30 15:34:33 +02:00
c58918268a Fixed missing file part 2
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 15:34:11 +02:00
3b65de9103 v0.6.1 2021-03-30 15:32:23 +02:00
208d0f8c06 Fixed missing file
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 15:32:10 +02:00
75ed12efea v0.6.0 2021-03-30 15:31:00 +02:00
2569db42f8 Changed back to prebuilt but this time it will build on install to allow theme.styl
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-30 15:30:26 +02:00
c1e40c6789 v0.5.4 2021-03-30 01:48:12 +02:00
bd0787d0ec Fixed Problems
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-03-30 01:47:40 +02:00
5f51088ab0 v0.5.3 2021-03-29 18:49:45 +02:00
d7a09a4dcd Finished Work On Navbar
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-03-29 18:49:23 +02:00
6c2b3466ba v0.5.2 2021-03-29 14:55:50 +02:00
31c9e30d3d Fixed Link colors
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-03-29 14:55:29 +02:00
0b60fa84ba v0.5.1 2021-03-29 14:07:38 +02:00
b586a32d00 Added back stylus utils
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-03-29 14:07:07 +02:00
ba3dcb22a1 v0.5.0 2021-03-29 14:01:46 +02:00
60f0ec23fc Updated Navbar Component
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-29 14:01:25 +02:00
803915999b v0.4.2 - Changed to be used only inconjonction with stylus
Signed-off-by: Avior <florian.bouillon@delta-wings.net>
2021-03-29 13:48:50 +02:00
af99c13922 v0.4.2 2021-03-29 13:43:03 +02:00
3d2fb93d72 v0.4.1 2021-03-29 13:32:26 +02:00
552f5b3dc6 v0.4.0 2021-03-29 12:48:16 +02:00
07dd430ffa Removed Tag element + Global Update
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-18 14:57:35 +01:00
6ff39ff3a7 Cleaned ignore files
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-15 17:28:58 +01:00
594e77a509 v0.3.1 2021-03-15 17:26:41 +01:00
8b12c56fe7 Moved types to the module folder
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-15 17:23:04 +01:00
3a908ccce0 Fixed Loader not found
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-15 17:22:40 +01:00
b34d25e5fd v0.3.0 2021-03-15 14:55:14 +01:00
67a4825cda Added a Loader module
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-15 14:54:27 +01:00
d898dc2f5b Fixed problems with Input and Fieldset
Signed-off-by: Florian BOUILLON <florian.bouillon@delta-wings.net>
2021-03-05 10:07:02 +01:00
8d99f1f3e6 v0.2.1 2021-03-05 10:06:11 +01:00
53 changed files with 3156 additions and 3075 deletions

13
.gitignore vendored
View File

@ -1,7 +1,12 @@
module/ module/
storybook-static/ node_modules/
*.mjs
*.js *.js
!src/dzeio/stylusUtils.js
*.d.ts
types/
!rollup.config.js
!src/stylus.d.ts
!.storybook/*.js
style.css style.css
yarn-error.log yarn-error.log
node_modules
types

View File

@ -1,11 +1,8 @@
.storybook/ .storybook/
src/ node_modules/
storybook-static/ *.stories.js
.gitattributes
.gitignore .gitignore
.npmignore .npmignore
rollup.config.js
tsconfig.json
yarn.lock yarn.lock
yarn-error.log
tsconfig.json
yarn-error.log yarn-error.log

View File

@ -1,11 +1,11 @@
const path = require("path"); const path = require("path");
const webpack = require('webpack')
module.exports = { module.exports = {
"stories": [ "stories": [
"../src/dzeio/**/*.stories.@(js|jsx|ts|tsx)", "../src/dzeio/**/*.stories.@(ts|tsx)",
], ],
"addons": [ "addons": [
"@storybook/addon-links",
"@storybook/addon-essentials" "@storybook/addon-essentials"
], ],
typescript: { typescript: {
@ -13,9 +13,22 @@ module.exports = {
checkOptions: {}, checkOptions: {},
reactDocgen: 'react-docgen-typescript', reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: { reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true, shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true), propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
}, },
}, },
presets: [path.resolve(__dirname, "./next.js")] presets: [path.resolve(__dirname, "./next.js")],
// Allow to use Next/Image
webpackFinal: (config) => {
config.plugins.push(new webpack.DefinePlugin({
'process.env.__NEXT_IMAGE_OPTS': JSON.stringify({
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
domains: [],
path: '/',
loader: 'default',
})
}))
return config
}
} }

View File

@ -0,0 +1,17 @@
// https://stackoverflow.com/a/64765638/7335674
import * as nextImage from 'next/image'
Object.defineProperty(nextImage, 'default', {
configurable: true,
value: (props) => {
return (
<div style={{display: 'inline-block', maxWidth: '100%', overflow: 'hidden', position: 'relative', boxSizing: 'border-box', margin: 0}}>
<div style={{boxSizing: 'border-box', display: 'block', maxWidth: '100%'}}>
<img {...props} alt="" aria-hidden="true" role="presentation" style={{maxWidth: '100%', display: 'block', margin: 0, border: 'none', padding: 0}} />
</div>
<img {...props} style={{position: 'absolute', inset: 0, boxSizing: 'border-box', padding: 0, border: 'none', margin: 'auto', display: 'block', width: 0, height: 0, minWidth: '100%', maxWidth: '100%', minHeight: '100%', maxHeight: '100%'}} />
</div>
)
},
})

View File

@ -0,0 +1,8 @@
import Router from 'next/router';
Router.router = {
push: async () => {},
replace: async () => {},
prefetch: () => {},
route: '/mock-route',
pathname: 'mock-path',};

View File

@ -18,12 +18,13 @@ module.exports = {
}); });
newConfig.resolve.extensions.push('.ts', '.tsx'); newConfig.resolve.extensions.push('.ts', '.tsx');
// SCSS // Stylus
newConfig.module.rules.push({ newConfig.module.rules.push({
test: /\.styl$/, test: /\.styl$/,
use: ['style-loader', { use: ['style-loader', {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
url: false,
importLoaders: 1, importLoaders: 1,
modules: true modules: true
}, },

View File

@ -1,4 +1,7 @@
import '../src/dzeio/general.styl'
import './mockNextRouter'
import './mockNextImage'
export const parameters = { export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" }, layout: 'centered'
} }

View File

@ -0,0 +1,3 @@
<svg width="90" height="38" viewBox="0 0 90 38" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="90" height="38" fill="#C4C4C4"/>
</svg>

After

Width:  |  Height:  |  Size: 150 B

View File

@ -1,20 +1,14 @@
{ {
"name": "@dzeio/components", "name": "@dzeio/components",
"version": "0.2.0", "version": "0.8.3",
"license": "MIT", "license": "MIT",
"main": "./index.js", "main": "./index.js",
"module": "./module/index.js",
"types": "./types/index.d.ts", "types": "./types/index.d.ts",
"dependencies": {},
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.16", "@babel/core": "^7.12.16",
"@babel/preset-env": "^7.12.16", "@babel/preset-env": "^7.12.16",
"@babel/preset-react": "^7.12.13", "@babel/preset-react": "^7.12.13",
"@rollup/plugin-typescript": "^8.2.0",
"@storybook/addon-actions": "^6.1.14",
"@storybook/addon-essentials": "^6.1.14", "@storybook/addon-essentials": "^6.1.14",
"@storybook/addon-knobs": "^6.1.14",
"@storybook/addon-links": "^6.1.14",
"@storybook/cli": "^6.1.14", "@storybook/cli": "^6.1.14",
"@storybook/react": "^6.1.14", "@storybook/react": "^6.1.14",
"@types/node": "^14.14.28", "@types/node": "^14.14.28",
@ -26,25 +20,31 @@
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-feather": "^2.0.9", "react-feather": "^2.0.9",
"rollup": "^2.39.0",
"rollup-plugin-styles": "^3.14.1",
"style-loader": "^2.0.0", "style-loader": "^2.0.0",
"stylus": "^0.54.8", "stylus": "^0.54.8",
"stylus-loader": "^4.3.3", "stylus-loader": "^4.3.3",
"ts-loader": "^8.0.17", "ts-loader": "^8.0.17",
"typescript": "^4.1.3", "typescript": "^4.2.3",
"webpack": "^4.44.2" "webpack": "^4.44.2"
}, },
"peerDependencies": { "peerDependencies": {
"next": "^10.0.5", "next": "^10.0.5",
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-feather": "^2.0.9" "react-feather": "^2.0.9",
"stylus": "^0.54.8",
"typescript": "^4.2.3"
}, },
"scripts": { "scripts": {
"storybook": "start-storybook -p 6006", "dev": "rm -rf src/dzeio/**/*.js && start-storybook -s ./.storybook/public -p 6006",
"build-storybook": "build-storybook", "build": "rollup --config",
"build": "tsc && rollup --config", "prepublishOnly": "yarn build",
"prepublishOnly": "yarn build" "postinstall": "rollup --config"
},
"dependencies": {
"rollup": "^2.44.0",
"rollup-plugin-styles": "^3.14.1",
"rollup-plugin-typescript2": "^0.30.0",
"tslib": "^2.1.0"
} }
} }

View File

@ -1,4 +1,4 @@
import typescript from '@rollup/plugin-typescript'; import typescript from 'rollup-plugin-typescript2';
import styles from 'rollup-plugin-styles' import styles from 'rollup-plugin-styles'
import pkg from './package.json'; import pkg from './package.json';
@ -12,20 +12,17 @@ export default [
url: false, url: false,
autoModules: true, autoModules: true,
mode: 'extract', mode: 'extract',
modules: {
generateScopedName: '[local][hash:5]'
}
}), }),
typescript(), // so Rollup can convert TypeScript to JavaScript typescript({useTsconfigDeclarationDir: true}), // so Rollup can convert TypeScript to JavaScript
], ],
output: [ output: [
{ {
dir: './', file: pkg.main,
format: 'cjs', format: 'cjs',
assetFileNames: 'style.css' assetFileNames: 'style.css'
},
{
file: pkg.module,
format: 'es',
assetFileNames: 'style.css'
} }
] ]
} }

View File

@ -3,19 +3,11 @@
.header .header
padding 16px padding 16px
.delimiter
border-bottom 2px solid grey
padding-bottom 2px
.img
border-top-left-radius 4px
border-top-right-radius 4px
.title .title
font-weight bold font-weight bold
font-size rem(20) font-size rem(18)
margin 0 0 8px margin 0 0 8px
.subtitle .subtitle
font-size rem(14) font-size rem(16)
margin 0 margin 0

View File

@ -11,21 +11,15 @@ export interface Props {
title?: string title?: string
titleColSize?: number titleColSize?: number
subtitle?: string subtitle?: string
delimiter?: boolean
titleClassName?: string titleClassName?: string
// image?: ImageProps
} }
export default class BoxHeader extends React.Component<Props> { export default class BoxHeader extends React.Component<Props> {
public render = () => ( public render = () => (
<> <>
{/* {this.props.image && (
<Image {...this.props.image} />
)} */}
<div className={buildClassName( <div className={buildClassName(
[css.header], css.header
[css.delimiter, this.props.delimiter]
)}> )}>
<Row> <Row>
<Col size={this.props.titleColSize as 1 || 8}> <Col size={this.props.titleColSize as 1 || 8}>

View File

@ -1,21 +1,12 @@
@import "../../config" @import "../../config"
.box .box
background white background $foregroundLight
@media (prefers-color-scheme dark)
background $foregroundDark
border-radius 8px border-radius 8px
box-shadow 0px 2px 4px 0px rgba(black, .33)
transition all $transition
.outline .outline
border 2px solid #E0E0E0 border 2px solid $grayDark
box-shadow none @media (prefers-color-scheme dark)
transition border-color $transition border-color $grayLight
&:hover
border-color darken(@border[2], 20%)
@media (prefers-color-scheme dark)
.box
background #202020
.outline
border-color #1F1F1F

View File

@ -32,15 +32,16 @@ export default class Box extends React.Component<Props> {
title={this.props.title} title={this.props.title}
titleColSize={this.props.titleColSize} titleColSize={this.props.titleColSize}
subtitle={this.props.subtitle} subtitle={this.props.subtitle}
delimiter={this.props.delimiter}
titleClassName={this.props.titleClassName} titleClassName={this.props.titleClassName}
> >
{this.props.headerButtons} {this.props.headerButtons}
</BoxHeader> </BoxHeader>
)} )}
<BoxBody noPadding={this.props.noPadding}> {this.props.children && (
{this.props.children} <BoxBody noPadding={this.props.noPadding}>
</BoxBody> {this.props.children}
</BoxBody>
)}
</BoxWrapper> </BoxWrapper>
) )
} }

View File

@ -5,28 +5,33 @@ $backColor = #757575
.label .label
position relative position relative
display flex display flex
padding-left 8px
margin 8px
user-select none user-select none
align-items center
+ .label
margin-top 8px
p p
margin-left 18px margin-left 8px
span span
top 0 top 0
left 0 left 0
width 20px width 20px
height @width height @width
position absolute position relative
box-shadow inset 0 0 0 2px $backColor box-shadow inset 0 0 0 2px $grayDark
border-radius 2px border-radius 2px
transition all $transition transition all $transition
@media (prefers-color-scheme dark)
box-shadow inset 0 0 0 2px $grayLight
&::after &::after
border-radius 20px border-radius 20px
position absolute position absolute
transition all $transition transition all $transition
background $default background $main
svg svg
transition $transition transition $transition
@ -41,19 +46,9 @@ $backColor = #757575
left 0 left 0
opacity 0 opacity 0
&:focus + span
box-shadow inset 0 0 0 2px black, 0 0 0 2px rgba(black,.3)
@media (prefers-color-scheme dark)
box-shadow inset 0 0 0 2px white, 0 0 0 2px rgba(white,.3)
&:focus:checked + span
box-shadow inset 0 0 0 2px $default, 0 0 0 2px rgba($default,.3)
@media (prefers-color-scheme dark)
box-shadow inset 0 0 0 2px $default, 0 0 0 2px rgba($default,.3)
&:checked + span &:checked + span
background rgba($default, .5) background rgba($main, .5)
box-shadow inset 0 0 0 2px $default box-shadow inset 0 0 0 2px $main
svg svg
color white color white
@ -67,7 +62,6 @@ $backColor = #757575
box-shadow inset 0 0 0 2px white box-shadow inset 0 0 0 2px white
.radio .radio
margin-left 18px // Margin + margin for Circle
span span
border-radius 20px border-radius 20px
@ -86,20 +80,19 @@ $backColor = #757575
.switch .switch
padding 2px 0 2px 10px // 2px base padding 10px circle padding padding 2px 0 2px 10px // 2px base padding 10px circle padding
&:hover span &:hover span::after
box-shadow none
&::after
background black background black
@media (prefers-color-scheme dark)
background white
span span
width 28px width 28px
height 14px height 14px
border-radius 20px border-radius 20px
top 50% top 50%
margin-right 10px
box-shadow none box-shadow none
background rgba($backColor, .5) background rgba($backColor, .5)
transform translateY(-50%)
&::after &::after
content " " content " "
@ -115,93 +108,39 @@ $backColor = #757575
width 20px width 20px
&:checked + span &:checked + span
box-shadow none
&::after &::after
left 100% left 100%
transform translate(-50%, -50%) transform translate(-50%, -50%)
background $default background $main
.primary
$color = $primary
checkBox($color)
input:checked + span input:checked + span
background rgba($color, .5) background rgba($color, .5)
box-shadow inset 0 0 0 2px $color box-shadow inset 0 0 0 2px $color
&::after &::after
background $color background $color
input:focus:checked + span
box-shadow inset 0 0 0 2px $color, 0 0 0 2px rgba($color,.3)
&.switch &.switch
input:checked + span input:checked + span
box-shadow none box-shadow none
.secondary
$color = $secondary
input:checked + span
background rgba($color, .5)
box-shadow inset 0 0 0 2px $color
&::after
background $color
&.switch
input:checked + span
box-shadow none
.info .info
$color = $info checkBox($infoLight)
@media (prefers-color-scheme dark)
input:checked + span checkBox($infoDark)
background rgba($color, .5)
box-shadow inset 0 0 0 2px $color
&::after
background $color
&.switch
input:checked + span
box-shadow none
.success .success
$color = $success checkBox($successLight)
@media (prefers-color-scheme dark)
checkBox($successDark)
input:checked + span .error
background rgba($color, .5) checkBox($errorLight)
box-shadow inset 0 0 0 2px $color @media (prefers-color-scheme dark)
checkBox($errorDark)
&::after
background $color
&.switch
input:checked + span
box-shadow none
.danger
$color = $danger
input:checked + span
background rgba($color, .5)
box-shadow inset 0 0 0 2px $color
&::after
background $color
&.switch
input:checked + span
box-shadow none
.warning .warning
$color = $warning checkBox($warningLight)
@media (prefers-color-scheme dark)
input:checked + span checkBox($warningDark)
background rgba($color, .5)
box-shadow inset 0 0 0 2px $color
&::after
background $color
&.switch
input:checked + span
box-shadow none

View File

@ -7,38 +7,32 @@ import css from './Checkbox.module.styl'
import Text from '../Text' import Text from '../Text'
interface Props extends React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> { interface Props extends React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> {
label?: string label: string
id: string type?: 'checkbox' | 'radio' | 'switch'
type?: undefined
radio?: boolean
switch?: boolean
color?: ColorType
} }
export default class Checkbox extends React.Component<Props> { export default class Checkbox extends React.Component<Props> {
public render() { public render() {
const props: Props = Object.assign({}, this.props) const props: Partial<Props> = Object.assign({}, this.props)
delete props.label delete props.label
delete props.type delete props.type
delete props.color
delete props.switch
delete props.radio
const realType = this.props.radio ? 'radio' : 'checkbox' const realType = this.props.type ?? 'checkbox'
return ( return (
<label htmlFor={this.props.id} className={buildClassName( <label htmlFor={this.props.id ?? this.props.label} className={buildClassName(
[css.label], [css.label],
[css.radio, realType === 'radio'], [css.radio, realType === 'radio'],
[css.switch, this.props.switch], [css.switch, realType === 'switch'],
[css[this.props.color as string], this.props.color] [css[this.props.color as string], this.props.color]
)}> )}>
<input {...props} <input {...props}
type={realType} id={this.props.id ?? this.props.label}
type={realType === 'switch' ? 'checkbox' : realType}
/> />
<span> <span>
{realType === 'checkbox' && ! this.props.switch && ( {realType === 'checkbox' && (
<Check strokeWidth={4} size={16}/> <Check strokeWidth={4} size={16}/>
)} )}
</span> </span>

View File

@ -3,3 +3,11 @@
background #E8EAF6 background #E8EAF6
padding 4px 8px padding 4px 8px
border-radius 8px border-radius 8px
.pre
border-radius 8px
padding 4px 8px
background #E8EAF6
display block
.code
padding 0

View File

@ -19,7 +19,7 @@ export default class Code extends React.Component<Props> {
} }
return ( return (
<pre> <pre className={css.pre}>
{code} {code}
</pre> </pre>
) )

View File

@ -3,7 +3,7 @@ import Row from '../Row'
import css from './DebugCols.module.styl' import css from './DebugCols.module.styl'
import Col from '.' import Col from '../Col'
enum Breakpoint { enum Breakpoint {
MOBILE, MOBILE,

View File

@ -2,7 +2,7 @@
.fieldset .fieldset
border-radius 4px border-radius 4px
border 2px solid grey border 2px solid $grayDark
transition all $transition transition all $transition
margin 0 margin 0

View File

@ -0,0 +1,16 @@
import { Meta } from '@storybook/react/types-6-0'
import React from 'react'
import Component from '.'
import Input from '../Input'
export default {
title: 'DZEIO/Fieldset',
component: Component,
argTypes: {
title: { control: 'text'}
}
} as Meta
export const Basic = (args: any) => (
<Component {...args}><Input label="Test" /></Component>
)

View File

@ -2,22 +2,27 @@
.footer .footer
padding 24px 16px padding 24px 16px
background $foregroundLight
@media (prefers-color-scheme dark)
background $foregroundDark
ul
list-type none
li
display inline-block
.animation .animation
animation grow 1s linear infinite animation grow 1s linear infinite
display inline-block display inline-block
vertical-align middle
margin 0 2px
@keyframes grow @keyframes grow
0% 0%
transform scale(1)
40% 40%
transform scale(1)
50%
transform scale(1.2)
60% 60%
transform scale(1)
70%
transform scale(1.2)
95% 95%
transform scale(1) transform scale(1)
50%
70%
transform scale(1.2)

View File

@ -0,0 +1,15 @@
import { Meta, Story } from '@storybook/react/types-6-0'
import React from 'react'
import Component from '.'
export default {
title: 'DZEIO/Footer',
component: Component,
} as Meta
export const Basic: Story<any> = (args: any) => <Component {...args} />
let tmp = Basic.bind({})
tmp.args = {links: [{name: 'test1', path: '/'}, {name: 'test2', path: '/'}, {name: 'test3', path: '/'}]}
export const Normal = tmp

View File

@ -1,13 +1,32 @@
import React from 'react' import React from 'react'
import { Heart } from 'react-feather'
import Link from '../Link'
import Text from '../Text' import Text from '../Text'
import css from './Footer.module.styl' import css from './Footer.module.styl'
export default class Footer extends React.Component { interface Props {
text?: string
company?: string
links?: Array<{
path: string
name: string
}>
}
export default class Footer extends React.Component<Props> {
public render = () => ( public render = () => (
<footer className={css.footer}> <footer className={css.footer}>
<Text align="center">Made with <span className={css.animation}>💗</span> by Dzeio</Text> {this.props.text ? (
<Text align="center">Copyright © 2020 Dzeio. All rights reserved.</Text> <Text align="center">{this.props.text}</Text>
) : (
<Text align="center">Made with <span className={css.animation}><Heart color={'#E6808A'} fill={'#E6808A'} size={16} fillOpacity={0.5} /></span> by {this.props.company || 'Dzeio'}</Text>
)}
{this.props.links && (
<ul>{this.props.links.map((l, index) => (
<li key={l.path}><Text>{index !== 0 && (<>&nbsp;- </>)}<Link href={l.path}>{l.name}</Link></Text></li>
))}</ul>
)}
</footer> </footer>
) )
} }

View File

@ -1,35 +1,31 @@
@import "../config" @import "../config"
$transparent = 75% $percent = 15%
.back .back
transition all $transition transition all $transition
background linear-gradient(to left, $default, transparentify($default, $transparent)) background $mainGradient
.primary &.fullscreen
$color = $primary min-height 100vh
background linear-gradient(to left, $color, transparentify($color, $transparent))
.secondary
$color = $secondary
background linear-gradient(to left, $color, transparentify($color, $transparent))
.info .info
$color = $info background linear-gradient(to right, $infoLight, lighten($infoLight, $percent))
background linear-gradient(to left, $color, transparentify($color, $transparent)) @media (prefers-color-scheme dark)
background linear-gradient(to right, $infoDark, darken($infoDark, $percent))
.success .success
$color = $success background linear-gradient(to right, $successLight, lighten($successLight, $percent))
background linear-gradient(to left, $color, transparentify($color, $transparent)) @media (prefers-color-scheme dark)
background linear-gradient(to right, $successDark, darken($successDark, $percent))
.danger .error
$color = $danger background linear-gradient(to right, $errorLight, lighten($errorLight, $percent))
background linear-gradient(to left, $color, transparentify($color, $transparent)) @media (prefers-color-scheme dark)
background linear-gradient(to right, $errorDark, darken($errorDark, $percent))
.warning .warning
$color = $warning background linear-gradient(to right, $warningLight, lighten($warningLight, $percent))
background linear-gradient(to left, $color, transparentify($color, $transparent)) @media (prefers-color-scheme dark)
background linear-gradient(to right, $warningDark, darken($warningDark, $percent))
@media (prefers-color-scheme dark)
.back
background $darkBackground

View File

@ -8,12 +8,18 @@ interface Props {
color?: ColorType color?: ColorType
className?: string className?: string
children: React.ReactNode children: React.ReactNode
fullscreen?: boolean
} }
/**
* Make the background a linear-gradient
*
* @version 1.0.1
*/
export default class GradientBackground extends React.Component<Props> { export default class GradientBackground extends React.Component<Props> {
public render = () => ( public render = () => (
<div className={buildClassName([css.back], [css[this.props.color as string], this.props.color], [this.props.className])}> <div className={buildClassName(css.back, [css[this.props.color as string], this.props.color], this.props.className, [css.fullscreen, this.props.fullscreen])}>
{this.props.children} {this.props.children}
</div> </div>
) )

View File

@ -6,7 +6,7 @@
max-width 100% max-width 100%
display inline-block display inline-block
+ .parent &:not(.block) + .parent:not(.block)
margin-left 16px margin-left 16px
label label
@ -34,7 +34,7 @@
left 16px // input padding-left left 16px // input padding-left
~ label ~ label
left 16px + 24px + 16px left 16px + 24px + 10px
&.right &.right
right 16px right 16px
@ -68,6 +68,7 @@
display flex display flex
opacity 0 opacity 0
transition all $transition transition all $transition
overflow-x hidden
pointer-events none pointer-events none
// display flex // display flex
flex-direction column flex-direction column
@ -109,10 +110,12 @@
@media (prefers-color-scheme dark) @media (prefers-color-scheme dark)
background lighten(lighten($foregroundDark, 5%), 20%) background lighten(lighten($foregroundDark, 5%), 20%)
div + .autocomplete
top calc(100% - 4px - .9em)
input:focus + .autocomplete input:focus ~ .autocomplete
select:focus + .autocomplete select:focus ~ .autocomplete
textarea:focus + .autocomplete textarea:focus ~ .autocomplete
.autocomplete:hover .autocomplete:hover
opacity 1 opacity 1
pointer-events inherit pointer-events inherit
@ -122,7 +125,7 @@
textarea textarea
padding 14px 16px padding 14px 16px
height 56px height 56px
border 2px solid rgba(black, .3) border 2px solid $grayDark
border-radius 4px border-radius 4px
max-width 100% max-width 100%
box-sizing border-box box-sizing border-box
@ -132,20 +135,9 @@
transition all $transition transition all $transition
color black color black
@media (prefers-color-scheme dark) @media (prefers-color-scheme dark)
border-color rgba(white, .3) border-color $grayLight
color white color white
&:not(:disabled):hover
border-color black
@media (prefers-color-scheme dark)
border-color white
+ svg
color black
@media (prefers-color-scheme dark)
color white
&:not(:placeholder-shown) &:not(:placeholder-shown)
&:focus &:focus
&:not([placeholder=" "]) &:not([placeholder=" "])
@ -168,27 +160,47 @@
~ label ~ label
color #999 color #999
&:invalid &:not(:disabled)
border-color $danger &:hover
border-color black
@media (prefers-color-scheme dark)
border-color white
~ label + svg
color @border-color color black
~ svg @media (prefers-color-scheme dark)
color @border-color color white
&:focus &:focus
border-color $default border-color $main
~ label ~ label
color @border-color color @border-color
~ svg
color @border-color
&:invalid
border-color $errorLight
~ label
color @border-color
~ svg
color @border-color
@media (prefers-color-scheme dark)
border-color $errorDark
~ label
color @border-color
~ svg
color @border-color
~ svg
color @border-color
&.iconLeft &.iconLeft
padding-left 16px + 24px + 16px padding-left 16px + 24px + 10px
&.iconRight &.iconRight
padding-right 16 + 24 + 16px padding-right 16 + 24 + 10px
&.filled &.filled
border none border none
background rgba(gray, .1) background rgba(gray, .1)
@ -205,7 +217,7 @@
@media (prefers-color-scheme dark) @media (prefers-color-scheme dark)
background #202020 background #202020
&:hover &:hover:not(:disabled)
background rgba(gray, .2) background rgba(gray, .2)
@media (prefers-color-scheme dark) @media (prefers-color-scheme dark)
@ -235,12 +247,12 @@
padding 0 padding 0
font-size .75rem font-size .75rem
~ svg.left ~ label ~ svg.left ~ label
left 16px + 24px + 16px // .input/padding-left label/padding-left left 16px + 24px + 10px // .input/padding-left label/padding-left
~ svg.rotate ~ svg.rotate
transform rotateX(0) transform rotateX(0)
transition $transition transition $transition
&:hover:focus ~ svg.rotate, ~.autocomplete:hover ~ svg.rotate &:focus ~ svg.rotate, ~.autocomplete:hover ~ svg.rotate
transform rotateX(180deg) transform rotateX(180deg)
div div
display flex display flex

View File

@ -1,10 +1,29 @@
import { Meta } from '@storybook/react/types-6-0' import { Meta } from '@storybook/react/types-6-0'
import { Story } from "@storybook/react"
import React from 'react' import React from 'react'
import Component from '.' import Component from '.'
import { X } from 'react-feather'
export default { export default {
title: 'DZEIO/Input', title: 'DZEIO/Input',
component: Component component: Component
} as Meta } as Meta
export const Basic = (args: any) => <Component {...args} /> export const Basic: Story<any> = (args: any) => <Component {...args} />
let tmp = Basic.bind({})
tmp.args = {label: 'Label', helper: 'Helper', maxLength: 6, characterCount: true, icon: X}
export const Normal = tmp
tmp = Basic.bind({})
tmp.args = {label: 'Label', filled:true, helper: 'Helper', autocomplete: ['a', 'b', 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'], characterCount: true, icon: X}
export const AutoComplete = tmp
export const Select: Story<any> = (args: any) => <Component type="select" {...args}>
<option>a</option>
<option>b</option>
<option>c</option>
<option>d</option>
</Component>

View File

@ -5,6 +5,7 @@ import Text from '../Text'
import { IconProps } from '../interfaces' import { IconProps } from '../interfaces'
import { buildClassName } from '../Util' import { buildClassName } from '../Util'
import css from './Input.module.styl' import css from './Input.module.styl'
import Row from '../Row'
interface Props extends React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> { interface Props extends React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> {
id?: string id?: string
@ -37,6 +38,8 @@ interface States {
export default class Input extends React.Component<Props, States> { export default class Input extends React.Component<Props, States> {
public state: States = {}
// any because f*ck types // any because f*ck types
private inputRef: React.RefObject<any> = React.createRef() private inputRef: React.RefObject<any> = React.createRef()
private parentRef: React.RefObject<HTMLDivElement> = React.createRef() private parentRef: React.RefObject<HTMLDivElement> = React.createRef()
@ -50,11 +53,14 @@ export default class Input extends React.Component<Props, States> {
} }
if (this.props.autocomplete) { if (this.props.autocomplete) {
window.addEventListener('scroll', this.parentScroll) window.addEventListener('scroll', this.parentScroll)
this.parentScroll()
} }
} }
public componentWillUnmount() { public componentWillUnmount() {
window.removeEventListener('scroll', this.parentScroll) if (this.props.autocomplete) {
window.removeEventListener('scroll', this.parentScroll)
}
} }
public render() { public render() {
@ -65,7 +71,9 @@ export default class Input extends React.Component<Props, States> {
delete props.opaque delete props.opaque
delete props.helper delete props.helper
delete props.infinityText delete props.infinityText
delete props.autocomplete
delete props.filled delete props.filled
delete props.iconRight
delete props.inputRef delete props.inputRef
delete props.selectRef delete props.selectRef
delete props.block delete props.block
@ -77,7 +85,7 @@ export default class Input extends React.Component<Props, States> {
ref: this.props.inputRef || this.inputRef, ref: this.props.inputRef || this.inputRef,
className: buildClassName( className: buildClassName(
[css.iconLeft, this.props.icon], [css.iconLeft, this.props.icon],
[css.iconRight, this.props.iconRight], [css.iconRight, this.props.iconRight || this.props.autocomplete],
[css.filled, this.props.filled], [css.filled, this.props.filled],
[css.opaque, this.props.opaque] [css.opaque, this.props.opaque]
), ),
@ -94,7 +102,7 @@ export default class Input extends React.Component<Props, States> {
input = ( input = (
<select <select
ref={this.props.selectRef || this.inputRef} ref={this.props.selectRef || this.inputRef}
{...this.props as React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>} {...props as React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>}
className={buildClassName( className={buildClassName(
[css.iconLeft, this.props.icon], [css.iconLeft, this.props.icon],
[css.iconRight, !this.props.disabled || this.props.iconRight], [css.iconRight, !this.props.disabled || this.props.iconRight],
@ -138,12 +146,6 @@ export default class Input extends React.Component<Props, States> {
> >
{input} {input}
{this.props.autocomplete && this.props.autocomplete.indexOf(this.state?.value || '') === -1 && (
<ul className={buildClassName(css.autocomplete, [css.reverse, !this.state?.isInFirstPartOfScreen])}>
{this.props.autocomplete.filter((item) => item.includes(this.state?.value || '')).map((item) => (<li key={item} onClick={this.onAutoCompleteClick(item)}><Text>{item}</Text></li>))}
</ul>
)}
{/* Process Icon */} {/* Process Icon */}
{this.props.icon && ( {this.props.icon && (
<this.props.icon className={css.left} /> <this.props.icon className={css.left} />
@ -167,6 +169,12 @@ export default class Input extends React.Component<Props, States> {
)} )}
</div> </div>
)} )}
{this.props.autocomplete && this.props.autocomplete.indexOf(this.state?.value || '') === -1 && (
<ul className={buildClassName(css.autocomplete, [css.reverse, !this.state.isInFirstPartOfScreen])}>
{this.props.autocomplete.filter((item) => item.includes(this.state?.value || '')).map((item) => (<li key={item} onClick={this.onAutoCompleteClick(item)}><Text>{item}</Text></li>))}
</ul>
)}
</div> </div>
) )
} }
@ -175,6 +183,7 @@ export default class Input extends React.Component<Props, States> {
const div = this.parentRef.current const div = this.parentRef.current
if (!div) {return} if (!div) {return}
const result = !(div.offsetTop - window.scrollY >= window.innerHeight / 2) const result = !(div.offsetTop - window.scrollY >= window.innerHeight / 2)
console.log(result, div, this.state.isInFirstPartOfScreen)
if (this.state.isInFirstPartOfScreen !== result) { if (this.state.isInFirstPartOfScreen !== result) {
this.setState({isInFirstPartOfScreen: result}) this.setState({isInFirstPartOfScreen: result})
} }

View File

@ -1,3 +1,12 @@
@import '../config'
.link
color $infoDark
@media (prefers-color-scheme dark)
color $infoLight
&:hover
text-decoration underline
.icon .icon
vertical-align sub vertical-align sub
margin 2px margin 2px

View File

@ -3,22 +3,34 @@ import NextLink from 'next/link'
import { ExternalLink } from 'react-feather' import { ExternalLink } from 'react-feather'
import css from './Link.module.styl' import css from './Link.module.styl'
import { buildClassName } from '../Util'
interface Props { interface Props {
linkProps?: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>
href: string href: string
children?: React.ReactNode children?: React.ReactNode
className?: string className?: string
forceNewTab?: boolean /**
* Remove styling
*/
noStyle?: boolean
/**
* Override external detection system
*/
external?: boolean
} }
export default class Link extends React.Component<Props> { export default class Link extends React.Component<Props> {
public render() { public render() {
if (!this.props.href.startsWith('/')) { const external = this.props.external ?? this.props.href.startsWith('http')
if (external) {
// external link // external link
return ( return (
<a <a
className={this.props.className} {...this.props.linkProps}
className={buildClassName(this.props.className, [css.link, !this.props.noStyle])}
href={this.props.href} href={this.props.href}
rel="noreferrer nofollow" rel="noreferrer nofollow"
target="_blank" target="_blank"
@ -30,9 +42,8 @@ export default class Link extends React.Component<Props> {
return ( return (
<NextLink href={this.props.href}> <NextLink href={this.props.href}>
<a <a
className={this.props.className} {...this.props.linkProps}
target={this.props.forceNewTab ? '_blank' : undefined} className={buildClassName(this.props.className, [css.link, !this.props.noStyle])}
rel={this.props.forceNewTab ? 'noreferrer nofollow' : undefined}
>{this.props.children}</a> >{this.props.children}</a>
</NextLink> </NextLink>
) )

View File

@ -0,0 +1,19 @@
@import '../config'
.div
position fixed
left 0
width 100%
height 7px
pointer-events none
z-index 200
top 0
&.hide
transition top .5s ease-in-out
top -7px
div
&:not([style="width: 0px;"])
transition width 50ms ease-in-out
background rgba($main, .7)
height 100%

View File

@ -0,0 +1,97 @@
import { Router } from 'next/router'
import React from 'react'
import { buildClassName } from '../Util'
import css from './Loader.module.styl'
interface Props {
/**
* The new Percentage (if you calculate it yourself)
*/
percent?: number
/**
* Auto random loader
*/
auto?: {
/**
* the minimum and maximum interval between two increment
*/
interval: [number, number]
/**
* the minimum and maximum incrementation (MUST be an integer)
*/
increment: [number, number]
}
}
interface State {
percent?: number
}
/**
* Display a simple loading animation at the top of the page
*
* @version 1.0.0
*/
export default class Loader extends React.Component<Props, State> {
public state: State = {}
private interval?: NodeJS.Timeout
public componentDidMount() {
if (this.props.auto) {
Router.events.on('routeChangeComplete', this.routeChangeComplete)
Router.events.on('routeChangeStart', this.routeChangeStart)
}
}
public componentWillUnmount() {
if (this.props.auto) {
Router.events.off('routechangeComplete', this.routeChangeComplete)
Router.events.off('routechangeStart', this.routeChangeStart)
}
}
public render = () => (
<div className={buildClassName(css.div, [css.hide, (this.props.percent || this.state.percent) === 100])}>
<div style={{width: (this.props.percent || this.state.percent) ? `${(this.props.percent || this.state.percent)}%` : 0}}></div>
</div>
)
private routeChangeComplete = () => {
if (this.interval) {
clearTimeout(this.interval)
this.interval = undefined
}
this.setState({percent: 100})
}
private routeChangeStart = () => {
if (this.interval) {
clearTimeout(this.interval)
}
this.setState({percent: 0}, () => {
if (!this.props.auto) {return}
this.interval = setTimeout(this.timeoutFn, this.randomInt(this.props.auto.interval[0], this.props.auto.interval[1]))
})
}
private timeoutFn = () => {
if (!this.props.auto) {return}
const p = this.state.percent || 0
this.setState({
percent: Math.min(
99,
p >= 80 ? p + Math.random() : p + this.randomInt(this.props.auto.increment[0], this.props.auto.increment[1])
)
})
this.interval = setTimeout(this.timeoutFn, this.randomInt(this.props.auto.interval[0], this.props.auto.interval[1]))
}
private randomInt(min = 0, max = 10) {
min = Math.ceil(min)
max = Math.floor(max)
return Math.floor(Math.random() * (max - min + 1)) + min
}
}

View File

@ -1,49 +1,231 @@
@import "../config" @import '../config'
// $transition = 10s linear
// $transitionTime = 10s
// $transitionFunction = linear
.body-sidebar
margin-left 300px
transition margin-left $transition
&.short
margin-left 56px
.body-navbar
margin-top 70px
.navbar .navbar
width 100% background $foregroundLight
height 70px @media (prefers-color-scheme dark)
padding 16px background $foregroundDark
position absolute position fixed
top 0
left 0 left 0
border-bottom 1px solid white top 0
&.small
padding-left 216px
.alignRight
text-align right
.favicon img
height 38px
border-radius 8px
border 2px solid white
padding 2px
background white
width 38px
.userIcon img
padding 0
cursor pointer
.text
display inline-block
margin 0
height 38px
line-height 1
font-weight bold
font-size rem(20)
padding 7px 0 11px 16px
text-decoration none
color white
cursor pointer
.spacer
height 70px height 70px
width 100%
z-index 100
display flex
padding 16px
.icon > ul, .userSpaceParent ul
padding 7px 16px display flex
color white
box-sizing content-box li:first-child p
cursor pointer margin-left 0
> ul p, .userSpaceParent > ul p
padding 8px
margin-left 16px
border-radius 4px
&.active
background $mainGradient
color $textOnMain
.userSpace
height 100%
display flex
align-items center
cursor pointer
user-select none
svg
margin-left 16px
vertical-align top
.userMenu
position fixed
top 70px
right 0
padding 16px
border-bottom-left-radius 4px
transform translateX(100%)
background inherit
transition transform $transition
&.menuActive
transform translateX(0%)
.sidebar
background $foregroundLight
@media (prefers-color-scheme dark)
background $foregroundDark
position fixed
left 0
top 0
height 100vh
width 300px
z-index 100
display flex
flex-direction column
&.mobile
width 100%
z-index 101
&
transition width $transition
.header
.userSpace
.header .imgContainer
> ul span
// transition all $transition
transition-property width, padding, margin, max-width
transition-duration $transitionTime
transition-timing-function $transitionFunction
overflow hidden
> ul span
width calc(100% - 40px)
max-width 100%
.header p
cursor pointer
.userSpaceParent
background $backgroundLight
@media (prefers-color-scheme dark)
background $backgroundDark
> ul, .userSpaceParent ul
display flex
padding 16px
justify-content center
li:first-child p
margin-left 0
> ul p, .userSpaceParent > ul p
padding 8px
margin-left 16px
border-radius 4px
&.active
background $mainGradient
color $textOnMain
.userSpace
cursor pointer
user-select none
padding 16px
width 100%
max-width 100%
min-height 86px
p
overflow hidden
white-space nowrap
p:last-child:not(:first-child)
margin-top 8px
font-style italic
font-size rem(14)
p:first-child
font-weight 500
svg
vertical-align top
transition transform $transition
&.menuActive
transform rotateX(180deg)
.userMenu
max-height 0px
transition all $transition
&.menuActive
// TODO find better way to animate this shit
max-height 100%
&.short
width 56px
.header > div
padding 0
.header .imgContainer
.userSpace
> ul span
width 0
padding-left 0
padding-right 0
margin 0
max-width 0
.header
min-height 70px
padding 0
margin 0
> div p > div
> div:first-child
padding 16px
> div:last-child
padding 0
hr
margin 0
> ul li
width 100%
p
padding 16px 0
display flex
align-items center
z-index 111
position relative
// Temporary fix the transition for linear-gradient
&::before
transition opacity $transition
opacity 0
width 100%
height 100%
content " "
position absolute
z-index -1
background-image $mainGradient
&:hover
&.active
color $textOnMain
&::before
opacity 1
svg
margin-left 16px
span
padding-left 16px
height inherit
.navbar, .sidebar
ul
list-style none
margin 0
padding 0
.userMenu a
padding 16px 0
.mobileMenu
opacity 0
transition opacity $transition
&.shown
opacity 1
.mainGradient
//WIP
fill $mainGradient

View File

@ -1,4 +1,4 @@
import { Meta } from '@storybook/react/types-6-0' import { Meta, Story } from '@storybook/react/types-6-0'
import React from 'react' import React from 'react'
import Component from '.' import Component from '.'
@ -7,4 +7,24 @@ export default {
component: Component component: Component
} as Meta } as Meta
export const Basic = (args: any) => <Component {...args} /> export const Basic: Story<any> = (args: any) => <Component {...args} />
Basic.args = {
items: [{
path: '/dashboard',
name: 'Dasboard'
}],
loginUrl: '/login',
registerUrl: '/register',
type: 'navbar',
user: {
name: 'Username',
description: 'User Description',
menu: {
links: [{
path: '/logout',
name: 'Logout'
}]
}
},
logo: {src: '/90-38.svg', width: 90, height: 38}
}

View File

@ -1,11 +0,0 @@
import React from 'react'
import css from './Navbar.module.styl'
export default class NavbarSpace extends React.Component {
public render = () => (
<div className={css.spacer}></div>
)
}

View File

@ -1,48 +1,273 @@
import React from 'react' import Router from 'next/router'
import Link from 'next/link'
import Row from '../Row' import Image, { ImageProps } from 'next/image'
import React, { FC } from 'react'
import { ChevronDown, ChevronsRight, Menu, X } from 'react-feather'
import Text from '../Text'
import Col from '../Col' import Col from '../Col'
import Image from '../Image' import Row from '../Row'
import Link from '../Link'
import { buildClassName } from '../Util'
import css from './Navbar.module.styl' import css from './Navbar.module.styl'
interface Props { interface Props {
logo?: { /**
link?: string * Type of Navbar
label?: string * _note: when in mobile it is not listened_
src: string */
alt?: string type: 'navbar' | 'sidebar'
/**
* Logo to display
*/
logo?: ImageProps & {height: number, width: number}
/**
* Login URL
*/
loginUrl?: string
/**
* Login URL
*/
registerUrl?: string
/**
* User Informations if loggedin
*/
user?: {
/**
* Username
*/
name: string
/**
* User Short description
*/
description?: string
/**
* User Menu
*/
menu?: {
/**
* Menu links
*/
links: Array<{
path: string
name: string
}>
/**
* Custom informations shown next to the links
*/
informations?: JSX.Element
}
} }
/**
* Links to display
*/
items: Array<{
path: string
icon?: FC
name: string
}>
/**
* Internal Use don't use it !
*/
mobileMenu?: () => void
} }
export default class Navbar extends React.Component<Props> { interface State {
path?: string
short: boolean
isMobile: boolean
menuActive: boolean
}
/**
* Navbar/Sidebar Component
* @version 1.0.2
*/
export default class Navbar extends React.Component<Props, State> {
public state: State = {
short: false,
isMobile: false,
menuActive: false
}
public componentDidMount() {
this.setState({
path: Router.asPath,
menuActive: !!this.props.mobileMenu
})
Router.events.on('routeChangeComplete', () => {
this.setState({path: Router.asPath, menuActive: false})
})
Router.events.on('routeChangeError', () => {
this.setState({path: Router.asPath, menuActive: false})
})
if (!this.props.mobileMenu) {
window.addEventListener('resize', this.onResize)
this.onResize()
}
}
public onResize = () => {
const isMobile = window.innerWidth <= 768
if (this.state.isMobile !== isMobile) {
this.setState({isMobile})
}
}
public componentDidUpdate() {
if (!this.props.mobileMenu) {
if (this.state.short) {
document.body.classList.add(css.short)
} else {
document.body.classList.remove(css.short)
}
if (this.getType() === 'sidebar') {
document.body.classList.add(css['body-sidebar'])
document.body.classList.remove(css['body-navbar'])
} else {
document.body.classList.remove(css['body-sidebar'])
document.body.classList.add(css['body-navbar'])
}
}
}
public componentWillUnmount() {
if (!this.props.mobileMenu) {
document.body.classList.remove(css.short, css[`body-${this.getType()}`])
window.removeEventListener('resize', this.onResize)
}
}
public onSidebarButton = () => {
if (!this.props.mobileMenu) {
this.setState({short: !this.state.short, menuActive: false})
} else {
this.props.mobileMenu()
}
}
public menuCloseCallback = () => {
this.setState({menuActive: false})
}
public getType(): 'sidebar' | 'navbar' {
if (this.props.mobileMenu) {
return 'sidebar'
}
return this.state.isMobile ? 'navbar' : this.props.type
}
public render = () => ( public render = () => (
<nav className={css.navbar}> <>
<Row nomargin> <nav className={buildClassName(css[this.getType()], [css.short, this.state.short && !this.props.mobileMenu], [css.mobile, this.props.mobileMenu])}>
{this.props.logo && ( <Row nowrap className={css.header} align="center">
<Col> {this.props.logo && (
<Row align="center"> <Col className={css.imgContainer}>
<Link href={this.props.logo.link || '/'}> <Link href="/">
<a aria-label={this.props.logo.label || 'Homepage'}> <Image {...this.props.logo} height={34} width={this.props.logo.width*34/this.props.logo.height} />
<Image
alt={this.props.logo.alt}
src={this.props.logo.src}
height={38}
width={120}
/>
</a>
</Link> </Link>
</Row> </Col>
</Col> )}
{this.getType() === 'sidebar' && (
<Col nogrow><Text><div onClick={this.onSidebarButton}>
{this.state.short ? (
<ChevronsRight size={30} />
) : (
<X size={30} />
)}
</div></Text></Col>
)}
</Row>
{this.getType() === 'sidebar' && (
<hr/>
)} )}
<ul>
{!this.state.isMobile && this.props.items.map((item) => (
<li key={item.path}><Link noStyle href={item.path}><a>
<Text className={buildClassName([css.active, this.state.path?.startsWith(item.path)])}>
{this.getType() === 'sidebar' && item.icon && (
<item.icon />
)}
<span>{item.name}</span>
</Text>
</a></Link></li>
))}
</ul>
<div style={{flex: 1}}></div>
{/* Spacer */}
{this.state.isMobile && (
<div className={css.userSpaceParent}>
<div onClick={() => this.setState({menuActive: !this.state.menuActive})} className={css.userSpace}>
<Text>
<Menu size={38} className={css.mainGradient} />
</Text>
</div>
</div>
)}
{!this.state.isMobile && this.props.user ? (
<>
<div className={css.userSpaceParent}>
{this.getType() === 'sidebar' && (
<hr/>
)}
<div onClick={() => this.setState({menuActive: !this.state.menuActive})} className={css.userSpace}>
<Text>
{this.props.user.name}
<ChevronDown className={buildClassName([css.menuActive, this.state.menuActive])} />
</Text>
{this.getType() === 'sidebar' && this.props.user.description && (
<Text>{this.props.user.description}</Text>
)}
</div>
</div>
<div className={buildClassName(css.userMenu, [css.menuActive, !this.state.isMobile && this.state.menuActive])}>
<Row nomargin={this.getType() === 'navbar'}>
{this.props.user.menu?.informations && (
<Col>{this.props.user.menu?.informations}</Col>
)}
<Col>
<ul>
{this.props.user.menu?.links.map((l) => (
<li key={l.path}><Text><Link noStyle href={l.path}>{l.name}</Link></Text></li>
))}
</ul>
</Col>
</Row>
</div>
</>
) : !this.state.isMobile ? (
<div className={css.userSpaceParent}>
{this.getType() === 'sidebar' && (
<hr/>
)}
<ul>
{this.props.registerUrl && (
<li><Link noStyle href={this.props.registerUrl}><a>
<Text className={buildClassName(css.active)}>
<span>Register</span>
</Text>
</a></Link></li>
)}
{this.props.loginUrl && (
<li><Link noStyle href={this.props.loginUrl}><a>
<Text>
<span>Login</span>
</Text>
</a></Link></li>
)}
</ul>
</div>
) : undefined}
</nav>
<Col> {!this.props.mobileMenu && this.state.isMobile && (
<Row justify="flex-end" align="center"> <div className={buildClassName(css.mobileMenu, [css.shown, this.state.menuActive])}>
{this.props.children} <Navbar {...this.props} type="sidebar" mobileMenu={this.menuCloseCallback} />
</Row> </div>
</Col> )}
</Row> </>
</nav>
) )
} }

View File

@ -6,22 +6,38 @@
width 100% width 100%
top 0 top 0
left 0 left 0
background rgba(black, .3) background rgba($backgroundLight, .7)
@media (prefers-color-scheme dark)
background rgba($backgroundDark, .7)
cursor pointer cursor pointer
z-index 1000 z-index 200
animation fadeIn .3s ease-in-out 1 forwards
@keyframes fadeIn
from
opacity 0
to
opacity 1
.popupChild .popupChild
cursor initial cursor initial
z-index 1001 z-index 201
min-width 50% min-width 50%
animation popin .3s ease-in-out 1
@media (max-width $tablet) @media (max-width $tablet)
min-width 70% min-width 70%
@media (max-width $mobile) @media (max-width $mobile)
min-width 90% min-width 90%
// min-height 50vh
@keyframes popin
from
margin-top 50px
to
margin-top 0
.exit .exit
cursor pointer cursor pointer

View File

@ -3,14 +3,12 @@
.row .row
display flex display flex
flex-wrap wrap flex-wrap wrap
margin (0 - $gapSize) 0 0 (0 - $gapSize)
padding $gapSize
&:not(.nomargin) &.nomargin
margin (0 - $gapSize) 0 0 .row
padding 0 $gapSize * 2 0 $gapSize padding 0
.row:not(.nomargin)
padding 0
margin (0 - $gapSize) 0 0 (0 - $gapSize)
.nowrap .nowrap
flex-wrap nowrap flex-wrap nowrap

View File

@ -1,32 +0,0 @@
@import "../config.styl"
.sidebar
position fixed
width 200px
top 0
left 0
height 100%
background white
padding 16px
.content
padding-left 200px
.item
display flex
padding 8px 16px
margin-top 8px
transition $transition
border-radius 8px
svg
margin-right 8px
div
text-align center
flex-grow 1
margin-left -32px
&:hover
background $default
color white

View File

@ -1,45 +0,0 @@
import React, { FC } from 'react'
import { ChevronLeft, TrendingUp } from 'react-feather'
import Link from 'next/link'
import Image from '../Image'
import { IconProps } from '../interfaces'
import css from './SidebarContainer.module.styl'
interface Props {
domain: string
children: React.ReactNode
}
export default class SidebarContainer extends React.Component<Props> {
private menu: Array<{name: string, icon: FC<IconProps>, href: string, as?: string}> = [
{ name: 'back', icon: ChevronLeft, href: '/dashboard' },
{ name: 'Uptime', icon: TrendingUp, as: `/dashboard/${this.props.domain}/uptime`, href: '/dashboard/[domain]/uptime' }
]
public render = () => (
<>
<nav className={css.sidebar}>
<Link href="/dashboard">
<a>
<Image src="/assets/logo.svg" width={175} height={100} />
</a>
</Link>
{this.menu.map((item, index) => (
<Link key={index} href={item.href} as={item.as}>
<a className={css.item}>
<item.icon />
<div>{item.name}</div>
</a>
</Link>
))}
</nav>
<div className={css.content}>
{this.props.children}
</div>
</>
)
}

View File

@ -1,139 +0,0 @@
@import '../config'
.tag
padding 8px 12px
border-radius 8px
margin-left 8px
height 32px
line-height 1
display inline-block
color white
background $default
outline none
&:hover
background darken($default, 10%)
&:focus
background darken($default, 20%)
&.outline
border 2px solid $default
padding 6px 10px
background transparent
&:hover
background rgba($default, .5)
&:focus
background rgba($default, .7)
.primary
$color = $primary
color white
background $color
&:hover
background lighten($color, 30%)
&:focus
background lighten($color, 15%)
&.outline
color black
border 2px solid $color
background transparent
&:hover
color white
background rgba($color, .5)
&:focus
color white
background rgba($color, .7)
.secondary
$color = $secondary
background $color
&:hover
background lighten($color, 30%)
&:focus
background lighten($color, 15%)
&.outline
color white
border 2px solid $color
background transparent
&:hover
color black
background rgba($color, .5)
&:focus
color black
background rgba($color, .7)
.info
$color = $info
color white
background $color
&:hover
background lighten($color, 30%)
&:focus
background lighten($color, 15%)
&.outline
color black
border 2px solid $color
background transparent
&:hover
color white
background rgba($color, .5)
&:focus
color white
background rgba($color, .7)
.success
$color = $success
color white
background $color
&:hover
background lighten($color, 30%)
&:focus
background lighten($color, 15%)
&.outline
color black
border 2px solid $color
background transparent
&:hover
color white
background rgba($color, .5)
&:focus
color white
background rgba($color, .7)
.danger
$color = $danger
color white
background $color
&:hover
background lighten($color, 30%)
&:focus
background lighten($color, 15%)
&.outline
color black
border 2px solid $color
background transparent
&:hover
color white
background rgba($color, .5)
&:focus
color white
background rgba($color, .7)
.warning
$color = $warning
color white
background $color
&:hover
background lighten($color, 30%)
&:focus
background lighten($color, 15%)
&.outline
color black
border 2px solid $color
background transparent
&:hover
color white
background rgba($color, .5)
&:focus
color white
background rgba($color, .7)

View File

@ -1,17 +0,0 @@
import { Meta } from '@storybook/react/types-6-0'
import React from 'react'
import Component from '.'
export default {
title: 'DZEIO/Tag',
component: Component
} as Meta
export const Basic = (args: any) => {
const content = args.content
delete args.content
return (
<Component {...args}>{content}</Component>
)
}

View File

@ -1,42 +0,0 @@
import React from 'react'
import { ColorType } from '../interfaces'
import { buildClassName } from '../Util'
import Link from '../Link'
import css from './Tag.module.styl'
import Text from '../Text'
interface Props {
text: string
color?: ColorType
href?: string
outline?: boolean
}
export default class Tag extends React.Component<Props> {
public render() {
const classes = buildClassName(
css.tag,
[css[this.props.color as string], this.props.color],
[css.outline, this.props.outline]
)
if (!this.props.href) {
return (
<Text
className={classes}
>{this.props.text}</Text>
)
}
return (
<Link
href={this.props.href}
className={classes}
>
{this.props.text}
</Link>
)
}
}

View File

@ -12,7 +12,6 @@ interface Props {
export default class Text extends React.Component<Props> { export default class Text extends React.Component<Props> {
public render() { public render() {
const classes = buildClassName( const classes = buildClassName(
css.text, css.text,
@ -23,16 +22,10 @@ export default class Text extends React.Component<Props> {
this.props.className this.props.className
) )
switch (this.props.type || 'p') { if (this.props.type === 'em') {
case 'h1': return (<h1 className={classes}>{this.props.children}</h1>) return (<p className={classes}><em>{this.props.children}</em></p>)
case 'h2': return (<h2 className={classes}>{this.props.children}</h2>)
case 'h3': return (<h3 className={classes}>{this.props.children}</h3>)
case 'h4': return (<h4 className={classes}>{this.props.children}</h4>)
case 'h5': return (<h5 className={classes}>{this.props.children}</h5>)
case 'h6': return (<h6 className={classes}>{this.props.children}</h6>)
case 'em': return (<p className={classes}><em>{this.props.children}</em></p>)
case 'span': return (<span className={classes}>{this.props.children}</span>)
default: return (<p className={classes}>{this.props.children}</p>)
} }
return React.createElement(this.props.type || 'p', {className: classes, children: this.props.children})
} }
} }

View File

@ -24,13 +24,3 @@ export function buildClassName(...classes: Array<Array<any> | string | undefined
} }
return classesFinal.join(' ') return classesFinal.join(' ')
} }
export const colors = {
default: '#3949AB', // This color should never appear
primary: '#3949AB',
secondary: '#FCFCFC',
info: '#03A9F4',
success: '#2DCE89',
danger: '#F5365C',
warning: '#FB6340'
}

View File

@ -52,3 +52,9 @@ $success = $successLight
$danger = $errorLight $danger = $errorLight
$warning = $warningLight $warning = $warningLight
$darkBackground = $backgroundDark $darkBackground = $backgroundDark
// See https://github.com/stylus/stylus/issues/1872#issuecomment-86553717
use('stylusUtils.js')
@import '../../../../../../theme' if file-exists('../../../../../../theme.styl')

View File

@ -27,13 +27,16 @@ a
} }
/* Track */ /* Track */
::-webkit-scrollbar-corner
::-webkit-scrollbar-track ::-webkit-scrollbar-track
background $foregroundLight background $foregroundLight
transition $transition
@media (prefers-color-scheme dark) @media (prefers-color-scheme dark)
background $foregroundDark background $foregroundDark
::-webkit-scrollbar-thumb ::-webkit-scrollbar-thumb
background: darken($foregroundLight, 16%) background: darken($foregroundLight, 16%)
transition $transition
@media (prefers-color-scheme dark) @media (prefers-color-scheme dark)
background lighten($foregroundDark, 16%) background lighten($foregroundDark, 16%)
&:hover &:hover

View File

@ -1,6 +1,6 @@
import { SVGAttributes } from 'react' import { SVGAttributes } from 'react'
export type ColorType = 'primary' | 'info' | 'success' | 'error' | 'warning' export type ColorType = 'info' | 'success' | 'error' | 'warning'
export interface IconProps extends SVGAttributes<SVGElement> { export interface IconProps extends SVGAttributes<SVGElement> {
color?: string color?: string

11
src/dzeio/stylusUtils.js Normal file
View File

@ -0,0 +1,11 @@
// See https://github.com/stylus/stylus/issues/1872#issuecomment-86553717
var stylus = require('stylus');
module.exports = function() {
return function(style) {
style.define('file-exists', function(path) {
return !!stylus.utils.lookup(path.string, this.paths);
});
};
};

View File

@ -1,4 +1,12 @@
import Box, { BoxBody, BoxHeader, BoxWrapper } from './dzeio/Box' /**
* Copyright (c) 2021
*
* @summary DZEIO Component Library
*/
import './dzeio/general.styl'
import Box from './dzeio/Box'
import Button from './dzeio/Button' import Button from './dzeio/Button'
import Checkbox from './dzeio/Checkbox' import Checkbox from './dzeio/Checkbox'
import Code from './dzeio/Code' import Code from './dzeio/Code'
@ -7,28 +15,21 @@ import Container from './dzeio/Container'
import Fieldset from './dzeio/Fieldset' import Fieldset from './dzeio/Fieldset'
import Footer from './dzeio/Footer' import Footer from './dzeio/Footer'
import GradientBackground from './dzeio/GradientBackground' import GradientBackground from './dzeio/GradientBackground'
import Input from './dzeio/Input'
import Image from './dzeio/Image' import Image from './dzeio/Image'
import Input from './dzeio/Input'
import Link from './dzeio/Link' import Link from './dzeio/Link'
import Loader from './dzeio/Loader'
import Menu from './dzeio/Menu' import Menu from './dzeio/Menu'
import Navbar from './dzeio/Navbar' import Navbar from './dzeio/Navbar'
import NavbarSpace from './dzeio/Navbar/NavbarSpace'
import Overflow from './dzeio/Overflow' import Overflow from './dzeio/Overflow'
import Popup from './dzeio/Popup' import Popup from './dzeio/Popup'
import Row from './dzeio/Row' import Row from './dzeio/Row'
import SidebarContainer from './dzeio/SidebarContainer'
import Table from './dzeio/Table' import Table from './dzeio/Table'
import Tag from './dzeio/Tag'
import Text from './dzeio/Text' import Text from './dzeio/Text'
import * as Util from './dzeio/Util' import * as Util from './dzeio/Util'
import './dzeio/general.styl'
export { export {
Box, Box,
BoxBody,
BoxHeader,
BoxWrapper,
Button, Button,
Checkbox, Checkbox,
Code, Code,
@ -40,15 +41,13 @@ export {
Image, Image,
Input, Input,
Link, Link,
Loader,
Menu, Menu,
Navbar, Navbar,
NavbarSpace,
Overflow, Overflow,
Popup, Popup,
Row, Row,
SidebarContainer,
Table, Table,
Tag,
Text, Text,
Util Util
} }

View File

@ -17,7 +17,7 @@
// "composite": true, /* Enable project compilation */ // "composite": true, /* Enable project compilation */
// "removeComments": true, /* Do not emit comments to output. */ // "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */ // "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ "importHelpers": false, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
@ -64,6 +64,7 @@
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",
"build" "build",
"src/**/*.stories.tsx"
] ]
} }

4497
yarn.lock

File diff suppressed because it is too large Load Diff