aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/assets/README.md3
-rw-r--r--packages/assets/package.json8
-rw-r--r--packages/assets/scripts/generate.mjs62
-rw-r--r--packages/config/.eslintrc.js4
-rw-r--r--packages/config/app.tsconfig.json7
-rw-r--r--packages/config/base.tsconfig.json22
-rw-r--r--packages/config/eslint/base.js79
-rw-r--r--packages/config/eslint/tailwind.js23
-rw-r--r--packages/config/eslint/web.js22
-rw-r--r--packages/config/index.js3
-rw-r--r--packages/config/package.json29
-rw-r--r--packages/config/vite/index.ts27
-rw-r--r--packages/config/vite/relAlias.ts77
-rw-r--r--packages/ui/.eslintrc.js8
-rw-r--r--packages/ui/package.json51
-rw-r--r--packages/ui/postcss.config.js3
-rw-r--r--packages/ui/src/index.ts1
-rw-r--r--packages/ui/src/keys.ts56
-rw-r--r--packages/ui/src/utils.tsx28
-rw-r--r--packages/ui/style/index.js1
-rw-r--r--packages/ui/style/postcss.config.js1
-rw-r--r--packages/ui/style/style.scss30
-rw-r--r--packages/ui/style/tailwind.js119
-rw-r--r--packages/ui/style/tailwind.pcss4
-rw-r--r--packages/ui/tailwind.config.js2
-rw-r--r--packages/ui/tsconfig.json8
26 files changed, 678 insertions, 0 deletions
diff --git a/packages/assets/README.md b/packages/assets/README.md
new file mode 100644
index 0000000..bbe042c
--- /dev/null
+++ b/packages/assets/README.md
@@ -0,0 +1,3 @@
+# shared assets
+
+all svgs and other shared assets put here
diff --git a/packages/assets/package.json b/packages/assets/package.json
new file mode 100644
index 0000000..cc29174
--- /dev/null
+++ b/packages/assets/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@polyfrost/assets",
+ "version": "0.0.0",
+ "private": true,
+ "scripts": {
+ "gen": "node ./scripts/generate.mjs"
+ }
+}
diff --git a/packages/assets/scripts/generate.mjs b/packages/assets/scripts/generate.mjs
new file mode 100644
index 0000000..44ba4e4
--- /dev/null
+++ b/packages/assets/scripts/generate.mjs
@@ -0,0 +1,62 @@
+import fs from 'node:fs/promises';
+import { dirname, join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import prettier from 'prettier';
+
+const assetFolders = ['icons', 'images', 'svgs/brands', 'svgs/ext/Extras', 'svgs/ext/Code'];
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+prettier.resolveConfig(join(__dirname, '..', '..', '..', '.prettierrc.js')).then((options) =>
+ Promise.all(
+ assetFolders.map(async (folder) => {
+ const indexFilePath = join(__dirname, '..', folder, 'index.ts');
+ const assetsFolderPath = join(__dirname, '..', folder);
+
+ if (
+ await fs.access(indexFilePath).then(
+ () => true,
+ () => false
+ )
+ ) {
+ await fs.unlink(indexFilePath);
+ }
+
+ const fileNames = await fs.readdir(assetsFolderPath);
+
+ const assetImports = fileNames
+ .filter((fileName) => fileName !== 'index.ts' && !/(^|\/)\.[^\/\.]/g.test(fileName))
+ .map((fileName) => {
+ const variableName = fileName.split('.')[0].replace(/-/g, '');
+ if (folder.startsWith('svgs')) {
+ return `import { ReactComponent as ${variableName} } from './${fileName}';`;
+ }
+ return `import ${variableName} from './${fileName}';`;
+ })
+ .join('\n');
+
+ const assetExports = fileNames
+ .filter((fileName) => fileName !== 'index.ts' && !/(^|\/)\.[^\/\.]/g.test(fileName))
+ .map((fileName) => `${fileName.split('.')[0].replace(/-/g, '')}`)
+ .join(',\n');
+
+ const indexFileContent = await prettier.format(
+ `
+ /*
+ * This file was automatically generated by a script.
+ * To regenerate this file, run: pnpm assets gen
+ */
+
+ ${assetImports}
+
+ export {
+ ${assetExports}
+ };`,
+ { ...options, parser: 'typescript' }
+ );
+
+ await fs.writeFile(indexFilePath, indexFileContent);
+ })
+ )
+);
diff --git a/packages/config/.eslintrc.js b/packages/config/.eslintrc.js
new file mode 100644
index 0000000..93a0c63
--- /dev/null
+++ b/packages/config/.eslintrc.js
@@ -0,0 +1,4 @@
+/** @type {import('eslint').ESLint.ConfigData} */
+module.exports = {
+ extends: [require.resolve('./eslint/base.js'), require.resolve('./eslint/tailwind.js')]
+};
diff --git a/packages/config/app.tsconfig.json b/packages/config/app.tsconfig.json
new file mode 100644
index 0000000..e17622d
--- /dev/null
+++ b/packages/config/app.tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./base.tsconfig.json",
+ "compilerOptions": {
+ "noEmit": true,
+ "emitDeclarationOnly": false
+ }
+}
diff --git a/packages/config/base.tsconfig.json b/packages/config/base.tsconfig.json
new file mode 100644
index 0000000..2d27ce4
--- /dev/null
+++ b/packages/config/base.tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "display": "Default",
+ "compilerOptions": {
+ "strict": true,
+ "jsx": "react-jsx",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "preserveWatchOutput": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowSyntheticDefaultImports": true,
+ "noUncheckedIndexedAccess": true,
+ "composite": true,
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "moduleResolution": "Node",
+ "resolveJsonModule": true,
+ "module": "ESNext",
+ "target": "ESNext",
+ "types": ["vite/client"]
+ }
+}
diff --git a/packages/config/eslint/base.js b/packages/config/eslint/base.js
new file mode 100644
index 0000000..200f17d
--- /dev/null
+++ b/packages/config/eslint/base.js
@@ -0,0 +1,79 @@
+const path = require('node:path');
+
+/** @type {import('eslint').ESLint.ConfigData} */
+module.exports = {
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true
+ },
+ ecmaVersion: 12,
+ sourceType: 'module'
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:react-hooks/recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:astro/recommended',
+ 'plugin:astro/jsx-a11y-recommended',
+ 'turbo',
+ 'prettier'
+ ],
+ plugins: ['react', 'jsx-a11y'],
+ rules: {
+ 'react/display-name': 'off',
+ 'react/prop-types': 'off',
+ 'react/no-unescaped-entities': 'off',
+ 'react/react-in-jsx-scope': 'off',
+ 'react-hooks/rules-of-hooks': 'warn',
+ 'react-hooks/exhaustive-deps': 'warn',
+ '@typescript-eslint/no-unused-vars': 'off',
+ '@typescript-eslint/ban-ts-comment': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
+ '@typescript-eslint/no-var-requires': 'off',
+ '@typescript-eslint/no-non-null-assertion': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+ '@typescript-eslint/no-empty-interface': 'off',
+ '@typescript-eslint/no-empty-function': 'off',
+ '@typescript-eslint/ban-types': 'off',
+ 'no-control-regex': 'off',
+ 'no-mixed-spaces-and-tabs': ['warn', 'smart-tabs'],
+ 'turbo/no-undeclared-env-vars': [
+ 'error',
+ {
+ cwd: path.resolve(path.join(__dirname, '..', '..', '..'))
+ }
+ ]
+ },
+ ignorePatterns: ['dist', '**/*.js', '**/*.json', 'node_modules'],
+ settings: {
+ react: {
+ version: 'detect'
+ }
+ },
+ overrides: [
+ {
+ files: ['*.astro'],
+ parser: 'astro-eslint-parser',
+ parserOptions: {
+ parser: '@typescript-eslint/parser',
+ extraFileExtensions: ['.astro']
+ },
+ rules: {
+ 'astro/no-set-html-directive': 2,
+ 'indent': 'off'
+ }
+ },
+ {
+ files: ['*.ts', '*.d.ts', '*.tsx', '*.js', '*.jsx', '*.mjs', '*.cjs'],
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ parser: '@typescript-eslint/parser'
+ },
+ rules: {
+ indent: 'off'
+ }
+ }
+ ]
+};
diff --git a/packages/config/eslint/tailwind.js b/packages/config/eslint/tailwind.js
new file mode 100644
index 0000000..9ac36ae
--- /dev/null
+++ b/packages/config/eslint/tailwind.js
@@ -0,0 +1,23 @@
+const path = require('node:path');
+
+/** @type {import('eslint').ESLint.ConfigData} */
+module.exports = {
+ extends: ['plugin:tailwindcss/recommended'],
+ rules: {
+ 'tailwindcss/no-custom-classname': 'off',
+ 'tailwindcss/classnames-order': [
+ 'warn',
+ {
+ config: path.resolve(
+ path.join(__dirname, '../../..', 'packages/ui/tailwind.config.js')
+ )
+ }
+ ]
+ },
+ settings: {
+ tailwindcss: {
+ callees: ['classnames', 'clsx', 'ctl', 'cva', 'tw', 'twStyle'],
+ tags: ['tw', 'twStyle']
+ }
+ }
+};
diff --git a/packages/config/eslint/web.js b/packages/config/eslint/web.js
new file mode 100644
index 0000000..dc010b3
--- /dev/null
+++ b/packages/config/eslint/web.js
@@ -0,0 +1,22 @@
+/** @type {import('eslint').ESLint.ConfigData} */
+module.exports = {
+ extends: [require.resolve('./base.js'), require.resolve('./tailwind.js')],
+ ignorePatterns: ['public', 'vite.config.ts'],
+ env: {
+ browser: true,
+ node: true
+ },
+ rules: {
+ 'no-restricted-syntax': [
+ 'error',
+ {
+ selector: "CallExpression[callee.name='useParams']",
+ message: 'useParams is illegal, use useZodRouteParams!'
+ },
+ {
+ selector: "CallExpression[callee.name='useSearchParams']",
+ message: 'useSearchParams is illegal, use useZodSearchParams!'
+ }
+ ]
+ }
+};
diff --git a/packages/config/index.js b/packages/config/index.js
new file mode 100644
index 0000000..524af3b
--- /dev/null
+++ b/packages/config/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+ vite: require('./vite')
+};
diff --git a/packages/config/package.json b/packages/config/package.json
new file mode 100644
index 0000000..2a16d61
--- /dev/null
+++ b/packages/config/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "@polyfrost/config",
+ "version": "0.0.0",
+ "exports": {
+ "./*": "./*",
+ "./vite": "./vite",
+ "./vite/relAlias": "./vite/relAlias"
+ },
+ "scripts": {
+ "lint": "eslint . --cache"
+ },
+ "devDependencies": {
+ "@typescript-eslint/eslint-plugin": "^6.7.5",
+ "@typescript-eslint/parser": "^6.7.5",
+ "eslint": "^8.51.0",
+ "eslint-config-turbo": "^1.10.15",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-plugin-prettier": "^5.0.1",
+ "eslint-plugin-react": "^7.33.2",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-tailwindcss": "^3.13.0",
+ "eslint-plugin-astro": "^0.29.1",
+ "eslint-plugin-jsx-a11y": "^6.7.1",
+ "eslint-utils": "^3.0.0",
+ "regexpp": "^3.2.0",
+ "vite-plugin-html": "^3.2.0",
+ "vite-plugin-svgr": "^4.1.0"
+ }
+}
diff --git a/packages/config/vite/index.ts b/packages/config/vite/index.ts
new file mode 100644
index 0000000..a9306a6
--- /dev/null
+++ b/packages/config/vite/index.ts
@@ -0,0 +1,27 @@
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+import { createHtmlPlugin } from 'vite-plugin-html';
+import svg from 'vite-plugin-svgr';
+import tsconfigPaths from 'vite-tsconfig-paths';
+
+export default defineConfig({
+ plugins: [
+ tsconfigPaths(),
+ react(),
+ svg({ svgrOptions: { icon: true } }),
+ createHtmlPlugin({
+ minify: true
+ })
+ ],
+ css: {
+ modules: {
+ localsConvention: 'camelCaseOnly'
+ }
+ },
+ root: 'src',
+ build: {
+ sourcemap: true,
+ outDir: '../dist',
+ assetsDir: '.'
+ }
+});
diff --git a/packages/config/vite/relAlias.ts b/packages/config/vite/relAlias.ts
new file mode 100644
index 0000000..1a502b5
--- /dev/null
+++ b/packages/config/vite/relAlias.ts
@@ -0,0 +1,77 @@
+import fs from 'fs/promises';
+import path from 'path';
+import { Alias } from 'vite';
+
+const projectPath = path.resolve(__dirname, '../../../');
+const pkgJsonCache = new Map();
+
+const SRC_DIR_PATH = `${path.sep}src${path.sep}`;
+
+const resolver: Alias = {
+ find: /^(~\/.+)/,
+ replacement: '$1',
+ async customResolver(source, importer) {
+ let root: null | string = null;
+
+ if (importer) importer = path.normalize(importer);
+
+ const [_, sourcePath] = source.split('~/');
+
+ const relativeImporter = importer?.replace(projectPath, '');
+ if (relativeImporter && relativeImporter.includes(SRC_DIR_PATH)) {
+ const [pkg] = relativeImporter.split(SRC_DIR_PATH);
+ root = path.join(projectPath, pkg, 'src');
+ } else if (importer) {
+ const pathObj = path.parse(importer);
+
+ let parent = pathObj.dir;
+ while (parent !== pathObj.root) {
+ parent = path.dirname(parent);
+
+ let hasPkgJson = pkgJsonCache.get(parent);
+
+ if (hasPkgJson === undefined)
+ try {
+ await fs.stat(path.join(parent, 'package.json'));
+ pkgJsonCache.set(parent, (hasPkgJson = true));
+ } catch {
+ pkgJsonCache.set(parent, (hasPkgJson = false));
+ }
+
+ if (hasPkgJson) {
+ root = parent;
+ break;
+ }
+ }
+
+ if (root === null)
+ throw new Error(`Failed to resolve import path ${source} in file ${importer}`);
+ } else {
+ throw new Error(`Failed to resolve import path ${source} in file ${importer}`);
+ }
+
+ const absolutePath = path.join(root, sourcePath);
+
+ const folderItems = await fs.readdir(path.join(absolutePath, '..'));
+
+ const item = folderItems.find((i) => i.startsWith(sourcePath.split('/').at(-1)!))!;
+
+ const fullPath = absolutePath + path.extname(item);
+
+ const stats = await fs.stat(fullPath);
+
+ if (stats.isDirectory()) {
+ const directoryItems = await fs.readdir(absolutePath + path.extname(item));
+
+ const indexFile = directoryItems.find((i) => i.startsWith('index'));
+ if (!indexFile)
+ throw new Error(`Failed to resolve import path ${source} in file ${importer}`);
+
+ return path.join(absolutePath, indexFile);
+ } else {
+ return fullPath;
+ }
+ }
+};
+
+export default resolver;
diff --git a/packages/ui/.eslintrc.js b/packages/ui/.eslintrc.js
new file mode 100644
index 0000000..f80eaa9
--- /dev/null
+++ b/packages/ui/.eslintrc.js
@@ -0,0 +1,8 @@
+/** @type {import('eslint').ESLint.ConfigData} */
+module.exports = {
+ extends: [require.resolve('@polyfrost/config/eslint/web.js')],
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ project: './tsconfig.json'
+ }
+};
diff --git a/packages/ui/package.json b/packages/ui/package.json
new file mode 100644
index 0000000..e79d4c0
--- /dev/null
+++ b/packages/ui/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "@polyfrost/ui",
+ "version": "0.0.0",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "exports": {
+ ".": "./src/index.ts",
+ "./src/forms": "./src/forms/index.ts",
+ "./postcss": "./style/postcss.config.js",
+ "./tailwind": "./style/tailwind.js",
+ "./style": "./style/index.js",
+ "./style/style.scss": "./style/style.scss",
+ "./package.json": "./package.json"
+ },
+ "scripts": {
+ "lint": "eslint src --cache",
+ "typecheck": "tsc -b"
+ },
+ "dependencies": {
+ "@headlessui/react": "^1.7.17",
+ "@headlessui/tailwindcss": "^0.1.1",
+ "@react-spring/web": "^9.7.3",
+ "@polyfrost/assets": "workspace:*",
+ "@tailwindcss/forms": "^0.5.6",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.0.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.16.0",
+ "sonner": "^1.0.3",
+ "tailwindcss-radix": "^2.8.0",
+ "ts-pattern": "^5.0.5",
+ "use-debounce": "^9.0.4",
+ "zod": "^3.22.4"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.23.2",
+ "@polyfrost/config": "workspace:*",
+ "@storybook/types": "^7.4.6",
+ "@tailwindcss/typography": "^0.5.10",
+ "@types/node": "~18.17.19",
+ "@types/react": "^18.2.28",
+ "@types/react-dom": "^18.2.13",
+ "autoprefixer": "^10.4.16",
+ "postcss": "^8.4.31",
+ "sass": "^1.69.3",
+ "tailwindcss": "^3.3.3",
+ "tailwindcss-animate": "^1.0.7",
+ "typescript": "^5.2.2"
+ }
+}
diff --git a/packages/ui/postcss.config.js b/packages/ui/postcss.config.js
new file mode 100644
index 0000000..708cbaf
--- /dev/null
+++ b/packages/ui/postcss.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ plugins: [require('tailwindcss'), require('autoprefixer')]
+};
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
new file mode 100644
index 0000000..904db93
--- /dev/null
+++ b/packages/ui/src/index.ts
@@ -0,0 +1 @@
+export { cva, cx } from 'class-variance-authority';
diff --git a/packages/ui/src/keys.ts b/packages/ui/src/keys.ts
new file mode 100644
index 0000000..55940f9
--- /dev/null
+++ b/packages/ui/src/keys.ts
@@ -0,0 +1,56 @@
+export enum ModifierKeys {
+ Alt = 'Alt',
+ Shift = 'Shift',
+ AltGraph = 'AltGraph',
+ CapsLock = 'CapsLock',
+ Control = 'Control',
+ Fn = 'Fn',
+ FnLock = 'FnLock',
+ Meta = 'Meta',
+ NumLock = 'NumLock',
+ ScrollLock = 'ScrollLock',
+ Symbol = 'Symbol',
+ SymbolLock = 'SymbolLock'
+}
+
+export type OSforKeys = 'macOS' | 'Windows' | 'Other';
+
+export const modifierSymbols: Record<
+ ModifierKeys,
+ { macOS?: string; Windows?: string; Other: string }
+> = {
+ Alt: { macOS: '⌥', Other: 'Alt' },
+ AltGraph: { macOS: '⌥', Other: 'Alt' },
+ CapsLock: { Other: '⇪' },
+ Control: { macOS: '⌃', Other: 'Ctrl' },
+ Fn: { macOS: 'fn', Other: 'Fn' },
+ FnLock: { macOS: 'fn', Other: 'Fn' },
+ Meta: { macOS: '⌘', Windows: '⊞ Win', Other: 'Meta' },
+ NumLock: { macOS: '⇭', Other: 'Num' },
+ ScrollLock: { macOS: '⤓', Other: 'ScrLk' },
+ Shift: { Other: 'Shift', macOS: '⇧' },
+ Symbol: { macOS: '⎄', Other: 'Sym' },
+ SymbolLock: { macOS: '⎄', Other: 'Sym' }
+};
+
+export const keySymbols: Record<string, { macOS?: string; Windows?: string; Other: string }> = {
+ ' ': { Other: '␣' },
+ 'Tab': { macOS: '⇥', Other: '⭾' },
+ 'Enter': { macOS: '↩', Other: '↵' },
+ 'Escape': { macOS: '⎋', Other: 'Esc' },
+ 'Backspace': { macOS: '⌫', Other: '⟵' },
+ 'ArrowUp': { Other: '↑' },
+ 'ArrowDown': { Other: '↓' },
+ 'ArrowLeft': { Other: '←' },
+ 'ArrowRight': { Other: '→' },
+ 'Insert': { Other: 'Ins' },
+ 'Delete': { macOS: '⌦', Other: 'Del' },
+ 'Home': { macOS: '↖', Other: 'Home' },
+ 'End': { macOS: '↘', Other: 'End' },
+ 'PageUp': { macOS: '⇞', Other: 'PgUp' },
+ 'PageDown': { macOS: '⇟', Other: 'PgDn' },
+ 'Shift': { macOS: '⇧', Other: 'Shift' },
+ 'PrintScreen': { Other: 'PrtSc' },
+ 'ScrollLock': { macOS: '⤓', Other: 'ScrLk' },
+ 'Pause': { macOS: '⎉', Other: 'Pause' }
+};
diff --git a/packages/ui/src/utils.tsx b/packages/ui/src/utils.tsx
new file mode 100644
index 0000000..5ccb488
--- /dev/null
+++ b/packages/ui/src/utils.tsx
@@ -0,0 +1,28 @@
+import clsx from 'clsx';
+import React from 'react';
+
+const twFactory =
+ (element: any) =>
+ ([newClassNames, ..._]: TemplateStringsArray) =>
+ React.forwardRef(({ className, ...props }: any, ref) =>
+ React.createElement(element, {
+ ...props,
+ className: clsx(newClassNames, className),
+ ref
+ })
+ );
+
+type ClassnameFactory<T> = (s: TemplateStringsArray) => T;
+
+type TailwindFactory = {
+ [K in keyof JSX.IntrinsicElements]: ClassnameFactory<
+ React.ForwardRefExoticComponent<JSX.IntrinsicElements[K]>
+ >;
+} & {
+ <T>(c: T): ClassnameFactory<T>;
+};
+
+export const tw = new Proxy((() => {}) as unknown as TailwindFactory, {
+ get: (_, property: string) => twFactory(property),
+ apply: (_, __, [el]: [React.ReactElement]) => twFactory(el)
+});
diff --git a/packages/ui/style/index.js b/packages/ui/style/index.js
new file mode 100644
index 0000000..423b033
--- /dev/null
+++ b/packages/ui/style/index.js
@@ -0,0 +1 @@
+import './style.scss';
diff --git a/packages/ui/style/postcss.config.js b/packages/ui/style/postcss.config.js
new file mode 100644
index 0000000..0b6eba2
--- /dev/null
+++ b/packages/ui/style/postcss.config.js
@@ -0,0 +1 @@
+module.exports = require('../postcss.config');
diff --git a/packages/ui/style/style.scss b/packages/ui/style/style.scss
new file mode 100644
index 0000000..bf5a2e7
--- /dev/null
+++ b/packages/ui/style/style.scss
@@ -0,0 +1,30 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+@tailwind variants;
+
+* {
+ font-family: 'Poppins', sans-serif;
+}
+
+@layer base {
+ :focus-visible {
+ @apply outline-none ring ring-blue-500;
+ }
+}
+
+@layer utilities {
+ .no-scrollbar::-webkit-scrollbar {
+ display: none;
+ }
+
+ .no-scrollbar {
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+ }
+}
+
+// tauri button patch
+[type='button'] {
+ -webkit-appearance: none;
+}
diff --git a/packages/ui/style/tailwind.js b/packages/ui/style/tailwind.js
new file mode 100644
index 0000000..fc05bd9
--- /dev/null
+++ b/packages/ui/style/tailwind.js
@@ -0,0 +1,119 @@
+const defaultTheme = require('tailwindcss/defaultTheme');
+
+/** @type {(varName: string) => string} */
+const alpha = (varName) => `hsla(var(${varName}), <alpha-value>)`;
+const contentExts = `{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue,stories.tsx}`;
+
+/**
+ * @param {string} app
+ * @param {import('tailwindcss').Config} options
+ * @returns {import('tailwindcss').Config}
+ */
+module.exports = (app, options) => {
+ /** @type {import('tailwindcss').Config} */
+ let config = {
+ content: [
+ `../../apps/${app}/src/**/*.${contentExts}`,
+ `../../packages/*/src/**/*.${contentExts}`,
+ `../../interface/**/*.${contentExts}`
+ ],
+ darkMode: 'class',
+ theme: {
+ screens: {
+ xs: '475px',
+ sm: '650px',
+ md: '868px',
+ lg: '1024px',
+ xl: '1280px',
+ ...defaultTheme.screens
+ },
+ fontSize: {
+ 'xs': '12px',
+ 'sm': '14px',
+ 'md': '16px',
+ 'lg': '18px',
+ 'header-sm': '24px',
+ 'header': '28px',
+ 'header-lg': '32px',
+ 'body-sm': '15px',
+ 'body': '16px',
+ 'body-lg': '17px'
+ },
+ borderRadius: {
+ none: '0',
+ sm: '3px',
+ md: '5px',
+ lg: '8px',
+ xl: '12px',
+ full: '100vw'
+ },
+ extend: {
+ colors: {
+ blue: {
+ 500: 'rgba(31, 101, 214, 1)'
+ },
+ gray: {
+ 50: 'rgba(240, 242, 244, 1)',
+ 400: 'rgba(138, 150, 168, 1)',
+ 700: 'rgba(65, 74, 88, 1)',
+ 800: 'rgba(42, 47, 55, 1)'
+ },
+ white: {
+ DEFAULT: 'rgba(255, 255, 255, 1)',
+ secondary: 'rgba(238, 241, 254, 1)',
+ hover: 'rgba(231, 235, 252, 1)'
+ },
+ black: {
+ DEFAULT: 'rgba(0, 0, 0, 1)'
+ },
+ text: {
+ DEFAULT: 'rgba(2, 3, 7, 1)',
+ primary: 'rgba(2, 3, 7, 1)'
+ }
+ },
+ extend: {
+ transitionTimingFunction: {
+ 'css': 'ease',
+ 'css-in': 'ease-in',
+ 'css-out': 'ease-out',
+ 'css-in-out': 'ease-in-out',
+ 'in-sine': 'cubic-bezier(0.12, 0, 0.39, 0)',
+ 'out-sine': 'cubic-bezier(0.61, 1, 0.88, 1)',
+ 'in-out-sine': 'cubic-bezier(0.37, 0, 0.63, 1)',
+ 'in-quad': 'cubic-bezier(0.11, 0, 0.5, 0)',
+ 'out-quad': 'cubic-bezier(0.5, 1, 0.89, 1)',
+ 'in-out-quad': 'cubic-bezier(0.45, 0, 0.55, 1)',
+ 'in-cubic': 'cubic-bezier(0.32, 0, 0.67, 0)',
+ 'out-cubic': 'cubic-bezier(0.33, 1, 0.68, 1)',
+ 'in-out-cubic': 'cubic-bezier(0.65, 0, 0.35, 1)',
+ 'in-quart': 'cubic-bezier(0.5, 0, 0.75, 0)',
+ 'out-quart': 'cubic-bezier(0.25, 1, 0.5, 1)',
+ 'in-out-quart': 'cubic-bezier(0.76, 0, 0.24, 1)',
+ 'in-quint': 'cubic-bezier(0.64, 0, 0.78, 0)',
+ 'out-quint': 'cubic-bezier(0.22, 1, 0.36, 1)',
+ 'in-out-quint': 'cubic-bezier(0.83, 0, 0.17, 1)',
+ 'in-expo': 'cubic-bezier(0.7, 0, 0.84, 0)',
+ 'out-expo': 'cubic-bezier(0.16, 1, 0.3, 1)',
+ 'in-out-expo': 'cubic-bezier(0.87, 0, 0.13, 1)',
+ 'in-circ': 'cubic-bezier(0.55, 0, 1, 0.45)',
+ 'out-circ': 'cubic-bezier(0, 0.55, 0.45, 1)',
+ 'in-out-circ': 'cubic-bezier(0.85, 0, 0.15, 1)',
+ 'in-back': 'cubic-bezier(0.36, 0, 0.66, -0.56)',
+ 'out-back': 'cubic-bezier(0.34, 1.56, 0.64, 1)',
+ 'in-out-back': 'cubic-bezier(0.68, -0.6, 0.32, 1.6)'
+ }
+ }
+ }
+ },
+ plugins: [
+ require('@tailwindcss/forms'),
+ require('tailwindcss-animate'),
+ require('@headlessui/tailwindcss'),
+ require('tailwindcss-radix')()
+ ]
+ };
+
+ if (app === 'website') config.plugins.push(require('@tailwindcss/typography'));
+
+ return config;
+};
diff --git a/packages/ui/style/tailwind.pcss b/packages/ui/style/tailwind.pcss
new file mode 100644
index 0000000..510ff1d
--- /dev/null
+++ b/packages/ui/style/tailwind.pcss
@@ -0,0 +1,4 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+@tailwind variants;
diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js
new file mode 100644
index 0000000..8c53793
--- /dev/null
+++ b/packages/ui/tailwind.config.js
@@ -0,0 +1,2 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = require('./style/tailwind')('web');
diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json
new file mode 100644
index 0000000..8e080d5
--- /dev/null
+++ b/packages/ui/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../config/base.tsconfig.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "declarationDir": "dist"
+ },
+ "include": ["src"]
+}