├── src ├── hooks │ ├── index.js │ └── useResizeObserver.js ├── index.js ├── .eslintrc ├── util │ ├── index.js │ ├── common.js │ ├── dom.js │ └── props.js ├── components │ ├── index.js │ ├── background │ │ ├── Background.module.css │ │ └── Background.jsx │ ├── card │ │ ├── Card.module.css │ │ └── Card.jsx │ └── styles.module.css └── index.test.js ├── .travis.yml ├── .eslintignore ├── example ├── src │ ├── bg.webp │ ├── book.png │ ├── play.png │ ├── laptop.png │ ├── dumbell.png │ ├── index.js │ ├── App.test.js │ ├── index.css │ └── App.js ├── public │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── README.md └── package.json ├── .editorconfig ├── .prettierrc ├── .gitignore ├── .eslintrc ├── README.md └── package.json /src/hooks/index.js: -------------------------------------------------------------------------------- 1 | export * from './useResizeObserver' 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | - 10 5 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { Card, Background } from './components' 2 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules/ 4 | .snapshots/ 5 | *.min.js -------------------------------------------------------------------------------- /example/src/bg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-glassmorphism/HEAD/example/src/bg.webp -------------------------------------------------------------------------------- /example/src/book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-glassmorphism/HEAD/example/src/book.png -------------------------------------------------------------------------------- /example/src/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-glassmorphism/HEAD/example/src/play.png -------------------------------------------------------------------------------- /src/util/index.js: -------------------------------------------------------------------------------- 1 | export * from './dom' 2 | export * from './props' 3 | export * from './common' 4 | -------------------------------------------------------------------------------- /example/src/laptop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-glassmorphism/HEAD/example/src/laptop.png -------------------------------------------------------------------------------- /example/src/dumbell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-glassmorphism/HEAD/example/src/dumbell.png -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKAspanion/ui-glassmorphism/HEAD/example/public/favicon.ico -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | export { Card } from './card/Card.jsx' 2 | export { Background } from './background/Background.jsx' 3 | -------------------------------------------------------------------------------- /src/index.test.js: -------------------------------------------------------------------------------- 1 | import { Card } from './components' 2 | 3 | describe('Card', () => { 4 | it('is truthy', () => { 5 | expect(Card).toBeTruthy() 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import './index.css' 2 | 3 | import React from 'react' 4 | import ReactDOM from 'react-dom' 5 | import App from './App' 6 | 7 | ReactDOM.render(, document.getElementById('root')) 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "jsxBracketSameLine": false, 8 | "arrowParens": "always", 9 | "trailingComma": "none" 10 | } 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This example was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | It is linked to the ui-glassmorphism package in the parent directory for development purposes. 4 | 5 | You can run `npm install` and then `npm start` to test your package. 6 | -------------------------------------------------------------------------------- /example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div') 7 | ReactDOM.render(, div) 8 | ReactDOM.unmountComponentAtNode(div) 9 | }) 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/ignore-files/ for more about ignoring files. 3 | 4 | # dependencies 5 | node_modules 6 | 7 | # builds 8 | build 9 | dist 10 | .rpt2_cache 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "ui-glassmorphism", 3 | "name": "ui-glassmorphism", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /src/util/common.js: -------------------------------------------------------------------------------- 1 | import globalModule from '../components/styles.module.css' 2 | 3 | export const getModuleClasses = (localModule, classNames) => { 4 | const styles = { 5 | ...localModule, 6 | ...globalModule 7 | } 8 | 9 | return classNames 10 | .replace(/^\s+|\s+$/g, '') 11 | .split(/\s+/) 12 | .map((cl) => styles[cl.trim()]) 13 | .join(' ') 14 | .trim() 15 | } 16 | -------------------------------------------------------------------------------- /src/components/background/Background.module.css: -------------------------------------------------------------------------------- 1 | .gl-background { 2 | background-size: cover !important; 3 | /* background: var(--gl-background-value); */ 4 | } 5 | 6 | .gl-background:before { 7 | content: ''; 8 | top: 0; 9 | left: 0; 10 | position: absolute; 11 | width: var(--gl-background-width); 12 | height: var(--gl-background-height); 13 | backdrop-filter: blur(var(--gl-background-blur)); 14 | } 15 | -------------------------------------------------------------------------------- /example/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | 16 | .activity__card__container::-webkit-scrollbar { 17 | display: none; 18 | } 19 | 20 | .activity__card:last-of-type { 21 | margin-right: 0px !important; 22 | } 23 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react" 6 | ], 7 | "env": { 8 | "node": true 9 | }, 10 | "parserOptions": { 11 | "ecmaVersion": 2020, 12 | "ecmaFeatures": { 13 | "legacyDecorators": true, 14 | "jsx": true 15 | } 16 | }, 17 | "settings": { 18 | "react": { 19 | "version": "17" 20 | } 21 | }, 22 | "rules": { 23 | "space-before-function-parent": 0, 24 | "react/prop-types": 0, 25 | "react/jsx-handler-names": 0, 26 | "react/jsx-fragments": 0, 27 | "react/no-unused-prop-types": 0, 28 | "import/export": 0 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/util/dom.js: -------------------------------------------------------------------------------- 1 | export const RGBFromCSSColor = (color) => { 2 | var canvas = document.createElement('canvas') 3 | 4 | canvas.id = 'color-canvas' 5 | canvas.width = 2 6 | canvas.height = 2 7 | canvas.style.zIndex = -1 8 | canvas.style.position = 'absolute' 9 | canvas.style.border = '1px solid' 10 | 11 | var fragment = document.createDocumentFragment() 12 | fragment.appendChild(canvas) 13 | 14 | var ctx = canvas.getContext('2d') 15 | ctx.fillStyle = color 16 | ctx.fillRect(0, 0, 2, 2) 17 | 18 | var imgData = ctx.getImageData(0, 0, 2, 2) 19 | 20 | var colorArray = imgData.data.slice(2 * 4, 2 * 4 + 4) 21 | 22 | // document.getElementById('color-canvas').remove() 23 | 24 | return [colorArray[0], colorArray[1], colorArray[2]] 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ui-glassmorphism 2 | 3 | > React component library on "glassmorphism" UI/UX trend. 4 | 5 | [![NPM](https://img.shields.io/npm/v/ui-glassmorphism.svg)](https://www.npmjs.com/package/ui-glassmorphism) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) 6 | 7 | ## Install 8 | 9 | ```bash 10 | npm install --save ui-glassmorphism 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```jsx 16 | import React, { Component } from 'react' 17 | 18 | import Card from 'ui-glassmorphism' 19 | import 'ui-glassmorphism/dist/index.css' 20 | 21 | class Example extends Component { 22 | render() { 23 | return 24 | } 25 | } 26 | ``` 27 | 28 | ## License 29 | 30 | MIT © [AKAspanion](https://github.com/AKAspanion) 31 | -------------------------------------------------------------------------------- /src/components/card/Card.module.css: -------------------------------------------------------------------------------- 1 | .gl-card { 2 | padding: 16px; 3 | overflow: hidden; 4 | border-radius: 12px; 5 | box-sizing: border-box; 6 | color: var(--text-color); 7 | } 8 | 9 | .gl-card-shine { 10 | position: absolute; 11 | pointer-events: none; 12 | background: radial-gradient( 13 | ellipse at center, 14 | rgba(255, 255, 255, 0.24) 0%, 15 | rgba(255, 255, 255, 0) 65% 16 | ); 17 | transform: translate3d(-50%, -50%, 0); 18 | } 19 | 20 | .gl-card--outlined { 21 | border: 2px solid rgba(255, 255, 255, 0.18); 22 | } 23 | 24 | .gl-card.gl-card--light { 25 | --text-color: var(--g-text-color-light); 26 | } 27 | 28 | .gl-card.gl-card--dark { 29 | --text-color: var(--g-text-color-dark); 30 | } 31 | 32 | .gl-card.gl-card--elevation-1 { 33 | box-shadow: 0 3px 32px 0 rgba(31, 38, 135, 0.07); 34 | } 35 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-glassmorphism-example", 3 | "homepage": ".", 4 | "version": "0.0.0", 5 | "private": true, 6 | "scripts": { 7 | "start": "node ../node_modules/react-scripts/bin/react-scripts.js start", 8 | "build": "node ../node_modules/react-scripts/bin/react-scripts.js build", 9 | "test": "node ../node_modules/react-scripts/bin/react-scripts.js test", 10 | "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject" 11 | }, 12 | "dependencies": { 13 | "react": "file:../node_modules/react", 14 | "react-dom": "file:../node_modules/react-dom", 15 | "react-scripts": "file:../node_modules/react-scripts", 16 | "ui-glassmorphism": "file:.." 17 | }, 18 | "devDependencies": { 19 | "@babel/plugin-syntax-object-rest-spread": "^7.8.3" 20 | }, 21 | "eslintConfig": { 22 | "extends": "react-app" 23 | }, 24 | "browserslist": [ 25 | ">0.2%", 26 | "not dead", 27 | "not ie <= 11", 28 | "not op_mini all" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /src/components/styles.module.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --gradient-left: #bbf4dc; 3 | --gradient-right: #aacce9; 4 | 5 | --white: #ffffff; 6 | --black: #000000; 7 | 8 | --primary: #2979ff; 9 | --primary-dark: #2962ff; 10 | --primary-light: #82b1ff; 11 | 12 | --error: #ff5252; 13 | --info: #2196f3; 14 | --success: #4caf50; 15 | --warning: #dfa700; 16 | 17 | --g-text-color-light: rgba(0, 0, 0, 0.8); 18 | --g-text-color-disabled-light: rgba(0, 0, 0, 0.45); 19 | --g-text-color-secondary-light: rgba(0, 0, 0, 0.67); 20 | 21 | --g-text-color-dark: rgba(255, 255, 255, 0.8); 22 | --g-text-color-disabled-dark: rgba(255, 255, 255, 0.45); 23 | --g-text-color-secondary-dark: rgba(255, 255, 255, 0.67); 24 | 25 | --g-bg-color-disabled-light: #dee5e8; 26 | --g-bg-color-disabled-dark: #727272; 27 | } 28 | 29 | * { 30 | margin: 0; 31 | padding: 0; 32 | box-sizing: inherit; 33 | } 34 | 35 | input, 36 | label, 37 | textarea, 38 | button, 39 | select, 40 | a { 41 | -webkit-tap-highlight-color: transparent !important; 42 | font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Oxygen', 43 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 44 | sans-serif; 45 | } 46 | -------------------------------------------------------------------------------- /src/util/props.js: -------------------------------------------------------------------------------- 1 | import { Children, cloneElement } from 'react' 2 | 3 | export const isMyReactComponent = (component) => { 4 | let componentName = '' 5 | if (component && component.type && typeof component.type !== 'string') { 6 | componentName = component.type.displayName 7 | } 8 | return componentName && componentName.includes('Gu') 9 | } 10 | 11 | export const passDownProp = (children, props, propName) => { 12 | return Children.map(children, (child) => { 13 | if (isMyReactComponent(child)) { 14 | const newProps = { 15 | ...child.props 16 | } 17 | 18 | if (typeof propName === 'string') { 19 | if (props[propName] !== undefined) { 20 | newProps[propName] = 21 | child.props[propName] === undefined 22 | ? props[propName] 23 | : child.props[propName] 24 | } 25 | } else if (Array.isArray(propName)) { 26 | propName.forEach((prop) => { 27 | if (props[prop] === undefined) return 28 | 29 | newProps[prop] = 30 | child.props[prop] === undefined ? props[prop] : child.props[prop] 31 | }) 32 | } 33 | return cloneElement(child, newProps) 34 | } else { 35 | return child 36 | } 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /src/components/background/Background.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable indent */ 2 | import React from 'react' 3 | import styles from './Background.module.css' 4 | 5 | import { passDownProp, getModuleClasses } from '../../util' 6 | import { useResizeObserver } from '../../hooks' 7 | 8 | const Background = (props) => { 9 | const { style, children, className = '', blur = 100, img } = props 10 | 11 | const bgNode = React.useRef(null) 12 | 13 | const { height, width } = useResizeObserver(bgNode) 14 | 15 | const getClasses = (key) => { 16 | switch (key) { 17 | default: 18 | return getModuleClasses(styles, key) 19 | } 20 | } 21 | 22 | const backgroundStyle = () => { 23 | return img 24 | ? { backgroundImage: `url(${img})` } 25 | : { 26 | background: `linear-gradient( 27 | 90deg, 28 | var(--gradient-left) 0%, 29 | var(--gradient-right) 100%) 30 | ` 31 | } 32 | } 33 | 34 | const getChildren = () => { 35 | return passDownProp(children, props, 'dark') 36 | } 37 | 38 | return ( 39 |
50 | {getChildren()} 51 |
52 | ) 53 | } 54 | 55 | Background.displayName = 'GuBackground' 56 | 57 | export { Background } 58 | -------------------------------------------------------------------------------- /src/hooks/useResizeObserver.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const useResizeObserver = (element) => { 4 | const current = element && element.current 5 | 6 | const observer = React.useRef(null) 7 | 8 | const [width, setWidth] = React.useState(0) 9 | const [height, setHeight] = React.useState(0) 10 | 11 | React.useLayoutEffect(() => { 12 | if (observer && observer.current && current) { 13 | observer.current.unobserve(current) 14 | } 15 | 16 | // eslint-disable-next-line no-undef 17 | observer.current = new ResizeObserver((entries) => { 18 | const currentWidth = width 19 | const currentHeight = height 20 | 21 | entries.forEach((entry) => { 22 | const { clientHeight, clientWidth } = (entry && entry.target) || {} 23 | 24 | const isWidthChanged = currentWidth !== clientWidth 25 | const isHeightChanged = currentHeight !== clientHeight 26 | 27 | if (isWidthChanged) { 28 | setWidth(clientWidth) 29 | } 30 | if (isHeightChanged) { 31 | setHeight(clientHeight) 32 | } 33 | }) 34 | }) 35 | 36 | observe() 37 | 38 | return () => unobserve() 39 | }, [current]) 40 | 41 | const observe = () => { 42 | if (isObserverValid()) { 43 | observer.current.observe(element.current) 44 | } 45 | } 46 | 47 | const unobserve = () => { 48 | if (isObserverValid()) { 49 | observer.current.unobserve(element.current) 50 | } 51 | } 52 | 53 | const isObserverValid = () => { 54 | return element && element.current && observer.current 55 | } 56 | 57 | return { width, height } 58 | } 59 | -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 16 | 17 | 18 | 27 | ui-glassmorphism 28 | 29 | 30 | 31 | 34 | 35 |
36 | 37 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-glassmorphism", 3 | "version": "0.0.1", 4 | "description": "React component library on 'glassmorphism' UI/UX trend.", 5 | "author": "Ankit Kumar Pandit", 6 | "license": "MIT", 7 | "repository": "https://github.com/AKAspanion/ui-glassmorphism", 8 | "main": "dist/index.js", 9 | "module": "dist/index.modern.js", 10 | "source": "src/index.js", 11 | "engines": { 12 | "node": ">=10" 13 | }, 14 | "scripts": { 15 | "build": "microbundle-crl --no-compress --format modern,cjs", 16 | "start": "microbundle-crl watch --no-compress --format modern,cjs", 17 | "prepare": "run-s build", 18 | "test": "run-s test:unit test:lint test:build", 19 | "test:build": "run-s build", 20 | "test:lint": "eslint .", 21 | "test:unit": "cross-env CI=1 react-scripts test --env=jsdom", 22 | "test:watch": "react-scripts test --env=jsdom", 23 | "predeploy": "cd example && npm install && npm run build", 24 | "deploy": "gh-pages -d example/build" 25 | }, 26 | "peerDependencies": { 27 | "react": "^17.0.1", 28 | "react-dom": "^17.0.1" 29 | }, 30 | "devDependencies": { 31 | "microbundle-crl": "^0.13.10", 32 | "babel-eslint": "^10.0.3", 33 | "cross-env": "^7.0.2", 34 | "eslint": "^6.8.0", 35 | "eslint-config-prettier": "^6.7.0", 36 | "eslint-config-standard": "^14.1.0", 37 | "eslint-config-standard-react": "^9.2.0", 38 | "eslint-plugin-import": "^2.18.2", 39 | "eslint-plugin-node": "^11.0.0", 40 | "eslint-plugin-prettier": "^3.1.1", 41 | "eslint-plugin-promise": "^4.2.1", 42 | "eslint-plugin-react": "^7.17.0", 43 | "eslint-plugin-standard": "^4.0.1", 44 | "gh-pages": "^2.2.0", 45 | "npm-run-all": "^4.1.5", 46 | "prettier": "^2.0.4", 47 | "react": "^17.0.1", 48 | "react-dom": "^17.0.1", 49 | "react-scripts": "^3.4.1" 50 | }, 51 | "files": [ 52 | "dist" 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /src/components/card/Card.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './Card.module.css' 3 | 4 | import { getModuleClasses, RGBFromCSSColor } from '../../util' 5 | import { useResizeObserver } from '../../hooks' 6 | 7 | const Card = (props) => { 8 | const { 9 | style, 10 | children, 11 | dark = false, 12 | className = '', 13 | color, 14 | blur = 4, 15 | elevation, 16 | outlined = false, 17 | transparency = 0.25, 18 | shineOnHover = false 19 | } = props 20 | 21 | const shine = React.useRef(null) 22 | const cardNode = React.useRef(null) 23 | 24 | const { width } = useResizeObserver(cardNode) 25 | 26 | const background = () => { 27 | if (transparency === 0) return '' 28 | 29 | const colorLight = '255, 255, 255' 30 | const colorDark = '0, 0, 0' 31 | 32 | let rgbColor = colorLight 33 | 34 | if (dark) { 35 | rgbColor = colorDark 36 | } 37 | 38 | if (color) { 39 | const [r, g, b] = RGBFromCSSColor(color) 40 | 41 | if (r === 0 && g === 0 && b === 0) { 42 | if (dark) { 43 | rgbColor = colorDark 44 | } else { 45 | rgbColor = colorLight 46 | } 47 | } else { 48 | rgbColor = `${r}, ${g}, ${b}` 49 | } 50 | } 51 | 52 | return `rgba(${rgbColor}, ${transparency})` 53 | } 54 | 55 | const bgBlur = () => { 56 | if (transparency === 0) return '' 57 | 58 | return `blur(${blur}px)` 59 | } 60 | 61 | const getClasses = (key) => { 62 | switch (key) { 63 | case 'card': 64 | return getModuleClasses( 65 | styles, 66 | ` 67 | gl-card 68 | gl-card--${dark ? 'dark' : 'light'} 69 | ${outlined ? 'gl-card--outlined' : ''} 70 | ${elevation ? `gl-card--elevation-${elevation}` : ''} 71 | ` 72 | ) 73 | default: 74 | return getModuleClasses(styles, key) 75 | } 76 | } 77 | 78 | const mouseMoveHandler = (event) => { 79 | if (!shineOnHover) return 80 | 81 | if (!event || !shine.current) return 82 | 83 | event.preventDefault() 84 | event.stopPropagation() 85 | event.nativeEvent.stopImmediatePropagation() 86 | 87 | const { pageX, pageY } = event 88 | const { x: cardX, y: cardY } = event.target.getBoundingClientRect() 89 | 90 | shine.current.style.top = `${pageY - cardY}px` 91 | shine.current.style.left = `${pageX - cardX}px` 92 | } 93 | 94 | return ( 95 |
105 | {shineOnHover && ( 106 |
111 | )} 112 | {children} 113 |
114 | ) 115 | } 116 | 117 | Card.displayName = 'GuCard' 118 | 119 | export { Card } 120 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Card, Background } from 'ui-glassmorphism' 4 | import 'ui-glassmorphism/dist/index.css' 5 | 6 | import './index.css' 7 | 8 | import bg from './bg.webp' 9 | import book from './book.png' 10 | import play from './play.png' 11 | import laptop from './laptop.png' 12 | import dumbell from './dumbell.png' 13 | 14 | const cards = [ 15 | { 16 | name: 'Fitness', 17 | image: dumbell, 18 | color: '#f400d0', 19 | width: '50%', 20 | time: '1:30h', 21 | transparency: 0.2 22 | }, 23 | { 24 | name: 'Work', 25 | color: '#54A1D2', 26 | width: '100%', 27 | time: '6h', 28 | image: laptop, 29 | transparency: 0.8 30 | }, 31 | { 32 | name: 'Study', 33 | image: book, 34 | color: 'cyan', 35 | width: '70%', 36 | time: '1h', 37 | transparency: 0.8 38 | }, 39 | { 40 | name: 'Play', 41 | image: play, 42 | color: 'red', 43 | width: '70%', 44 | time: '1h', 45 | transparency: 0.8 46 | } 47 | ] 48 | 49 | const activities = [ 50 | { name: 'S', percent: '50' }, 51 | { name: 'M', percent: '70' }, 52 | { name: 'T', percent: '30' }, 53 | { name: 'W', percent: '90' }, 54 | { name: 'T', percent: '80' }, 55 | { name: 'F', percent: '60' }, 56 | { name: 'S', percent: '80' } 57 | ] 58 | 59 | const flexItem = { 60 | display: 'flex', 61 | alignItems: 'center', 62 | justifyContent: 'center' 63 | } 64 | const App = () => { 65 | return ( 66 | 72 |
79 | 90 |
91 |
101 |
111 |
112 | 113 |
Today
114 |
120 | 125 | 138 |
139 | Fitness 140 |
141 |
1:30
142 |
143 |
144 |
145 | 146 |
149 | Last activity 150 |
151 |
159 |
166 | {cards.map( 167 | ({ name, color, image, time, width, transparency }, i) => ( 168 | 184 | icon 195 |
196 | {name} 197 |
198 |
205 | {time} 206 |
207 | 217 | 227 | 228 |
229 | ) 230 | )} 231 |
232 |
233 |
234 | 242 |
243 |
254 |
265 |
266 | 267 |
268 | Statistics 269 |
270 |
277 | This week 278 |
279 |
286 | {cards.map(({ name, image, transparency }) => ( 287 |
288 | 297 | {name} 305 | 306 |
309 | {name} 310 |
311 |
312 | ))} 313 |
314 | 315 |
322 | Activity 323 |
324 |
325 | {activities.map(({ name, percent }) => ( 326 |
327 |
336 |
348 |
351 | {name} 352 |
353 |
354 | ))} 355 |
356 | 357 |
358 | 359 |
365 | Plan your daytime! 366 |
367 |
368 |
369 | 370 |
371 | 372 | ) 373 | } 374 | 375 | export default App 376 | --------------------------------------------------------------------------------