From 3f63c202f6df7c4682b815597e886066b5648445 Mon Sep 17 00:00:00 2001 From: Fabian Stamm Date: Sun, 29 Mar 2020 16:05:39 +0200 Subject: [PATCH] First Commit --- .editorconfig | 5 +++ .gitignore | 2 + package-lock.json | 24 ++++++++++ package.json | 23 ++++++++++ src/Button.tsx | 45 +++++++++++++++++++ src/Card.tsx | 12 +++++ src/Container.tsx | 12 +++++ src/Fab.tsx | 16 +++++++ src/Header.tsx | 15 +++++++ src/IconButton.tsx | 12 +++++ src/Input.tsx | 81 ++++++++++++++++++++++++++++++++++ src/List.tsx | 27 ++++++++++++ src/Modal.tsx | 53 +++++++++++++++++++++++ src/Table.tsx | 13 ++++++ src/Theme.tsx | 106 +++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 39 +++++++++++++++++ tsconfig.json | 13 ++++++ 17 files changed, 498 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/Button.tsx create mode 100644 src/Card.tsx create mode 100644 src/Container.tsx create mode 100644 src/Fab.tsx create mode 100644 src/Header.tsx create mode 100644 src/IconButton.tsx create mode 100644 src/Input.tsx create mode 100644 src/List.tsx create mode 100644 src/Modal.tsx create mode 100644 src/Table.tsx create mode 100644 src/Theme.tsx create mode 100644 src/index.ts create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9a472c4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +[*] +indent_size = 3 +indent_style = space +charset = utf-8 +insert_final_newline = true \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed1bf77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +out/ +node_modules/ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8d0bd97 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "@hibas123/theme-preact", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@hibas123/theme": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@hibas123/theme/-/theme-2.0.2.tgz", + "integrity": "sha512-bx9g8OgxaMtsgnOEh+152WRC6hE8pHNR+Q2g/K9cfIY9Uy7k6ZHrsWz2ql8HJNJ/0Tn6/a15l5wQJyqBRnLnvQ==" + }, + "preact": { + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.3.4.tgz", + "integrity": "sha512-wMgzs/RGYf0I1PZf8ZFJdyU/3kCcwepJyVYe+N9FGajyQWarMoPrPfrQajcG0psPj6ySYv2cSuLYFCihvV/Qrw==" + }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..30bcef3 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "@hibas123/theme-preact", + "version": "1.0.0", + "description": "", + "main": "out/index.js", + "dependencies": { + "@hibas123/theme": "^2.0.2", + "preact": "^10.3.4" + }, + "peerDependencies": { + "preact": "^10.3.4" + }, + "devDependencies": { + "typescript": "^3.8.3" + }, + "scripts": { + "build": "tsc", + "watch": "tsc -w" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/src/Button.tsx b/src/Button.tsx new file mode 100644 index 0000000..b429cd7 --- /dev/null +++ b/src/Button.tsx @@ -0,0 +1,45 @@ +import { h, JSX } from "preact"; + +export enum ButtonFormats { + DEFAULT, + PRIMARY, + SECONDARY, + ERROR, + SUCCESS +} + +export interface IButtonProps extends JSX.HTMLAttributes { + format: ButtonFormats; +} + +export default function Button({ + children, + format, + className, + ...props +}: IButtonProps) { + let cl = "ht-btn"; + + if (className) cl += " " + className; + + switch (format) { + case ButtonFormats.DEFAULT: + break; + case ButtonFormats.PRIMARY: + cl += " ht-btn-primary"; + break; + case ButtonFormats.SECONDARY: + cl += " ht-btn-secondary"; + break; + case ButtonFormats.ERROR: + cl += " ht-btn-error"; + break; + case ButtonFormats.SUCCESS: + cl += " ht-btn-success"; + break; + } + + ; +} diff --git a/src/Card.tsx b/src/Card.tsx new file mode 100644 index 0000000..7f57ae2 --- /dev/null +++ b/src/Card.tsx @@ -0,0 +1,12 @@ +import { h, JSX } from "preact"; +export default function Card({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} diff --git a/src/Container.tsx b/src/Container.tsx new file mode 100644 index 0000000..df3b4e0 --- /dev/null +++ b/src/Container.tsx @@ -0,0 +1,12 @@ +import { h, JSX } from "preact"; +export default function Container({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} diff --git a/src/Fab.tsx b/src/Fab.tsx new file mode 100644 index 0000000..84c35d7 --- /dev/null +++ b/src/Fab.tsx @@ -0,0 +1,16 @@ +import { h, JSX } from "preact"; + +export default function Fab({ + className, + children, + alignLeft, + ...props +}: JSX.HTMLAttributes & { alignLeft: boolean }) { + let cl = "ht-fab " + (alignLeft ? "ht-fab-left " : ""); + + return ( + + ); +} diff --git a/src/Header.tsx b/src/Header.tsx new file mode 100644 index 0000000..c6cc5e0 --- /dev/null +++ b/src/Header.tsx @@ -0,0 +1,15 @@ +import { h, JSX } from "preact"; + +//TODO: Implement predefined children styles + +export default function Header({ + children, + className, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} diff --git a/src/IconButton.tsx b/src/IconButton.tsx new file mode 100644 index 0000000..a084f41 --- /dev/null +++ b/src/IconButton.tsx @@ -0,0 +1,12 @@ +import { h, JSX } from "preact"; +export default function IconButton({ + children, + className, + ...props +}: JSX.HTMLAttributes) { + return ( + + ); +} diff --git a/src/Input.tsx b/src/Input.tsx new file mode 100644 index 0000000..cd01df8 --- /dev/null +++ b/src/Input.tsx @@ -0,0 +1,81 @@ +import { h, JSX } from "preact"; + +export function Input({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( + + {children} + + ); +} + +export function TextArea({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( + + ); +} + +export function InputGroup({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} + +export interface IInputCheckboxProps { + label: string; +} +export function InputCheckbox({ + label, + ...props +}: IInputCheckboxProps & JSX.HTMLAttributes) { + return ( + + ); +} + +export interface IInputRadioProps { + label: string; +} +export function InputRadio({ + label, + ...props +}: IInputCheckboxProps & JSX.HTMLAttributes) { + return ( + + ); +} + +export function InputSelect({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( + + ); +} diff --git a/src/List.tsx b/src/List.tsx new file mode 100644 index 0000000..3e83e29 --- /dev/null +++ b/src/List.tsx @@ -0,0 +1,27 @@ +import { h, JSX } from "preact"; + +export interface IListProps { + clickable?: boolean; + divider?: boolean; +} + +export default function List({ + clickable, + divider, + className, + children, + ...props +}: JSX.HTMLAttributes & IListProps) { + let cl = "ht-list "; + if (clickable) cl += "ht-list-clickable "; + + if (divider) cl += "ht-list-divider "; + + cl += className; + + return ( +
    + {children} +
+ ); +} diff --git a/src/Modal.tsx b/src/Modal.tsx new file mode 100644 index 0000000..3c0a038 --- /dev/null +++ b/src/Modal.tsx @@ -0,0 +1,53 @@ +import { h, JSX } from "preact"; + +export function Modal({ + hidden, + className, + children, + ...props +}: JSX.HTMLAttributes & { hidden?: boolean }) { + return ( +
+ {children} +
+ ); +} + +export function ModalTitle({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} + +export function ModalContent({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} + +export function ModalActions({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} diff --git a/src/Table.tsx b/src/Table.tsx new file mode 100644 index 0000000..71df7a6 --- /dev/null +++ b/src/Table.tsx @@ -0,0 +1,13 @@ +import { h, JSX } from "preact"; + +export default function Table({ + className, + children, + ...props +}: JSX.HTMLAttributes) { + return ( +
+ {children} +
+ ); +} diff --git a/src/Theme.tsx b/src/Theme.tsx new file mode 100644 index 0000000..17aea41 --- /dev/null +++ b/src/Theme.tsx @@ -0,0 +1,106 @@ +import { h } from "preact"; +import { useEffect, useState, useMemo } from "preact/hooks"; + +export enum ThemeModes { + AUTO, + LIGHT, + DARK +} + +export interface IThemeProps { + mode: ThemeModes; + children: any; + + primary?: string; + onPrimary?: string; + secondary?: string; + onSecondary?: string; + error?: string; + onError?: string; + success?: string; + onSuccess?: string; +} + +const modeMediaQuery = window.matchMedia("prefers-color-scheme: dark"); + +export default function Theme({ mode, children, ...colors }: IThemeProps) { + const [isDark, setIsDark] = useState( + mode === ThemeModes.AUTO + ? modeMediaQuery.matches + : mode === ThemeModes.DARK + ); + useEffect(() => { + if (mode === ThemeModes.AUTO) { + const listener = (ev: MediaQueryListEvent) => { + setIsDark(ev.matches); + }; + modeMediaQuery.addListener(listener); + + setIsDark(modeMediaQuery.matches); + + return modeMediaQuery.removeListener(listener); + } + }, [mode]); + + const style = useMemo(() => { + let style = ""; + const getRGB = (color: string) => { + const cv = document.createElement("canvas"); + cv.width = 10; + cv.height = 10; + + const ctx = cv.getContext("2d"); + ctx.rect(0, 0, 1, 1); + ctx.fillStyle = color; + ctx.fill(); + + const [r, g, b] = ctx.getImageData(0, 0, 10, 10).data; + + return [r, g, b]; + }; + + const add = (name: string, value: string) => + (style += `--${name}: ${value};`); + + if (colors.primary) { + add("primary:", colors.primary); + add("primary-rgb", getRGB(colors.primary).join(", ")); + } + if (colors.onPrimary) add("on-primary:", colors.onPrimary); + + if (colors.secondary) { + add("secondary:", colors.secondary); + add("secondary-rgb", getRGB(colors.secondary).join(", ")); + } + if (colors.onSecondary) add("on-secondary:", colors.onSecondary); + + if (colors.error) { + add("error:", colors.error); + add("error-rgb", getRGB(colors.error).join(", ")); + } + if (colors.onError) add("on-error:", colors.onError); + + if (colors.success) { + add("success:", colors.success); + add("success-rgb", getRGB(colors.success).join(", ")); + } + if (colors.onSuccess) add("on-success:", colors.onSuccess); + + return style; + }, [ + colors.primary, + colors.secondary, + colors.error, + colors.success, + colors.onPrimary, + colors.onSecondary, + colors.onError, + colors.onSuccess + ]); + + return ( +
+ {children} +
+ ); +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..789cabc --- /dev/null +++ b/src/index.ts @@ -0,0 +1,39 @@ +import "@hibas123/theme/out/pref.css"; + +import Theme, { IThemeProps, ThemeModes } from "./Theme"; +import Container from "./Container"; +import Button, { ButtonFormats, IButtonProps } from "./Button"; +import Fab from "./Fab"; +import Card from "./Card"; +import Header from "./Header"; +import IconButton from "./IconButton"; +import List from "./List"; +export { Modal, ModalActions, ModalContent, ModalTitle } from "./Modal"; +import Table from "./Table"; + +export { + IInputCheckboxProps, + IInputRadioProps, + Input, + InputCheckbox, + InputGroup, + InputRadio, + InputSelect, + TextArea +} from "./Input"; + +export { + Theme, + IThemeProps, + ThemeModes, + Container, + Button, + ButtonFormats, + IButtonProps, + Fab, + Card, + IconButton, + Header, + List, + Table +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..86de61a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Node", + "target": "ES2019", + "jsx": "react", + "jsxFactory": "h", + "outDir": "out/", + "sourceMap": true, + "declaration": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +}