165 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import React from 'react'
 | |
| import themes from '../../themes/themes.json'
 | |
| import FlexLayout from '../components/FlexLayout'
 | |
| 
 | |
| import { getColor, parseBoolean } from './utils'
 | |
| 
 | |
| export interface CardOptions {
 | |
| 	title_color?: string
 | |
| 	bg_color?: string
 | |
| 	hide_border?: boolean
 | |
| 	hide_title?: boolean
 | |
| 	theme?: keyof typeof themes
 | |
| }
 | |
| 
 | |
| export default class Card {
 | |
| 
 | |
| 	public hideBorder = false
 | |
| 	public hideTitle = false
 | |
| 	public css = ''
 | |
| 	public paddingX = 25
 | |
| 	public paddingY = 35
 | |
| 	public animations = true
 | |
| 	public height = 100
 | |
| 	public width = 100
 | |
| 	public title = ''
 | |
| 	public colors: {
 | |
| 		titleColor?: string | Array<string>,
 | |
| 		bgColor?: string | Array<string>
 | |
| 	} = {}
 | |
| 	public titlePrefix?: JSX.Element
 | |
| 
 | |
| 	constructor(options?: CardOptions) {
 | |
| 		if (options) {
 | |
| 			this.hideBorder = parseBoolean(options.hide_border)
 | |
| 			this.hideTitle = parseBoolean(options.hide_title)
 | |
| 			this.colors = {
 | |
| 				titleColor: getColor('title_color', options?.title_color, options?.theme),
 | |
| 				bgColor: getColor('bg_color', options?.bg_color, options?.theme)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	renderTitle() {
 | |
| 		const titleText = (
 | |
| 			<text
 | |
| 				x="0"
 | |
| 				y="0"
 | |
| 				className="header"
 | |
| 			>{this.title}</text>
 | |
| 		)
 | |
| 
 | |
| 
 | |
| 		const prefixIcon = (
 | |
| 			<svg
 | |
| 				className="icon"
 | |
| 				x="0"
 | |
| 				y="-13"
 | |
| 				viewBox="0 0 16 16"
 | |
| 				version="1.1"
 | |
| 				width="16"
 | |
| 				height="16"
 | |
| 			>
 | |
| 				{this.titlePrefix}
 | |
| 			</svg>
 | |
| 		)
 | |
| 		return (
 | |
| 			<g
 | |
| 				transform={`translate(${this.paddingX}, ${this.paddingY})`}
 | |
| 			>
 | |
| 				<FlexLayout
 | |
| 					items={[this.titlePrefix && prefixIcon, titleText]}
 | |
| 					gap={25}
 | |
| 				/>
 | |
| 			</g>
 | |
| 		)
 | |
| 	}
 | |
| 
 | |
| 	renderGradient() {
 | |
| 		if (typeof this.colors.bgColor !== 'object') return
 | |
| 
 | |
| 		const gradients = this.colors.bgColor.slice(1)
 | |
| 		return typeof this.colors.bgColor === 'object' ?
 | |
| 			(
 | |
| 				<defs>
 | |
| 					<linearGradient
 | |
| 						id="gradient"
 | |
| 						gradientTransform={`rotate(${this.colors.bgColor[0]})`}
 | |
| 					>
 | |
| 						{gradients.map((grad, index) => {
 | |
| 							const offset = (index * 100) / (gradients.length - 1)
 | |
| 							return `<stop offset="${offset}%" stop-color="#${grad}" />`
 | |
| 						})}
 | |
| 					</linearGradient>
 | |
| 				</defs>
 | |
| 			) :
 | |
| 			''
 | |
| 	}
 | |
| 
 | |
| 	render(body: JSX.Element) {
 | |
| 		return (
 | |
| 			<svg
 | |
| 				width={this.width}
 | |
| 				height={this.height - (this.hideTitle ? 30 : 0)}
 | |
| 				viewBox={`0 0 ${this.width} ${this.height}`}
 | |
| 				fill="none"
 | |
| 				xmlns="http://www.w3.org/2000/svg"
 | |
| 			>
 | |
| 				<style>{`
 | |
| 					.header {
 | |
| 						font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif;
 | |
| 						fill: ${this.colors.titleColor};
 | |
| 						animation: fadeInAnimation 0.8s ease-in-out forwards;
 | |
| 					}
 | |
| 					${this.css}
 | |
| 
 | |
| 					/* Animations */
 | |
| 					@keyframes scaleInAnimation {
 | |
| 						from {
 | |
| 							transform: translate(-5px, 5px) scale(0);
 | |
| 						}
 | |
| 						to {
 | |
| 							transform: translate(-5px, 5px) scale(1);
 | |
| 						}
 | |
| 					}
 | |
| 					@keyframes fadeInAnimation {
 | |
| 						from {
 | |
| 							opacity: 0;
 | |
| 						}
 | |
| 						to {
 | |
| 							opacity: 1;
 | |
| 						}
 | |
| 					}
 | |
| 				`}</style>
 | |
| 
 | |
| 				{this.renderGradient()}
 | |
| 
 | |
| 				<rect
 | |
| 					x="0.5"
 | |
| 					y="0.5"
 | |
| 					rx="4.5"
 | |
| 					height="99%"
 | |
| 					stroke="#E4E2E2"
 | |
| 					width={this.width - 1}
 | |
| 					fill={
 | |
| 						typeof this.colors.bgColor === 'object' ?
 | |
| 							'url(#gradient)' :
 | |
| 							this.colors.bgColor
 | |
| 					}
 | |
| 					strokeOpacity={this.hideBorder ? 0 : 1}
 | |
| 				/>
 | |
| 
 | |
| 				{this.hideTitle ? '' : this.renderTitle()}
 | |
| 
 | |
| 				<g
 | |
| 					transform={`translate(0, ${
 | |
| 						this.hideTitle ? this.paddingX : this.paddingY + 20
 | |
| 					})`}
 | |
| 				>
 | |
| 					{body}
 | |
| 				</g>
 | |
| 			</svg>
 | |
| 		)
 | |
| 	}
 | |
| 
 | |
| }
 | 
