├── .babelrc ├── .codesandbox └── ci.json ├── .editorconfig ├── .env ├── .eslintrc.js ├── .firebaserc ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .prettierrc ├── .storybook ├── decorators │ └── withGlobalStyle.tsx ├── logo.png ├── main.ts ├── manager.css ├── manager.ts ├── preview.ts ├── theme-picker │ ├── ThemeButton.tsx │ ├── ThemeList.tsx │ ├── ThemeProvider.tsx │ ├── constants.ts │ └── register.ts └── theme.js ├── LICENSE ├── README.md ├── docs ├── Contributing.stories.mdx ├── Getting-Started.stories.mdx ├── Submit-your-Project.stories.mdx └── Welcome.stories.mdx ├── firebase.json ├── jest.config.js ├── package.json ├── rollup.config.js ├── src ├── Anchor │ ├── Anchor.spec.tsx │ ├── Anchor.stories.tsx │ └── Anchor.tsx ├── AppBar │ ├── AppBar.spec.tsx │ ├── AppBar.stories.tsx │ └── AppBar.tsx ├── Avatar │ ├── Avatar.spec.tsx │ ├── Avatar.stories.tsx │ └── Avatar.tsx ├── Button │ ├── Button.spec.tsx │ ├── Button.stories.tsx │ └── Button.tsx ├── Checkbox │ ├── Checkbox.spec.tsx │ ├── Checkbox.stories.tsx │ └── Checkbox.tsx ├── ColorInput │ ├── ColorInput.spec.tsx │ ├── ColorInput.stories.tsx │ └── ColorInput.tsx ├── Counter │ ├── Counter.spec.tsx │ ├── Counter.stories.tsx │ ├── Counter.tsx │ └── Digit.tsx ├── DatePicker │ ├── DatePicker.stories.tsx │ └── DatePicker.tsx ├── Frame │ ├── Frame.spec.tsx │ ├── Frame.stories.tsx │ └── Frame.tsx ├── GroupBox │ ├── GroupBox.spec.tsx │ ├── GroupBox.stories.tsx │ └── GroupBox.tsx ├── Handle │ ├── Handle.spec.tsx │ ├── Handle.stories.tsx │ └── Handle.tsx ├── Hourglass │ ├── Hourglass.spec.tsx │ ├── Hourglass.stories.tsx │ ├── Hourglass.tsx │ └── base64hourglass.tsx ├── MenuList │ ├── MenuList.spec.tsx │ ├── MenuList.stories.tsx │ ├── MenuList.tsx │ ├── MenuListItem.spec.tsx │ └── MenuListItem.tsx ├── Monitor │ ├── Monitor.spec.tsx │ ├── Monitor.stories.tsx │ └── Monitor.tsx ├── NumberInput │ ├── NumberInput.spec.tsx │ ├── NumberInput.stories.tsx │ └── NumberInput.tsx ├── ProgressBar │ ├── ProgressBar.spec.tsx │ ├── ProgressBar.stories.tsx │ └── ProgressBar.tsx ├── Radio │ ├── Radio.spec.tsx │ ├── Radio.stories.tsx │ └── Radio.tsx ├── ScrollView │ ├── ScrollView.spec.tsx │ ├── ScrollView.stories.tsx │ └── ScrollView.tsx ├── Select │ ├── Select.spec.tsx │ ├── Select.stories.data.ts │ ├── Select.stories.tsx │ ├── Select.styles.tsx │ ├── Select.tsx │ ├── Select.types.ts │ ├── SelectNative.spec.tsx │ ├── SelectNative.tsx │ ├── useSelectCommon.tsx │ └── useSelectState.ts ├── Separator │ ├── Separator.spec.tsx │ ├── Separator.stories.tsx │ └── Separator.tsx ├── Slider │ ├── Slider.spec.tsx │ ├── Slider.stories.tsx │ └── Slider.tsx ├── Table │ ├── Table.spec.tsx │ ├── Table.stories.tsx │ ├── Table.tsx │ ├── TableBody.spec.tsx │ ├── TableBody.tsx │ ├── TableDataCell.spec.tsx │ ├── TableDataCell.tsx │ ├── TableHead.spec.tsx │ ├── TableHead.tsx │ ├── TableHeadCell.spec.tsx │ ├── TableHeadCell.tsx │ ├── TableRow.spec.tsx │ └── TableRow.tsx ├── Tabs │ ├── Tab.spec.tsx │ ├── Tab.tsx │ ├── TabBody.spec.tsx │ ├── TabBody.tsx │ ├── Tabs.spec.tsx │ ├── Tabs.stories.tsx │ └── Tabs.tsx ├── TextInput │ ├── TextInput.spec.tsx │ ├── TextInput.stories.tsx │ └── TextInput.tsx ├── Toolbar │ ├── Toolbar.spec.tsx │ └── Toolbar.tsx ├── Tooltip │ ├── Tooltip.spec.tsx │ ├── Tooltip.stories.tsx │ └── Tooltip.tsx ├── TreeView │ ├── TreeView.spec.tsx │ ├── TreeView.stories.tsx │ └── TreeView.tsx ├── Window │ ├── Window.spec.tsx │ ├── Window.stories.tsx │ ├── Window.tsx │ ├── WindowContent.spec.tsx │ ├── WindowContent.tsx │ ├── WindowHeader.spec.tsx │ └── WindowHeader.tsx ├── assets │ ├── fonts │ │ ├── dist │ │ │ ├── ms_sans_serif.woff │ │ │ ├── ms_sans_serif.woff2 │ │ │ ├── ms_sans_serif_bold.woff │ │ │ └── ms_sans_serif_bold.woff2 │ │ └── src │ │ │ ├── ms-sans-serif-bold │ │ │ ├── MS Sans Serif Bold.ttf │ │ │ ├── license.txt │ │ │ └── readme.txt │ │ │ └── ms-sans-serif │ │ │ ├── MS Sans Serif.ttf │ │ │ ├── license.txt │ │ │ └── readme.txt │ └── images │ │ ├── logo.png │ │ └── logo.psd ├── common │ ├── SwitchBase.ts │ ├── constants.ts │ ├── hooks │ │ ├── useControlledOrUncontrolled.ts │ │ ├── useEventCallback.ts │ │ ├── useForkRef.spec.tsx │ │ ├── useForkRef.ts │ │ ├── useId.spec.ts │ │ ├── useId.ts │ │ └── useIsFocusVisible.ts │ ├── index.ts │ ├── styleReset.ts │ ├── system.ts │ ├── themes │ │ ├── aiee.ts │ │ ├── ash.ts │ │ ├── azureOrange.ts │ │ ├── bee.ts │ │ ├── blackAndWhite.ts │ │ ├── blue.ts │ │ ├── brick.ts │ │ ├── candy.ts │ │ ├── cherry.ts │ │ ├── coldGray.ts │ │ ├── counterStrike.ts │ │ ├── darkTeal.ts │ │ ├── denim.ts │ │ ├── eggplant.ts │ │ ├── fxDev.ts │ │ ├── highContrast.ts │ │ ├── honey.ts │ │ ├── hotChocolate.ts │ │ ├── hotdogStand.ts │ │ ├── index.ts │ │ ├── lilac.ts │ │ ├── lilacRoseDark.ts │ │ ├── maple.ts │ │ ├── marine.ts │ │ ├── matrix.ts │ │ ├── millenium.ts │ │ ├── modernDark.ts │ │ ├── molecule.ts │ │ ├── monochrome.ts │ │ ├── ninjaTurtles.ts │ │ ├── olive.ts │ │ ├── original.ts │ │ ├── pamelaAnderson.ts │ │ ├── peggysPastels.ts │ │ ├── plum.ts │ │ ├── polarized.ts │ │ ├── powerShell.ts │ │ ├── rainyDay.ts │ │ ├── raspberry.ts │ │ ├── redWine.ts │ │ ├── rose.ts │ │ ├── seawater.ts │ │ ├── shelbiTeal.ts │ │ ├── slate.ts │ │ ├── solarizedDark.ts │ │ ├── solarizedLight.ts │ │ ├── spruce.ts │ │ ├── stormClouds.ts │ │ ├── theSixtiesUSA.ts │ │ ├── tokyoDark.ts │ │ ├── toner.ts │ │ ├── tooSexy.ts │ │ ├── travel.ts │ │ ├── types.ts │ │ ├── vaporTeal.ts │ │ ├── vermillion.ts │ │ ├── violetDark.ts │ │ ├── vistaesqueMidnight.ts │ │ ├── water.ts │ │ ├── white.ts │ │ ├── windows1.ts │ │ └── wmii.ts │ └── utils │ │ ├── events.spec.tsx │ │ ├── events.ts │ │ ├── index.spec.ts │ │ └── index.ts ├── index.ts ├── legacy │ ├── Bar.tsx │ ├── Cutout.tsx │ ├── Desktop.tsx │ ├── Divider.tsx │ ├── Fieldset.tsx │ ├── List.tsx │ ├── ListItem.tsx │ ├── NumberField.tsx │ ├── Panel.tsx │ ├── Progress.tsx │ ├── TextField.tsx │ └── Tree.tsx └── types.ts ├── test ├── setup-test.ts └── utils.tsx ├── tsconfig.build.index.json ├── tsconfig.build.themes.json ├── tsconfig.json ├── types ├── globals.d.ts └── themes.d.ts └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "sourceType": "unambiguous", 3 | "presets": [ 4 | [ 5 | "@babel/preset-env", 6 | { 7 | "shippedProposals": true, 8 | "loose": true 9 | } 10 | ], 11 | "@babel/preset-typescript" 12 | ], 13 | "plugins": [ 14 | "@babel/plugin-transform-shorthand-properties", 15 | "@babel/plugin-transform-block-scoping", 16 | [ 17 | "@babel/plugin-proposal-decorators", 18 | { 19 | "legacy": true 20 | } 21 | ], 22 | [ 23 | "@babel/plugin-proposal-class-properties", 24 | { 25 | "loose": true 26 | } 27 | ], 28 | [ 29 | "@babel/plugin-proposal-private-property-in-object", 30 | { 31 | "loose": true 32 | } 33 | ], 34 | [ 35 | "@babel/plugin-proposal-private-methods", 36 | { 37 | "loose": true 38 | } 39 | ], 40 | "@babel/plugin-proposal-export-default-from", 41 | "@babel/plugin-syntax-dynamic-import", 42 | [ 43 | "@babel/plugin-proposal-object-rest-spread", 44 | { 45 | "loose": true, 46 | "useBuiltIns": true 47 | } 48 | ], 49 | "@babel/plugin-transform-classes", 50 | "@babel/plugin-transform-arrow-functions", 51 | "@babel/plugin-transform-parameters", 52 | "@babel/plugin-transform-destructuring", 53 | "@babel/plugin-transform-spread", 54 | "@babel/plugin-transform-for-of", 55 | "babel-plugin-macros", 56 | "@babel/plugin-proposal-optional-chaining", 57 | "@babel/plugin-proposal-nullish-coalescing-operator" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand": "build:prod", 3 | "node": "16", 4 | "sandboxes": [ 5 | "react95-template-xkfj0" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = yes 9 | insert_final_newline = yes 10 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | BROWSER=none 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'plugin:@typescript-eslint/recommended', 4 | 'airbnb', 5 | 'plugin:prettier/recommended', 6 | 'plugin:react-hooks/recommended' 7 | ], 8 | parser: '@typescript-eslint/parser', 9 | plugins: ['react', 'prettier'], 10 | env: { 11 | browser: true, 12 | es6: true, 13 | jest: true 14 | }, 15 | rules: { 16 | '@typescript-eslint/explicit-module-boundary-types': 'off', 17 | '@typescript-eslint/no-empty-function': 'off', 18 | '@typescript-eslint/no-empty-interface': 'off', 19 | '@typescript-eslint/no-use-before-define': 'off', 20 | '@typescript-eslint/no-unused-vars': [ 21 | 'error', 22 | { 23 | argsIgnorePattern: '^_\\d*$' 24 | } 25 | ], 26 | 'import/extensions': ['error', { js: 'never', ts: 'never', tsx: 'never' }], 27 | 'import/no-unresolved': [ 28 | 'error', 29 | // TODO: Remove ../../test/utils when TypeScript migration is complete 30 | { ignore: ['react95', '../../test/utils'] } 31 | ], 32 | 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], 33 | 'import/prefer-default-export': 'off', 34 | 'jsx-a11y/label-has-associated-control': ['error', { assert: 'either' }], 35 | 'jsx-a11y/label-has-for': 'off', 36 | 'no-nested-ternary': 'off', 37 | 'prettier/prettier': 'error', 38 | 'react/forbid-prop-types': 'off', 39 | 'react/jsx-filename-extension': [ 40 | 'warn', 41 | { extensions: ['.js', '.jsx', '.tsx'] } 42 | ], 43 | 'react/jsx-props-no-spreading': 'off', 44 | 'react/no-array-index-key': 'off', 45 | 'react/prop-types': 'off', 46 | 'react/require-default-props': 'off', 47 | 'react/static-property-placement': ['error', 'static public field'] 48 | }, 49 | overrides: [ 50 | { 51 | files: ['*.spec.@(js|jsx|ts|tsx)', '*.stories.@(js|jsx|ts|tsx)'], 52 | rules: { 53 | 'no-console': 'off' 54 | } 55 | }, 56 | { 57 | files: ['*.@(ts|tsx)'], 58 | rules: { 59 | // This is handled by @typescript-eslint/no-unused-vars 60 | 'no-undef': 'off' 61 | } 62 | } 63 | ], 64 | settings: { 65 | 'import/parsers': { 66 | '@typescript-eslint/parser': ['.ts', '.tsx'] 67 | }, 68 | 'import/resolver': { 69 | typescript: {} 70 | } 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "react95-storybook" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: arturbien 4 | patreon: arturbien 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | custom: https://www.paypal.me/react95 9 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - next 8 | - beta 9 | - alpha 10 | - '*.x' # maintenance releases 11 | 12 | jobs: 13 | release-library: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Git Checkout 17 | uses: actions/checkout@v2 18 | 19 | - name: Setup node 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: 16 23 | 24 | - name: Cache packages 25 | uses: actions/cache@v3 26 | with: 27 | key: node_modules-v4-${{ hashFiles('yarn.lock') }} 28 | path: |- 29 | node_modules 30 | */node_modules 31 | restore-keys: 'node_modules-v4-' 32 | 33 | - name: Yarn install 34 | run: yarn install --ignore-optional --frozen-lockfile 35 | 36 | - name: Build library 37 | run: yarn run build 38 | 39 | - name: Deploy library 40 | run: yarn run semantic-release || true 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 44 | 45 | release-storybook: 46 | needs: 47 | - release-library 48 | if: github.ref == 'refs/heads/master' 49 | runs-on: ubuntu-latest 50 | steps: 51 | - name: Git Checkout 52 | uses: actions/checkout@v2 53 | 54 | - name: Setup node 55 | uses: actions/setup-node@v3 56 | with: 57 | node-version: 16 58 | 59 | - name: Cache packages 60 | uses: actions/cache@v3 61 | with: 62 | key: node_modules-v4-${{ hashFiles('yarn.lock') }} 63 | path: |- 64 | node_modules 65 | */node_modules 66 | restore-keys: 'node_modules-v4-' 67 | 68 | - name: Yarn install 69 | run: yarn install --ignore-optional --frozen-lockfile 70 | 71 | - name: Build Storybook 72 | run: yarn run build:storybook 73 | 74 | - name: Deploy Storybook 75 | run: ./node_modules/.bin/firebase deploy --token=$FIREBASE_TOKEN 76 | env: 77 | FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # library build 12 | /cjs 13 | /esm 14 | /themes 15 | /images 16 | /fonts 17 | /dist 18 | 19 | # storybook 20 | /storybook 21 | /.firebase 22 | 23 | # misc 24 | .DS_Store 25 | .env.local 26 | .env.development.local 27 | .env.test.local 28 | .env.production.local 29 | 30 | npm-debug.log* 31 | yarn-debug.log* 32 | yarn-error.log* 33 | 34 | # JetBrains IDEs 35 | .idea/* 36 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": true, 4 | "htmlWhitespaceSensitivity": "css", 5 | "insertPragma": false, 6 | "jsxBracketSameLine": false, 7 | "jsxSingleQuote": true, 8 | "printWidth": 80, 9 | "proseWrap": "preserve", 10 | "quoteProps": "as-needed", 11 | "requirePragma": false, 12 | "semi": true, 13 | "singleQuote": true, 14 | "tabWidth": 2, 15 | "trailingComma": "none", 16 | "useTabs": false 17 | } 18 | -------------------------------------------------------------------------------- /.storybook/decorators/withGlobalStyle.tsx: -------------------------------------------------------------------------------- 1 | import { DecoratorFn } from '@storybook/react'; 2 | import React from 'react'; 3 | import { createGlobalStyle } from 'styled-components'; 4 | 5 | import ms_sans_serif from '../../src/assets/fonts/dist/ms_sans_serif.woff2'; 6 | import ms_sans_serif_bold from '../../src/assets/fonts/dist/ms_sans_serif_bold.woff2'; 7 | import styleReset from '../../src/common/styleReset'; 8 | 9 | const GlobalStyle = createGlobalStyle` 10 | ${styleReset} 11 | @font-face { 12 | font-family: 'ms_sans_serif'; 13 | src: url('${ms_sans_serif}') format('woff2'); 14 | font-weight: 400; 15 | font-style: normal 16 | } 17 | @font-face { 18 | font-family: 'ms_sans_serif'; 19 | src: url('${ms_sans_serif_bold}') format("woff2"); 20 | font-weight: bold; 21 | font-style: normal 22 | } 23 | html, body, #root { 24 | height: 100%; 25 | } 26 | #root > * { 27 | height: 100%; 28 | box-sizing: border-box; 29 | } 30 | body { 31 | font-family: 'ms_sans_serif', 'sans-serif'; 32 | } 33 | `; 34 | 35 | export const withGlobalStyle: DecoratorFn = story => ( 36 | <> 37 | 38 | {story()} 39 | 40 | ); 41 | -------------------------------------------------------------------------------- /.storybook/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/.storybook/logo.png -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from '@storybook/react/types'; 2 | import type { PropItem } from 'react-docgen-typescript'; 3 | 4 | const path = require('path'); 5 | 6 | const storybookConfig: StorybookConfig = { 7 | stories: ['../@(docs|src)/**/*.stories.@(tsx|mdx)'], 8 | addons: [ 9 | { 10 | name: '@storybook/addon-docs', 11 | options: { 12 | sourceLoaderOptions: { 13 | injectStoryParameters: false 14 | } 15 | } 16 | }, 17 | '@storybook/addon-storysource', 18 | './theme-picker/register.ts' 19 | ], 20 | core: { 21 | builder: 'webpack5' 22 | }, 23 | features: { 24 | babelModeV7: true, 25 | storyStoreV7: true, 26 | modernInlineRender: true, 27 | postcss: false 28 | }, 29 | typescript: { 30 | check: false, 31 | checkOptions: {}, 32 | reactDocgen: 'react-docgen-typescript', 33 | reactDocgenTypescriptOptions: { 34 | shouldExtractLiteralValuesFromEnum: true, 35 | propFilter: (prop: PropItem) => 36 | prop.parent ? !/node_modules/.test(prop.parent.fileName) : true 37 | } 38 | }, 39 | webpackFinal: config => { 40 | config.resolve = { 41 | ...config.resolve, 42 | alias: { 43 | ...config.resolve?.alias, 44 | react95: path.resolve(__dirname, '../src/index') 45 | } 46 | }; 47 | 48 | return config; 49 | } 50 | }; 51 | 52 | module.exports = storybookConfig; 53 | -------------------------------------------------------------------------------- /.storybook/manager.css: -------------------------------------------------------------------------------- 1 | /* Remove from the sidebar menu stories that contains "unstable" */ 2 | a[data-item-id$='-unstable'].sidebar-item, 3 | a[data-item-id*='-unstable-'].sidebar-item, 4 | button[data-item-id$='-unstable'].sidebar-item, 5 | button[data-item-id$='-unstable-'].sidebar-item { 6 | display: none !important; 7 | } 8 | -------------------------------------------------------------------------------- /.storybook/manager.ts: -------------------------------------------------------------------------------- 1 | import './manager.css'; 2 | 3 | import { addons } from '@storybook/addons'; 4 | import theme from './theme'; 5 | 6 | addons.setConfig({ 7 | theme 8 | }); 9 | -------------------------------------------------------------------------------- /.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import { DecoratorFn, Parameters } from '@storybook/react'; 2 | import { withGlobalStyle } from './decorators/withGlobalStyle'; 3 | import { withThemesProvider } from './theme-picker/ThemeProvider'; 4 | 5 | export const decorators: DecoratorFn[] = [withGlobalStyle, withThemesProvider]; 6 | 7 | export const parameters: Parameters = { 8 | layout: 'fullscreen', 9 | options: { 10 | storySort: { 11 | order: [ 12 | 'Docs', 13 | [ 14 | 'Welcome to React95', 15 | 'Getting Started', 16 | 'Contributing', 17 | 'Submit your Project' 18 | ], 19 | 'Controls', 20 | 'Environment', 21 | 'Layout', 22 | 'Typography', 23 | 'Other' 24 | ] 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /.storybook/theme-picker/ThemeButton.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react'; 2 | import { ThemeProvider } from 'styled-components'; 3 | import { Button } from '../../src/Button/Button'; 4 | import { Theme } from '../../src/types'; 5 | 6 | export function ThemeButton({ 7 | active, 8 | onChoose, 9 | theme 10 | }: { 11 | active: boolean; 12 | onChoose: (themeName: string) => void; 13 | theme: Theme; 14 | }) { 15 | const handleClick = useCallback(() => { 16 | onChoose(theme.name); 17 | }, []); 18 | 19 | return ( 20 | 21 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /.storybook/theme-picker/ThemeList.tsx: -------------------------------------------------------------------------------- 1 | import { useAddonState } from '@storybook/api'; 2 | import React, { useCallback } from 'react'; 3 | import styled from 'styled-components'; 4 | 5 | import themes from '../../src/common/themes'; 6 | import { Theme } from '../../src/types'; 7 | import { THEMES_ID } from './constants'; 8 | import { ThemeButton } from './ThemeButton'; 9 | 10 | const { 11 | original, 12 | rainyDay, 13 | vaporTeal, 14 | theSixtiesUSA, 15 | olive, 16 | tokyoDark, 17 | rose, 18 | plum, 19 | matrix, 20 | travel, 21 | ...otherThemes 22 | } = themes; 23 | 24 | const themeList = [ 25 | original, 26 | rainyDay, 27 | vaporTeal, 28 | theSixtiesUSA, 29 | olive, 30 | tokyoDark, 31 | rose, 32 | plum, 33 | matrix, 34 | travel, 35 | ...Object.values(otherThemes) 36 | ]; 37 | 38 | type ThemesProps = { 39 | active?: boolean; 40 | }; 41 | 42 | const Wrapper = styled.div<{ theme: Theme }>` 43 | display: grid; 44 | padding: 1em; 45 | gap: 1em; 46 | grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); 47 | grid-template-rows: repeat(auto-fill, 40px); 48 | background-color: ${({ theme }) => theme.material}; 49 | `; 50 | 51 | export function ThemeList({ active }: ThemesProps) { 52 | const [themeName, setThemeName] = useAddonState(THEMES_ID, 'original'); 53 | 54 | const handleChoose = useCallback( 55 | (newThemeName: string) => { 56 | setThemeName(newThemeName); 57 | }, 58 | [setThemeName] 59 | ); 60 | 61 | if (!active) { 62 | return <>; 63 | } 64 | 65 | return ( 66 | 67 | {themeList.map(theme => ( 68 | 74 | ))} 75 | 76 | ); 77 | } 78 | -------------------------------------------------------------------------------- /.storybook/theme-picker/ThemeProvider.tsx: -------------------------------------------------------------------------------- 1 | import { useAddonState } from '@storybook/client-api'; 2 | import { DecoratorFn } from '@storybook/react'; 3 | import React from 'react'; 4 | import { ThemeProvider } from 'styled-components'; 5 | 6 | import themes from '../../src/common/themes/index'; 7 | import { THEMES_ID } from './constants'; 8 | 9 | export const withThemesProvider: DecoratorFn = story => { 10 | const [themeName] = useAddonState(THEMES_ID, 'original'); 11 | 12 | return ( 13 | 14 | {story()} 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /.storybook/theme-picker/constants.ts: -------------------------------------------------------------------------------- 1 | export const THEMES_ID = 'storybook/themes'; 2 | -------------------------------------------------------------------------------- /.storybook/theme-picker/register.ts: -------------------------------------------------------------------------------- 1 | import addons, { makeDecorator, types } from '@storybook/addons'; 2 | import { THEMES_ID } from './constants'; 3 | import { ThemeList } from './ThemeList'; 4 | 5 | addons.register(THEMES_ID, () => { 6 | addons.addPanel(`${THEMES_ID}/panel`, { 7 | title: 'Themes', 8 | type: types.PANEL, 9 | render: ThemeList 10 | }); 11 | }); 12 | 13 | export default makeDecorator({ 14 | name: 'withThemesProvider', 15 | parameterName: 'theme', 16 | wrapper: (getStory, context) => getStory(context) 17 | }); 18 | -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | import { create } from '@storybook/theming'; 2 | 3 | import brandImage from './logo.png'; 4 | 5 | export default create({ 6 | base: 'light', 7 | brandTitle: 'React95', 8 | brandUrl: 'https://react95.io', 9 | brandImage, 10 | brandTarget: '_self', 11 | 12 | // UI 13 | appBg: '#dfdfdf', 14 | appContentBg: '#ffffff', 15 | appBorderColor: '#848584', 16 | appBorderRadius: 0, 17 | 18 | // Typography 19 | fontBase: '"ms_sans_serif", sans-serif', 20 | fontCode: 'monospace', 21 | 22 | // Text colors 23 | textColor: '#0a0a0a', 24 | textInverseColor: 'rgba(255,255,255,0.9)', 25 | 26 | // Toolbar default and active colors 27 | barTextColor: '#c6c6c6', 28 | barSelectedColor: '#fefefe', 29 | barBg: '#060084', 30 | 31 | // Form colors 32 | inputBg: '#ffffff', 33 | inputBorder: '#dfdfdf', 34 | inputTextColor: '#0a0a0a', 35 | inputBorderRadius: 0 36 | }); 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Artur Bień 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/Contributing.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs'; 2 | 3 | 4 | 5 | # Contributing 6 | 7 | Any help from UI/UX designers would be EXTREMELY appreciated. The challenge is 8 | to come up with new component designs/layouts that are broadly used in modern 9 | UIs, that weren't present back in 95. 10 | 11 | If you want to help with the project, feel free to [open pull requests][1], 12 | [submit issues or component proposals][2] and join our [Slack channels][3]! 13 | Let's bring this UI back to life ♥️ 14 | 15 | [1]: https://github.com/arturbien/react95/pulls 16 | [2]: https://github.com/arturbien/React95/issues 17 | [3]: https://join.slack.com/t/react95/shared_invite/enQtOTA1NzEyNjAyNTc4LWYxZjU3NWRiMWJlMGJiMjhkNzE2MDA3ZmZjZDc1YmY0ODdlZjMwZDA1NWJiYWExYmY1NTJmNmE4OWVjNWFhMTE 18 | -------------------------------------------------------------------------------- /docs/Getting-Started.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs'; 2 | 3 | 4 | 5 | # Installation 6 | 7 | React95 is available as an [npm package](https://www.npmjs.com/package/react95). 8 | 9 | ## npm 10 | 11 | To install and save your `package.json` dependencies, run: 12 | 13 | ```sh 14 | # yarn 15 | yarn add react95 styled-components 16 | 17 | # npm 18 | npm install -S react95 styled-components 19 | ``` 20 | 21 | In order to have `react95` working properly, you'll also need 22 | [styled-components 💅](https://github.com/styled-components/styled-components), 23 | this way you can use custom themes and get the best of the library 🙂 24 | 25 | ## Usage 26 | 27 | Apply style reset, wrap your app content with ThemeProvider with theme of your 28 | choice... and you are ready to go! 🚀 29 | 30 | ```jsx 31 | import React from 'react'; 32 | import { MenuList, MenuListItem, Separator, styleReset } from 'react95'; 33 | import { createGlobalStyle, ThemeProvider } from 'styled-components'; 34 | 35 | /* Pick a theme of your choice */ 36 | import original from 'react95/dist/themes/original'; 37 | 38 | /* Original Windows95 font (optional) */ 39 | import ms_sans_serif from 'react95/dist/fonts/ms_sans_serif.woff2'; 40 | import ms_sans_serif_bold from 'react95/dist/fonts/ms_sans_serif_bold.woff2'; 41 | 42 | const GlobalStyles = createGlobalStyle` 43 | ${styleReset} 44 | @font-face { 45 | font-family: 'ms_sans_serif'; 46 | src: url('${ms_sans_serif}') format('woff2'); 47 | font-weight: 400; 48 | font-style: normal 49 | } 50 | @font-face { 51 | font-family: 'ms_sans_serif'; 52 | src: url('${ms_sans_serif_bold}') format('woff2'); 53 | font-weight: bold; 54 | font-style: normal 55 | } 56 | body, input, select, textarea { 57 | font-family: 'ms_sans_serif'; 58 | } 59 | `; 60 | 61 | const App = () => ( 62 |
63 | 64 | 65 | 66 | 🎤 Sing 67 | 💃🏻 Dance 68 | 69 | 😴 Sleep 70 | 71 | 72 |
73 | ); 74 | 75 | export default App; 76 | ``` 77 | -------------------------------------------------------------------------------- /docs/Submit-your-Project.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs'; 2 | 3 | 4 | 5 | # Submit your Project 6 | 7 | Apps built with React95 will be featured on the official React95 [website](https://react95.io) 🤟🏻 8 | 9 | In order to submit your project, just drop a comment on [this issue](https://github.com/arturbien/React95/issues/25)! 10 | -------------------------------------------------------------------------------- /docs/Welcome.stories.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from '@storybook/addon-docs'; 2 | 3 | 4 | 5 | # Welcome to React95 6 | 7 | 8 | NPM 9 | 10 |   11 | 12 | React95 version 13 | 14 |   15 | 16 | React95 license 20 | 21 | 22 |

23 | Components 24 |  -  25 | Demo app 26 |  -  27 | Website 28 |  -  29 | 30 | Slack 31 | 32 |  -  33 | PayPal donation 💰 34 |

35 | 36 | **Refreshed** Windows 95 UI components for your modern React apps. Built with 37 | [styled-components](https://github.com/styled-components/styled-components) 💅. 38 | 39 | ![hero](https://user-images.githubusercontent.com/28541613/81947711-28b05580-9601-11ea-964a-c3a6de998496.png) 40 | 41 | ### Getting Started 42 | 43 | Check out our [getting started](?path=/story/docs-getting-started--page) docs! 44 | 45 | ### Motivation 46 | 47 | Create modern mobile/web applications with the retro and old school Windows 95 style. Our goal is not to exactly recreate Windows95 components, but to provide a solid component library for current scenarios. 48 | 49 | ### Support 50 | 51 | - [Become a backer or sponsor on Patreon](https://www.patreon.com/arturbien) 52 | - [One-time donation via PayPal](https://www.paypal.me/react95) 53 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "storybook", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | 'ts-jest': { 4 | diagnostics: false, 5 | isolatedModules: true 6 | } 7 | }, 8 | coverageReporters: ['text', 'html'], 9 | preset: 'ts-jest/presets/default-esm', 10 | setupFilesAfterEnv: ['/test/setup-test.ts'], 11 | testEnvironment: 'jsdom' 12 | }; 13 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | import copy from 'rollup-plugin-copy'; 3 | import esbuild from 'rollup-plugin-esbuild'; 4 | import replace from 'rollup-plugin-replace'; 5 | 6 | const NODE_ENV = process.env.NODE_ENV || 'development'; 7 | 8 | const baseBundle = { 9 | external: id => !/^[./]/.test(id), 10 | plugins: [ 11 | replace({ 12 | 'process.env.NODE_ENV': JSON.stringify(NODE_ENV) 13 | }), 14 | esbuild() 15 | ] 16 | }; 17 | 18 | export default [ 19 | { 20 | ...baseBundle, 21 | input: ['./src/index.ts', './src/types.ts'], 22 | output: [ 23 | { 24 | dir: 'dist', 25 | entryFileNames: '[name].js', 26 | exports: 'auto', 27 | format: 'cjs', 28 | preserveModules: true, 29 | preserveModulesRoot: 'src' 30 | }, 31 | { 32 | dir: 'dist', 33 | entryFileNames: '[name].mjs', 34 | exports: 'auto', 35 | format: 'es', 36 | preserveModules: true, 37 | preserveModulesRoot: 'src' 38 | } 39 | ], 40 | plugins: [ 41 | ...baseBundle.plugins, 42 | typescript({ 43 | tsconfig: './tsconfig.build.index.json', 44 | declaration: true, 45 | declarationDir: 'dist' 46 | }) 47 | ] 48 | }, 49 | { 50 | ...baseBundle, 51 | input: './src/common/themes/index.ts', 52 | output: { 53 | dir: 'dist/themes', 54 | exports: 'default', 55 | format: 'cjs', 56 | preserveModules: true, 57 | preserveModulesRoot: 'src/common/themes' 58 | }, 59 | plugins: [ 60 | ...baseBundle.plugins, 61 | copy({ 62 | targets: [ 63 | { src: './src/assets/fonts/dist/*', dest: './dist/fonts' }, 64 | { src: './src/assets/images/*', dest: './dist/images' } 65 | ] 66 | }), 67 | typescript({ 68 | tsconfig: './tsconfig.build.themes.json', 69 | declaration: true, 70 | declarationDir: 'dist/themes' 71 | }) 72 | ] 73 | } 74 | ]; 75 | -------------------------------------------------------------------------------- /src/Anchor/Anchor.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { render } from '@testing-library/react'; 4 | 5 | import { Anchor } from './Anchor'; 6 | 7 | const defaultProps = { 8 | children: '', 9 | href: '' 10 | }; 11 | 12 | describe('', () => { 13 | it('should render href', () => { 14 | const { container } = render( 15 | 16 | ); 17 | const anchorEl = container.firstChild; 18 | 19 | expect(anchorEl).toHaveAttribute('href', 'http://yoda.com'); 20 | }); 21 | 22 | it('should render children', () => { 23 | const { container } = render( 24 | You shall pass 25 | ); 26 | const anchorEl = container.firstChild; 27 | 28 | expect(anchorEl).toHaveTextContent('You shall pass'); 29 | }); 30 | 31 | it('should render custom style', () => { 32 | const { container } = render( 33 | 34 | ); 35 | const anchorEl = container.firstChild; 36 | 37 | expect(anchorEl).toHaveAttribute('style', 'color: papayawhip;'); 38 | }); 39 | 40 | it('should render custom props', () => { 41 | const customProps = { target: '_blank' }; 42 | const { container } = render(); 43 | const anchorEl = container.firstChild; 44 | 45 | expect(anchorEl).toHaveAttribute('target', '_blank'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/Anchor/Anchor.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { Anchor } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.material}; 9 | `; 10 | 11 | export default { 12 | title: 'Typography/Anchor', 13 | component: Anchor, 14 | decorators: [story => {story()}] 15 | } as ComponentMeta; 16 | 17 | export function Default() { 18 | return ( 19 |

20 | Everybody likes{' '} 21 | 22 | https://expensive.toys 23 | 24 |

25 | ); 26 | } 27 | 28 | Default.story = { 29 | name: 'default' 30 | }; 31 | -------------------------------------------------------------------------------- /src/Anchor/Anchor.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type AnchorProps = { 7 | children: React.ReactNode; 8 | underline?: boolean; 9 | } & React.AnchorHTMLAttributes & 10 | CommonStyledProps; 11 | 12 | const StyledAnchor = styled.a<{ underline: boolean }>` 13 | color: ${({ theme }) => theme.anchor}; 14 | font-size: inherit; 15 | text-decoration: ${({ underline }) => (underline ? 'underline' : 'none')}; 16 | &:visited { 17 | color: ${({ theme }) => theme.anchorVisited}; 18 | } 19 | `; 20 | 21 | const Anchor = forwardRef( 22 | ({ children, underline = true, ...otherProps }: AnchorProps, ref) => { 23 | return ( 24 | 25 | {children} 26 | 27 | ); 28 | } 29 | ); 30 | 31 | Anchor.displayName = 'Anchor'; 32 | 33 | export { Anchor, AnchorProps }; 34 | -------------------------------------------------------------------------------- /src/AppBar/AppBar.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import React from 'react'; 3 | 4 | import { AppBar } from './AppBar'; 5 | 6 | const defaultProps = { children: '' }; 7 | 8 | describe('', () => { 9 | it('should render header', () => { 10 | const { container } = render(); 11 | const headerEl = container.firstElementChild; 12 | 13 | expect(headerEl && headerEl.tagName).toBe('HEADER'); 14 | }); 15 | 16 | it('should render children', () => { 17 | const { container } = render(A nice app bar); 18 | const headerEl = container.firstElementChild; 19 | 20 | expect(headerEl).toHaveTextContent('A nice app bar'); 21 | }); 22 | 23 | it('should render fixed prop properly', () => { 24 | const { container, rerender } = render(); 25 | const headerEl = container.firstElementChild; 26 | 27 | expect(headerEl).toHaveStyleRule('position', 'fixed'); 28 | 29 | rerender(); 30 | 31 | expect(headerEl).toHaveStyleRule('position', 'absolute'); 32 | }); 33 | 34 | it('should render position prop properly', () => { 35 | const { container } = render( 36 | 37 | ); 38 | const headerEl = container.firstElementChild; 39 | 40 | expect(headerEl).toHaveStyleRule('position', 'sticky'); 41 | }); 42 | 43 | it('should custom style', () => { 44 | const { container } = render( 45 | 46 | ); 47 | const headerEl = container.firstElementChild; 48 | 49 | expect(headerEl).toHaveAttribute('style', 'background-color: papayawhip;'); 50 | }); 51 | 52 | it('should render custom props', () => { 53 | const customProps = { title: 'cool-header' }; 54 | const { container } = render(); 55 | const headerEl = container.firstElementChild; 56 | 57 | expect(headerEl).toHaveAttribute('title', 'cool-header'); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /src/AppBar/AppBar.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled, { CSSProperties } from 'styled-components'; 3 | 4 | import { createBorderStyles, createBoxStyles } from '../common'; 5 | import { CommonStyledProps } from '../types'; 6 | 7 | type AppBarProps = { 8 | children: React.ReactNode; 9 | /** @deprecated Use `position` instead */ 10 | fixed?: boolean; 11 | position?: CSSProperties['position']; 12 | } & React.HTMLAttributes & 13 | CommonStyledProps; 14 | 15 | const StyledAppBar = styled.header` 16 | ${createBorderStyles()}; 17 | ${createBoxStyles()}; 18 | 19 | position: ${props => props.position ?? (props.fixed ? 'fixed' : 'absolute')}; 20 | top: 0; 21 | right: 0; 22 | left: auto; 23 | display: flex; 24 | flex-direction: column; 25 | width: 100%; 26 | `; 27 | 28 | const AppBar = forwardRef( 29 | ({ children, fixed = true, position = 'fixed', ...otherProps }, ref) => { 30 | return ( 31 | 37 | {children} 38 | 39 | ); 40 | } 41 | ); 42 | 43 | AppBar.displayName = 'AppBar'; 44 | 45 | export { AppBar, AppBarProps }; 46 | -------------------------------------------------------------------------------- /src/Avatar/Avatar.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { Avatar } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.material}; 9 | & > div > * { 10 | margin-right: 1rem; 11 | } 12 | `; 13 | 14 | export default { 15 | title: 'Other/Avatar', 16 | component: Avatar, 17 | decorators: [story => {story()}] 18 | } as ComponentMeta; 19 | 20 | export function Default() { 21 | return ( 22 |
23 | 24 | 25 | 26 | AK 27 | 28 | 29 | 30 | 🚀 31 | 32 | 33 |
34 | ); 35 | } 36 | 37 | Default.story = { 38 | name: 'default' 39 | }; 40 | -------------------------------------------------------------------------------- /src/Avatar/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { getSize } from '../common/utils'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type AvatarProps = { 7 | alt?: string; 8 | children?: React.ReactNode; 9 | noBorder?: boolean; 10 | size?: string | number; 11 | square?: boolean; 12 | src?: string; 13 | } & React.HTMLAttributes & 14 | CommonStyledProps; 15 | 16 | const StyledAvatar = styled.div< 17 | Pick & { size?: string } 18 | >` 19 | display: inline-block; 20 | box-sizing: border-box; 21 | object-fit: contain; 22 | ${({ size }) => 23 | ` 24 | height: ${size}; 25 | width: ${size}; 26 | `} 27 | border-radius: ${({ square }) => (square ? 0 : '50%')}; 28 | overflow: hidden; 29 | ${({ noBorder, theme }) => 30 | !noBorder && 31 | ` 32 | border-top: 2px solid ${theme.borderDark}; 33 | border-left: 2px solid ${theme.borderDark}; 34 | border-bottom: 2px solid ${theme.borderLightest}; 35 | border-right: 2px solid ${theme.borderLightest}; 36 | background: ${theme.material}; 37 | `} 38 | ${({ src }) => 39 | !src && 40 | ` 41 | display: flex; 42 | align-items: center; 43 | justify-content: space-around; 44 | font-weight: bold; 45 | font-size: 1rem; 46 | `} 47 | `; 48 | 49 | const StyledAvatarImg = styled.img` 50 | display: block; 51 | object-fit: contain; 52 | width: 100%; 53 | height: 100%; 54 | `; 55 | 56 | const Avatar = forwardRef( 57 | ( 58 | { 59 | alt = '', 60 | children, 61 | noBorder = false, 62 | size = 35, 63 | square = false, 64 | src, 65 | ...otherProps 66 | }, 67 | ref 68 | ) => { 69 | return ( 70 | 78 | {src ? : children} 79 | 80 | ); 81 | } 82 | ); 83 | 84 | Avatar.displayName = 'Avatar'; 85 | 86 | export { Avatar, AvatarProps }; 87 | -------------------------------------------------------------------------------- /src/ColorInput/ColorInput.spec.tsx: -------------------------------------------------------------------------------- 1 | import { fireEvent } from '@testing-library/react'; 2 | import React from 'react'; 3 | import { renderWithTheme } from '../../test/utils'; 4 | import { ColorInput } from './ColorInput'; 5 | 6 | function rgb2hex(str: string) { 7 | const rgb = str.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); 8 | function hex(x: string) { 9 | return `0${parseInt(x, 10).toString(16)}`.slice(-2); 10 | } 11 | return rgb ? `#${hex(rgb[1])}${hex(rgb[2])}${hex(rgb[3])}` : ''; 12 | } 13 | 14 | describe('', () => { 15 | it('should call handlers', () => { 16 | const color = '#f0f0dd'; 17 | const onChange = jest.fn(); 18 | const { container } = renderWithTheme(); 19 | const input = container.querySelector(`[type="color"]`) as HTMLInputElement; 20 | fireEvent.change(input, { target: { value: color } }); 21 | expect(onChange).toBeCalledTimes(1); 22 | }); 23 | 24 | it('should properly pass value to input element', () => { 25 | const color = '#f0f0dd'; 26 | const { container } = renderWithTheme(); 27 | const input = container.querySelector(`[type="color"]`) as HTMLInputElement; 28 | 29 | expect(input.value).toBe(color); 30 | }); 31 | it('should display current color', () => { 32 | const color = '#f0f0dd'; 33 | const { getByRole } = renderWithTheme(); 34 | const colorPreview = getByRole('presentation'); 35 | const displayedColor = window.getComputedStyle( 36 | colorPreview, 37 | null 38 | ).background; 39 | 40 | const displayedColorHex = rgb2hex(displayedColor); 41 | expect(displayedColorHex).toBe(color); 42 | }); 43 | 44 | describe('prop: disabled', () => { 45 | it('should render disabled input', () => { 46 | const { container } = renderWithTheme(); 47 | const input = container.querySelector(`[type="color"]`); 48 | 49 | expect(input).toHaveAttribute('disabled'); 50 | }); 51 | 52 | it('should be overridden by props', () => { 53 | const { container, rerender } = renderWithTheme(); 54 | rerender(); 55 | const input = container.querySelector(`[type="color"]`); 56 | 57 | expect(input).not.toHaveAttribute('disabled'); 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /src/ColorInput/ColorInput.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import styled from 'styled-components'; 4 | 5 | import { ColorInput, ScrollView } from 'react95'; 6 | 7 | const Wrapper = styled.div` 8 | background: ${({ theme }) => theme.material}; 9 | padding: 5rem; 10 | & > span { 11 | margin-left: 1rem; 12 | margin-right: 0.5rem; 13 | } 14 | #cutout { 15 | background: ${({ theme }) => theme.canvas}; 16 | display: inline-block; 17 | } 18 | .content { 19 | padding: 1rem; 20 | & > div { 21 | margin: 1rem 0; 22 | } 23 | 24 | & > div > span { 25 | margin-right: 0.5rem; 26 | } 27 | } 28 | `; 29 | 30 | export default { 31 | title: 'Controls/ColorInput', 32 | component: ColorInput, 33 | decorators: [story => {story()}] 34 | } as ComponentMeta; 35 | 36 | export function Default() { 37 | return ( 38 | <> 39 | enabled: 40 | 41 | disabled: 42 | 43 | 44 | ); 45 | } 46 | 47 | Default.story = { 48 | name: 'default' 49 | }; 50 | 51 | export function Flat() { 52 | return ( 53 | 54 |
55 |
56 | enabled: 57 | 58 |
59 |
60 | disabled: 61 | 62 |
63 |
64 |
65 | ); 66 | } 67 | 68 | Flat.story = { 69 | name: 'flat' 70 | }; 71 | -------------------------------------------------------------------------------- /src/Counter/Counter.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { Counter } from './Counter'; 6 | 7 | describe('', () => { 8 | it('should render', () => { 9 | const { container } = renderWithTheme(); 10 | const counter = container.firstElementChild; 11 | 12 | expect(counter).toBeInTheDocument(); 13 | }); 14 | 15 | it('should handle custom style', () => { 16 | const { container } = renderWithTheme( 17 | 18 | ); 19 | const counter = container.firstElementChild; 20 | 21 | expect(counter).toHaveAttribute('style', 'background-color: papayawhip;'); 22 | }); 23 | 24 | it('should handle custom props', () => { 25 | const customProps: React.HTMLAttributes = { 26 | title: 'potatoe' 27 | }; 28 | const { container } = renderWithTheme(); 29 | const counter = container.firstElementChild; 30 | 31 | expect(counter).toHaveAttribute('title', 'potatoe'); 32 | }); 33 | 34 | describe('prop: minLength', () => { 35 | it('renders correct number of digits', () => { 36 | const { container } = renderWithTheme( 37 | 38 | ); 39 | const counter = container.firstElementChild; 40 | 41 | expect(counter && counter.childElementCount).toBe(7); 42 | }); 43 | 44 | it('value length takes priority if bigger than minLength', () => { 45 | const { container } = renderWithTheme( 46 | 47 | ); 48 | const counter = container.firstElementChild; 49 | 50 | expect(counter && counter.childElementCount).toBe(4); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/Counter/Counter.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React, { useState } from 'react'; 3 | import { Button, Counter, Frame } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.desktopBackground}; 9 | .counter-wrapper { 10 | display: flex; 11 | margin-top: 1rem; 12 | } 13 | .counter-wrapper button { 14 | margin-left: 0.5rem; 15 | height: 51px; 16 | } 17 | .wrapper { 18 | padding: 1rem; 19 | } 20 | `; 21 | 22 | export default { 23 | title: 'Other/Counter', 24 | component: Counter, 25 | decorators: [story => {story()}] 26 | } as ComponentMeta; 27 | 28 | export function Default() { 29 | const [count, setCount] = useState(13); 30 | const handleClick = () => setCount(count + 1); 31 | return ( 32 | 33 | 34 | 35 |
36 | 37 | 38 |
39 | 40 | ); 41 | } 42 | 43 | Default.story = { 44 | name: 'default' 45 | }; 46 | -------------------------------------------------------------------------------- /src/Counter/Counter.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef, useMemo } from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import { createBorderStyles } from '../common'; 5 | import { CommonStyledProps, Sizes } from '../types'; 6 | import { Digit } from './Digit'; 7 | 8 | type CounterProps = { 9 | minLength?: number; 10 | size?: Sizes | 'xl'; 11 | value?: number; 12 | } & React.HTMLAttributes & 13 | CommonStyledProps; 14 | 15 | const CounterWrapper = styled.div` 16 | ${createBorderStyles({ style: 'status' })} 17 | display: inline-flex; 18 | background: #000000; 19 | `; 20 | 21 | const pixelSizes = { 22 | sm: 1, 23 | md: 2, 24 | lg: 3, 25 | xl: 4 26 | }; 27 | 28 | const Counter = forwardRef( 29 | ({ value = 0, minLength = 3, size = 'md', ...otherProps }, ref) => { 30 | const digits = useMemo( 31 | () => value.toString().padStart(minLength, '0').split(''), 32 | [minLength, value] 33 | ); 34 | return ( 35 | 36 | {digits.map((digit, i) => ( 37 | 38 | ))} 39 | 40 | ); 41 | } 42 | ); 43 | 44 | Counter.displayName = 'Counter'; 45 | 46 | export { Counter, CounterProps }; 47 | -------------------------------------------------------------------------------- /src/DatePicker/DatePicker.stories.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase, react/jsx-pascal-case */ 2 | import { ComponentMeta } from '@storybook/react'; 3 | import React from 'react'; 4 | import { DatePicker__UNSTABLE } from 'react95'; 5 | import styled from 'styled-components'; 6 | 7 | const Wrapper = styled.div` 8 | padding: 5rem; 9 | background: ${({ theme }) => theme.desktopBackground}; 10 | `; 11 | 12 | export default { 13 | title: 'DatePicker__UNSTABLE', 14 | component: DatePicker__UNSTABLE, 15 | decorators: [story => {story()}] 16 | } as ComponentMeta; 17 | 18 | export function Default() { 19 | return console.log(date)} />; 20 | } 21 | 22 | Default.story = { 23 | name: 'default' 24 | }; 25 | -------------------------------------------------------------------------------- /src/Frame/Frame.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import React from 'react'; 3 | 4 | import { Frame } from './Frame'; 5 | 6 | describe('', () => { 7 | it('should render frame', () => { 8 | const { container } = render(); 9 | const frame = container.firstElementChild; 10 | 11 | expect(frame).toBeInTheDocument(); 12 | }); 13 | 14 | it('should render custom styles', () => { 15 | const { container } = render( 16 | 17 | ); 18 | const frame = container.firstElementChild; 19 | 20 | expect(frame).toHaveAttribute('style', 'background-color: papayawhip;'); 21 | }); 22 | 23 | it('should render children', async () => { 24 | const { findByText } = render( 25 | 26 | Cool frame 27 | 28 | ); 29 | const content = await findByText(/cool frame/i); 30 | 31 | expect(content).toBeInTheDocument(); 32 | }); 33 | 34 | it('should render custom props', () => { 35 | const customProps = { title: 'frame' }; 36 | const { container } = render(); 37 | const frame = container.firstElementChild; 38 | 39 | expect(frame).toHaveAttribute('title', 'frame'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/Frame/Frame.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { Frame } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.material}; 9 | #default-buttons button { 10 | margin-bottom: 1rem; 11 | margin-right: 1rem; 12 | } 13 | 14 | #cutout { 15 | background: ${({ theme }) => theme.canvas}; 16 | padding: 1rem; 17 | width: 300px; 18 | } 19 | `; 20 | 21 | export default { 22 | title: 'Layout/Frame', 23 | component: Frame, 24 | decorators: [story => {story()}] 25 | } as ComponentMeta; 26 | 27 | export function Default() { 28 | return ( 29 | 34 |

35 | This is a frame of the 'window' variant, the default. Notice 36 | the subtle difference in borders. The lightest border is not on the edge 37 | of this frame. 38 |

39 | 40 | This frame of the 'button' variant on the other hand has the 41 | lightest border on the edge. Use this frame inside 'window' 42 | frames. 43 |
44 | 53 | A field frame variant is used to display content. 54 | 55 | 56 | 60 | The 'status' variant of a frame is often used as a status bar 61 | at the end of the window. 62 | 63 | 64 | ); 65 | } 66 | 67 | Default.story = { 68 | name: 'default' 69 | }; 70 | -------------------------------------------------------------------------------- /src/Frame/Frame.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | import { createBorderStyles, createBoxStyles } from '../common'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type FrameProps = { 7 | children?: React.ReactNode; 8 | shadow?: boolean; 9 | } & ( 10 | | { 11 | variant?: 'window' | 'button' | 'field' | 'status'; 12 | } 13 | | { 14 | /** @deprecated Use 'window', 'button' or 'status' */ 15 | variant?: 'outside' | 'inside' | 'well'; 16 | } 17 | ) & 18 | React.HTMLAttributes & 19 | CommonStyledProps; 20 | 21 | const createFrameStyles = (variant: FrameProps['variant']) => { 22 | switch (variant) { 23 | case 'status': 24 | case 'well': 25 | return css` 26 | ${createBorderStyles({ style: 'status' })} 27 | `; 28 | case 'window': 29 | case 'outside': 30 | return css` 31 | ${createBorderStyles({ style: 'window' })} 32 | `; 33 | case 'field': 34 | return css` 35 | ${createBorderStyles({ style: 'field' })} 36 | `; 37 | default: 38 | return css` 39 | ${createBorderStyles()} 40 | `; 41 | } 42 | }; 43 | 44 | const StyledFrame = styled.div>>` 45 | position: relative; 46 | font-size: 1rem; 47 | ${({ variant }) => createFrameStyles(variant)} 48 | ${({ variant }) => 49 | createBoxStyles( 50 | variant === 'field' 51 | ? { background: 'canvas', color: 'canvasText' } 52 | : undefined 53 | )} 54 | `; 55 | 56 | const Frame = forwardRef( 57 | ({ children, shadow = false, variant = 'window', ...otherProps }, ref) => { 58 | return ( 59 | 60 | {children} 61 | 62 | ); 63 | } 64 | ); 65 | 66 | Frame.displayName = 'Frame'; 67 | 68 | export { Frame, FrameProps }; 69 | -------------------------------------------------------------------------------- /src/GroupBox/GroupBox.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme, theme } from '../../test/utils'; 4 | 5 | import { GroupBox } from './GroupBox'; 6 | 7 | describe('', () => { 8 | it('renders GroupBox', () => { 9 | const { container } = renderWithTheme(); 10 | const groupBox = container.firstChild as HTMLFieldSetElement; 11 | 12 | expect(groupBox).toBeInTheDocument(); 13 | }); 14 | it('renders children', () => { 15 | const textContent = 'Hi there!'; 16 | const { getByText } = renderWithTheme( 17 | 18 | {textContent} 19 | 20 | ); 21 | expect(getByText(textContent)).toBeInTheDocument(); 22 | }); 23 | 24 | describe('prop: label', () => { 25 | it('renders Label', () => { 26 | const labelText = 'Name:'; 27 | const { container } = renderWithTheme(); 28 | const groupBox = container.firstChild as HTMLFieldSetElement; 29 | const legend = groupBox.querySelector('legend'); 30 | expect(legend?.textContent).toBe(labelText); 31 | }); 32 | it('when not provided, element is not rendered', () => { 33 | const { container } = renderWithTheme(); 34 | const groupBox = container.firstChild as HTMLFieldSetElement; 35 | const legend = groupBox.querySelector('legend'); 36 | expect(legend).not.toBeInTheDocument(); 37 | }); 38 | }); 39 | describe('prop: disabled', () => { 40 | it('renders with disabled text content', () => { 41 | const { container } = renderWithTheme(); 42 | const groupBox = container.firstChild as HTMLFieldSetElement; 43 | 44 | expect(groupBox).toHaveAttribute('aria-disabled', 'true'); 45 | 46 | expect(groupBox).toHaveStyleRule('color', theme.materialTextDisabled); 47 | expect(groupBox).toHaveStyleRule( 48 | 'text-shadow', 49 | `1px 1px ${theme.materialTextDisabledShadow}` 50 | ); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/GroupBox/GroupBox.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | import { createDisabledTextStyles } from '../common'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type GroupBoxProps = { 7 | label?: React.ReactNode; 8 | children?: React.ReactNode; 9 | disabled?: boolean; 10 | variant?: 'default' | 'flat'; 11 | } & React.FieldsetHTMLAttributes & 12 | CommonStyledProps; 13 | 14 | const StyledFieldset = styled.fieldset< 15 | Pick & { $disabled: boolean } 16 | >` 17 | position: relative; 18 | border: 2px solid 19 | ${({ theme, variant }) => 20 | variant === 'flat' ? theme.flatDark : theme.borderLightest}; 21 | padding: 16px; 22 | margin-top: 8px; 23 | font-size: 1rem; 24 | color: ${({ theme }) => theme.materialText}; 25 | ${({ variant }) => 26 | variant !== 'flat' && 27 | css` 28 | box-shadow: -1px -1px 0 1px ${({ theme }) => theme.borderDark}, 29 | inset -1px -1px 0 1px ${({ theme }) => theme.borderDark}; 30 | `} 31 | ${props => props.$disabled && createDisabledTextStyles()} 32 | `; 33 | 34 | const StyledLegend = styled.legend>` 35 | display: flex; 36 | position: absolute; 37 | top: 0; 38 | left: 8px; 39 | transform: translateY(calc(-50% - 2px)); 40 | padding: 0 8px; 41 | 42 | font-size: 1rem; 43 | background: ${({ theme, variant }) => 44 | variant === 'flat' ? theme.canvas : theme.material}; 45 | `; 46 | 47 | const GroupBox = forwardRef( 48 | ( 49 | { label, disabled = false, variant = 'default', children, ...otherProps }, 50 | ref 51 | ) => { 52 | return ( 53 | 60 | {label && {label}} 61 | {children} 62 | 63 | ); 64 | } 65 | ); 66 | 67 | GroupBox.displayName = 'GroupBox'; 68 | 69 | export { GroupBox, GroupBoxProps }; 70 | -------------------------------------------------------------------------------- /src/Handle/Handle.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { Handle } from './Handle'; 6 | 7 | describe('', () => { 8 | it('should render bar', () => { 9 | const { container } = renderWithTheme(); 10 | const barEl = container.firstChild; 11 | 12 | expect(barEl).toBeInTheDocument(); 13 | }); 14 | 15 | it('should handle custom style', () => { 16 | const { container } = renderWithTheme( 17 | 18 | ); 19 | const barEl = container.firstChild; 20 | 21 | expect(barEl).toHaveAttribute('style', 'background-color: papayawhip;'); 22 | }); 23 | 24 | it('should handle custom props', () => { 25 | const customProps = { title: 'potatoe' }; 26 | const { container } = renderWithTheme(); 27 | const barEl = container.firstChild; 28 | 29 | expect(barEl).toHaveAttribute('title', 'potatoe'); 30 | }); 31 | 32 | describe('prop: size', () => { 33 | it('should set proper size', () => { 34 | const { container } = renderWithTheme(); 35 | const barEl = container.firstChild; 36 | 37 | expect(barEl).toHaveStyleRule('height', '85%'); 38 | }); 39 | 40 | it('when passed a number, sets size in px', () => { 41 | const { container } = renderWithTheme(); 42 | const barEl = container.firstChild; 43 | 44 | expect(barEl).toHaveStyleRule('height', '25px'); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/Handle/Handle.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { AppBar, Button, Handle, Toolbar } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.desktopBackground}; 9 | `; 10 | 11 | export default { 12 | title: 'Controls/Handle', 13 | component: Handle, 14 | decorators: [story => {story()}] 15 | } as ComponentMeta; 16 | 17 | export function Default() { 18 | return ( 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | Default.story = { 33 | name: 'default' 34 | }; 35 | -------------------------------------------------------------------------------- /src/Handle/Handle.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { CommonStyledProps } from '../types'; 4 | import { getSize } from '../common/utils'; 5 | 6 | type HandleProps = { 7 | size?: string | number; 8 | } & React.HTMLAttributes & 9 | CommonStyledProps; 10 | 11 | // TODO: add horizontal variant 12 | // TODO: allow user to specify number of bars (like 3 horizontal bars for drag handle) 13 | const Handle = styled.div` 14 | ${({ theme, size = '100%' }) => ` 15 | display: inline-block; 16 | box-sizing: border-box; 17 | height: ${getSize(size)}; 18 | width: 5px; 19 | border-top: 2px solid ${theme.borderLightest}; 20 | border-left: 2px solid ${theme.borderLightest}; 21 | border-bottom: 2px solid ${theme.borderDark}; 22 | border-right: 2px solid ${theme.borderDark}; 23 | background: ${theme.material}; 24 | `} 25 | `; 26 | 27 | Handle.displayName = 'Handle'; 28 | 29 | export { Handle, HandleProps }; 30 | -------------------------------------------------------------------------------- /src/Hourglass/Hourglass.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import React from 'react'; 3 | 4 | import { Hourglass } from './Hourglass'; 5 | 6 | describe('', () => { 7 | it('should render hourglass', () => { 8 | const { container } = render(); 9 | const hourglass = container.firstElementChild; 10 | 11 | expect(hourglass).toBeInTheDocument(); 12 | }); 13 | 14 | it('should render correct size', () => { 15 | const { container } = render(); 16 | const hourglass = container.firstElementChild; 17 | 18 | const computedStyles = hourglass 19 | ? window.getComputedStyle(hourglass) 20 | : null; 21 | expect(computedStyles?.width).toBe('66px'); 22 | expect(computedStyles?.height).toBe('66px'); 23 | }); 24 | 25 | it('should handle custom props', () => { 26 | const customProps: React.HTMLAttributes = { 27 | title: 'hourglass' 28 | }; 29 | const { container } = render(); 30 | const hourglass = container.firstElementChild; 31 | 32 | expect(hourglass).toHaveAttribute('title', 'hourglass'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/Hourglass/Hourglass.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { Hourglass } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.desktopBackground}; 9 | `; 10 | 11 | export default { 12 | title: 'Other/Hourglass', 13 | component: Hourglass, 14 | decorators: [story => {story()}] 15 | } as ComponentMeta; 16 | 17 | export function Default() { 18 | return ; 19 | } 20 | 21 | Default.story = { 22 | name: 'default' 23 | }; 24 | -------------------------------------------------------------------------------- /src/Hourglass/Hourglass.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { getSize } from '../common/utils'; 4 | import { CommonStyledProps } from '../types'; 5 | import base64hourglass from './base64hourglass'; 6 | 7 | type HourglassProps = { 8 | size?: string | number; 9 | } & React.HTMLAttributes & 10 | CommonStyledProps; 11 | 12 | const StyledContainer = styled.div>>` 13 | display: inline-block; 14 | height: ${({ size }) => getSize(size)}; 15 | width: ${({ size }) => getSize(size)}; 16 | `; 17 | 18 | const StyledHourglass = styled.span` 19 | display: block; 20 | background: ${base64hourglass}; 21 | background-size: cover; 22 | width: 100%; 23 | height: 100%; 24 | `; 25 | 26 | const Hourglass = forwardRef( 27 | ({ size = 30, ...otherProps }, ref) => { 28 | return ( 29 | 30 | 31 | 32 | ); 33 | } 34 | ); 35 | 36 | Hourglass.displayName = 'Hourglass'; 37 | 38 | export { Hourglass, HourglassProps }; 39 | -------------------------------------------------------------------------------- /src/MenuList/MenuList.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { MenuList } from './MenuList'; 6 | 7 | describe('', () => { 8 | it('renders MenuList', () => { 9 | const { container } = renderWithTheme(); 10 | const menuList = container.firstElementChild; 11 | 12 | expect(menuList).toBeInTheDocument(); 13 | }); 14 | it('is an ul', () => { 15 | const { container } = renderWithTheme(); 16 | const menuList = container.firstElementChild; 17 | 18 | expect(menuList?.tagName).toBe('UL'); 19 | }); 20 | it('renders children', () => { 21 | const textContent = 'Hi there!'; 22 | const { getByText } = renderWithTheme( 23 | 24 | {textContent} 25 | 26 | ); 27 | expect(getByText(textContent)).toBeInTheDocument(); 28 | }); 29 | 30 | describe('prop: inline', () => { 31 | it('renders inline', () => { 32 | const { container } = renderWithTheme(); 33 | const menuList = container.firstElementChild; 34 | 35 | expect(menuList).toHaveStyleRule('display', 'inline-flex'); 36 | expect(menuList).toHaveStyleRule('align-items', 'center'); 37 | }); 38 | }); 39 | describe('prop: fullWidth', () => { 40 | it('has 100% width', () => { 41 | const { container } = renderWithTheme(); 42 | const menuList = container.firstElementChild; 43 | 44 | expect(menuList).toHaveStyleRule('width', '100%'); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/MenuList/MenuList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import styled from 'styled-components'; 4 | import { createBorderStyles, createBoxStyles } from '../common'; 5 | import { CommonStyledProps } from '../types'; 6 | 7 | type MenuListProps = React.HTMLAttributes & { 8 | fullWidth?: boolean; 9 | shadow?: boolean; 10 | inline?: boolean; 11 | } & CommonStyledProps; 12 | 13 | // TODO keyboard controls 14 | const MenuList = styled.ul.attrs(() => ({ 15 | role: 'menu' 16 | }))` 17 | box-sizing: border-box; 18 | width: ${props => (props.fullWidth ? '100%' : 'auto')}; 19 | padding: 4px; 20 | ${createBorderStyles({ style: 'window' })} 21 | ${createBoxStyles()} 22 | ${props => 23 | props.inline && 24 | ` 25 | display: inline-flex; 26 | align-items: center; 27 | `} 28 | list-style: none; 29 | position: relative; 30 | `; 31 | 32 | MenuList.displayName = 'MenuList'; 33 | 34 | export * from './MenuListItem'; 35 | 36 | export { MenuList, MenuListProps }; 37 | -------------------------------------------------------------------------------- /src/Monitor/Monitor.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { Monitor } from './Monitor'; 6 | 7 | describe('', () => { 8 | it('should render', () => { 9 | const { container } = renderWithTheme(); 10 | const monitorElement = container.firstElementChild; 11 | 12 | expect(monitorElement).toBeInTheDocument(); 13 | }); 14 | 15 | it('should handle custom props', () => { 16 | const customProps: React.HTMLAttributes = { 17 | title: 'potatoe' 18 | }; 19 | const { container } = renderWithTheme(); 20 | const monitorElement = container.firstElementChild; 21 | 22 | expect(monitorElement).toHaveAttribute('title', 'potatoe'); 23 | }); 24 | 25 | describe('prop: backgroundStyles', () => { 26 | it('should forward styles to background element', () => { 27 | const { getByTestId } = renderWithTheme( 28 | 29 | ); 30 | const backgroundElement = getByTestId('background'); 31 | 32 | expect(backgroundElement).toHaveAttribute( 33 | 'style', 34 | 'background-color: papayawhip;' 35 | ); 36 | }); 37 | }); 38 | 39 | describe('prop: children', () => { 40 | it('children should be rendered in background element', () => { 41 | const { getByTestId } = renderWithTheme(Hi!); 42 | const backgroundElement = getByTestId('background'); 43 | 44 | expect(backgroundElement.innerHTML).toBe('Hi!'); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/Monitor/Monitor.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { Monitor } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.desktopBackground}; 9 | `; 10 | 11 | export default { 12 | title: 'Other/Monitor', 13 | component: Monitor, 14 | decorators: [story => {story()}] 15 | } as ComponentMeta; 16 | 17 | export function Default() { 18 | return ; 19 | } 20 | 21 | Default.story = { 22 | name: 'default' 23 | }; 24 | -------------------------------------------------------------------------------- /src/NumberInput/NumberInput.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { ScrollView, NumberInput } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | background: ${({ theme }) => theme.material}; 8 | padding: 5rem; 9 | & > * { 10 | margin-bottom: 1rem; 11 | } 12 | 13 | #cutout { 14 | background: ${({ theme }) => theme.canvas}; 15 | padding: 2rem; 16 | width: 300px; 17 | & > div > * { 18 | margin-bottom: 1rem; 19 | } 20 | } 21 | `; 22 | 23 | export default { 24 | title: 'Controls/NumberInput', 25 | component: NumberInput, 26 | decorators: [story => {story()}] 27 | } as ComponentMeta; 28 | 29 | export function Default() { 30 | return ( 31 | <> 32 | 33 |
34 | 35 |
36 | 37 | 38 | ); 39 | } 40 | 41 | Default.story = { 42 | name: 'default' 43 | }; 44 | 45 | export function Flat() { 46 | return ( 47 | 48 |

49 | When you want to use NumberInput on a light background (like scrollable 50 | content), just use the flat variant: 51 |

52 | 59 |
60 | 61 |
62 | 63 |
64 | ); 65 | } 66 | 67 | Flat.story = { 68 | name: 'flat' 69 | }; 70 | -------------------------------------------------------------------------------- /src/ScrollView/ScrollView.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import React from 'react'; 3 | 4 | import { ScrollView } from './ScrollView'; 5 | 6 | describe('', () => { 7 | it('should render scrollview', () => { 8 | const { container } = render(); 9 | const scrollView = container.firstElementChild; 10 | 11 | expect(scrollView).toBeInTheDocument(); 12 | }); 13 | 14 | it('should render custom styles', () => { 15 | const { container } = render( 16 | 17 | ); 18 | const scrollView = container.firstElementChild; 19 | 20 | expect(scrollView).toHaveAttribute( 21 | 'style', 22 | 'background-color: papayawhip;' 23 | ); 24 | }); 25 | 26 | it('should render children', async () => { 27 | const { findByText } = render( 28 | 29 | Cool ScrollView 30 | 31 | ); 32 | const content = await findByText(/cool scrollview/i); 33 | 34 | expect(content).toBeInTheDocument(); 35 | }); 36 | 37 | it('should render custom props', () => { 38 | const customProps = { title: 'scrollview' }; 39 | const { container } = render(); 40 | const scrollView = container.firstElementChild; 41 | 42 | expect(scrollView).toHaveAttribute('title', 'scrollview'); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/ScrollView/ScrollView.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { ScrollView, Window, WindowContent } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.desktopBackground}; 9 | `; 10 | 11 | export default { 12 | title: 'Layout/ScrollView', 13 | component: ScrollView, 14 | decorators: [story => {story()}] 15 | } as ComponentMeta; 16 | 17 | export function Default() { 18 | return ( 19 | 20 | 21 | 22 |
23 |

24 | React95 is the best UI library ever created 25 |

26 |

React95 is the best UI library ever created

27 |

React95 is the best UI library ever created

28 |

React95 is the best UI library ever created

29 |

React95 is the best UI library ever created

30 |

React95 is the best UI library ever created

31 |

React95 is the best UI library ever created

32 |

React95 is the best UI library ever created

33 |

React95 is the best UI library ever created

34 |
35 |
36 |
37 |
38 | ); 39 | } 40 | 41 | Default.story = { 42 | name: 'default' 43 | }; 44 | -------------------------------------------------------------------------------- /src/ScrollView/ScrollView.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { insetShadow, createScrollbars } from '../common'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type ScrollViewProps = { 7 | children?: React.ReactNode; 8 | shadow?: boolean; 9 | } & React.HTMLAttributes & 10 | CommonStyledProps; 11 | 12 | export const StyledScrollView = styled.div>` 13 | position: relative; 14 | box-sizing: border-box; 15 | padding: 2px; 16 | font-size: 1rem; 17 | border-style: solid; 18 | border-width: 2px; 19 | border-left-color: ${({ theme }) => theme.borderDark}; 20 | border-top-color: ${({ theme }) => theme.borderDark}; 21 | border-right-color: ${({ theme }) => theme.borderLightest}; 22 | border-bottom-color: ${({ theme }) => theme.borderLightest}; 23 | line-height: 1.5; 24 | &:before { 25 | position: absolute; 26 | left: 0; 27 | top: 0; 28 | content: ''; 29 | width: calc(100% - 4px); 30 | height: calc(100% - 4px); 31 | 32 | border-style: solid; 33 | border-width: 2px; 34 | border-left-color: ${({ theme }) => theme.borderDarkest}; 35 | border-top-color: ${({ theme }) => theme.borderDarkest}; 36 | border-right-color: ${({ theme }) => theme.borderLight}; 37 | border-bottom-color: ${({ theme }) => theme.borderLight}; 38 | 39 | pointer-events: none; 40 | ${props => props.shadow && `box-shadow:${insetShadow};`} 41 | } 42 | `; 43 | 44 | const Content = styled.div` 45 | box-sizing: border-box; 46 | width: 100%; 47 | height: 100%; 48 | padding: 4px; 49 | overflow: auto; 50 | ${createScrollbars()} 51 | `; 52 | 53 | const ScrollView = forwardRef( 54 | ({ children, shadow = true, ...otherProps }, ref) => { 55 | return ( 56 | 57 | {children} 58 | 59 | ); 60 | } 61 | ); 62 | 63 | ScrollView.displayName = 'ScrollView'; 64 | 65 | export { ScrollView, ScrollViewProps }; 66 | -------------------------------------------------------------------------------- /src/Select/Select.types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { HTMLDataAttributes } from '../types'; 3 | 4 | type SelectChangeEventTargetValue = { value: T; name: string | undefined }; 5 | 6 | export type SelectChangeEvent = 7 | | (Omit, 'target'> & { 8 | target: Omit< 9 | React.ChangeEvent['target'], 10 | 'name' | 'value' 11 | > & 12 | SelectChangeEventTargetValue; 13 | }) 14 | | (Omit & { 15 | target: Omit & 16 | SelectChangeEventTargetValue; 17 | }); 18 | 19 | export type SelectOption = { 20 | label?: string; 21 | value: T; 22 | }; 23 | 24 | export type SelectRef = Pick & { 25 | node: HTMLInputElement | null; 26 | }; 27 | 28 | export type SelectVariants = 'default' | 'flat'; 29 | 30 | export type SelectFormatDisplayCallback = ( 31 | option: SelectOption 32 | ) => string; 33 | 34 | export type SelectCommonProps = { 35 | 'aria-label'?: string; 36 | 'aria-labelledby'?: string; 37 | className?: string; 38 | defaultValue?: T; 39 | disabled?: boolean; 40 | name?: string; 41 | onChange?: ( 42 | selectedOption: SelectOption, 43 | options: { 44 | fromEvent: Event | React.SyntheticEvent; 45 | } 46 | ) => void; 47 | options?: (SelectOption | null | undefined)[]; 48 | readOnly?: boolean; 49 | shadow?: boolean; 50 | style?: React.CSSProperties; 51 | value?: T; 52 | variant?: SelectVariants; 53 | width?: React.CSSProperties['width']; 54 | }; 55 | 56 | export type SelectInnerProps = { 57 | formatDisplay?: SelectFormatDisplayCallback; 58 | inputProps?: React.HTMLAttributes & HTMLDataAttributes; 59 | /** @deprecated Use `aria-labelledby` instead */ 60 | labelId?: string; 61 | menuMaxHeight?: string | number; 62 | onClose?: (options: { fromEvent: Event | React.SyntheticEvent }) => void; 63 | onOpen?: (options: { fromEvent: Event | React.SyntheticEvent }) => void; 64 | open?: boolean; 65 | } & Pick< 66 | React.HTMLAttributes, 67 | 'onBlur' | 'onFocus' | 'onKeyDown' | 'onMouseDown' 68 | > & 69 | SelectCommonProps; 70 | -------------------------------------------------------------------------------- /src/Select/useSelectCommon.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react'; 2 | import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled'; 3 | import { 4 | StyledDropdownButton, 5 | StyledDropdownIcon, 6 | StyledFlatSelectWrapper, 7 | StyledSelectWrapper 8 | } from './Select.styles'; 9 | 10 | import { SelectCommonProps, SelectOption } from './Select.types'; 11 | 12 | const emptyArray: [] = []; 13 | 14 | export const useSelectCommon = ({ 15 | className, 16 | defaultValue, 17 | disabled, 18 | native, 19 | onChange, 20 | options: optionsProp = emptyArray, 21 | readOnly, 22 | style, 23 | value: valueProp, 24 | variant, 25 | width 26 | }: { native: boolean } & SelectCommonProps) => { 27 | const options = useMemo( 28 | () => optionsProp.filter(Boolean) as SelectOption[], 29 | [optionsProp] 30 | ); 31 | 32 | const [value, setValue] = useControlledOrUncontrolled({ 33 | defaultValue: defaultValue ?? options?.[0]?.value, 34 | onChange, 35 | readOnly, 36 | value: valueProp 37 | }); 38 | 39 | const isEnabled = !(disabled || readOnly); 40 | 41 | const wrapperProps: React.HTMLAttributes = useMemo( 42 | () => ({ 43 | className, 44 | style: { ...style, width } 45 | }), 46 | [className, style, width] 47 | ); 48 | 49 | const DropdownButton = useMemo( 50 | () => ( 51 | 59 | 60 | 61 | ), 62 | [disabled, native, variant] 63 | ); 64 | 65 | const Wrapper = useMemo( 66 | () => (variant === 'flat' ? StyledFlatSelectWrapper : StyledSelectWrapper), 67 | [variant] 68 | ); 69 | 70 | return useMemo( 71 | () => ({ 72 | isEnabled, 73 | options, 74 | value, 75 | setValue, 76 | wrapperProps, 77 | DropdownButton, 78 | Wrapper 79 | }), 80 | [DropdownButton, Wrapper, isEnabled, options, setValue, value, wrapperProps] 81 | ); 82 | }; 83 | -------------------------------------------------------------------------------- /src/Separator/Separator.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import styled from 'styled-components'; 4 | 5 | import { MenuList, MenuListItem, Separator } from 'react95'; 6 | 7 | const Wrapper = styled.div` 8 | padding: 5rem; 9 | background: ${({ theme }) => theme.desktopBackground}; 10 | `; 11 | 12 | export default { 13 | title: 'Layout/Separator', 14 | component: Separator, 15 | decorators: [story => {story()}] 16 | } as ComponentMeta; 17 | 18 | export function Default() { 19 | return ( 20 | <> 21 | 22 | Item 1 23 | 24 | Item 2 25 | 26 | Item 3 27 | 28 | 29 | Item 1 30 | 31 | Item 2 32 | 33 | Item 3 34 | 35 | 36 | ); 37 | } 38 | 39 | Default.story = { 40 | name: 'default' 41 | }; 42 | -------------------------------------------------------------------------------- /src/Separator/Separator.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { getSize } from '../common/utils'; 3 | import { Orientation } from '../types'; 4 | 5 | type SeparatorProps = { 6 | size?: string | number; 7 | orientation?: Orientation; 8 | }; 9 | 10 | const Separator = styled.div` 11 | ${({ orientation, theme, size = '100%' }) => 12 | orientation === 'vertical' 13 | ? ` 14 | height: ${getSize(size)}; 15 | border-left: 2px solid ${theme.borderDark}; 16 | border-right: 2px solid ${theme.borderLightest}; 17 | margin: 0; 18 | ` 19 | : ` 20 | width: ${getSize(size)}; 21 | border-bottom: 2px solid ${theme.borderLightest}; 22 | border-top: 2px solid ${theme.borderDark}; 23 | margin: 0; 24 | `} 25 | `; 26 | 27 | Separator.displayName = 'Separator'; 28 | 29 | export { Separator, SeparatorProps }; 30 | -------------------------------------------------------------------------------- /src/Table/Table.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { Table } from './Table'; 6 | 7 | describe('', () => { 8 | it('renders Table', () => { 9 | const { container } = renderWithTheme(
); 10 | const table = container.firstElementChild; 11 | 12 | expect(table).toBeInTheDocument(); 13 | }); 14 | it('renders table element', () => { 15 | const { getByRole } = renderWithTheme(
); 16 | 17 | expect(getByRole('table')).toBeInTheDocument(); 18 | }); 19 | it('renders children', () => { 20 | const { getByTestId } = renderWithTheme( 21 |
22 | 23 |
24 | ); 25 | expect(getByTestId('children')).toBeInTheDocument(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/Table/Table.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { StyledScrollView } from '../ScrollView/ScrollView'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type TableProps = { 7 | children?: React.ReactNode; 8 | } & React.TableHTMLAttributes & 9 | CommonStyledProps; 10 | 11 | const StyledTable = styled.table` 12 | display: table; 13 | width: 100%; 14 | border-collapse: collapse; 15 | border-spacing: 0; 16 | font-size: 1rem; 17 | `; 18 | 19 | const Wrapper = styled(StyledScrollView)` 20 | &:before { 21 | box-shadow: none; 22 | } 23 | `; 24 | 25 | const Table = forwardRef( 26 | ({ children, ...otherProps }, ref) => { 27 | return ( 28 | 29 | 30 | {children} 31 | 32 | 33 | ); 34 | } 35 | ); 36 | 37 | Table.displayName = 'Table'; 38 | 39 | export * from './TableBody'; 40 | export * from './TableDataCell'; 41 | export * from './TableHead'; 42 | export * from './TableHeadCell'; 43 | export * from './TableRow'; 44 | 45 | export { Table, TableProps }; 46 | -------------------------------------------------------------------------------- /src/Table/TableBody.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { TableBody } from './TableBody'; 6 | 7 | describe('', () => { 8 | function mountInTable(node: React.ReactNode) { 9 | const { container, getByTestId } = renderWithTheme({node}
); 10 | return { 11 | tbody: container.querySelector('table')?.firstElementChild, 12 | getByTestId 13 | }; 14 | } 15 | 16 | it('renders TableBody', () => { 17 | const { tbody } = mountInTable(); 18 | 19 | expect(tbody).toBeInTheDocument(); 20 | expect(tbody?.tagName).toBe('TBODY'); 21 | }); 22 | 23 | it('renders children', () => { 24 | const children = ; 25 | const { getByTestId } = mountInTable({children}); 26 | expect(getByTestId('tr')).toBeInTheDocument(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/Table/TableBody.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { insetShadow } from '../common'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type TableBodyProps = { 7 | children?: React.ReactNode; 8 | } & React.HTMLAttributes & 9 | CommonStyledProps; 10 | 11 | const StyledTableBody = styled.tbody` 12 | background: ${({ theme }) => theme.canvas}; 13 | display: table-row-group; 14 | box-shadow: ${insetShadow}; 15 | overflow-y: auto; 16 | `; 17 | 18 | const TableBody = forwardRef( 19 | function TableBody({ children, ...otherProps }, ref) { 20 | return ( 21 | 22 | {children} 23 | 24 | ); 25 | } 26 | ); 27 | 28 | TableBody.displayName = 'TableBody'; 29 | 30 | export { TableBody, TableBodyProps }; 31 | -------------------------------------------------------------------------------- /src/Table/TableDataCell.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { TableDataCell } from './TableDataCell'; 6 | 7 | describe('', () => { 8 | function mountInTable(node: React.ReactNode) { 9 | const { container, getByText } = renderWithTheme( 10 | 11 | 12 | {node} 13 | 14 |
15 | ); 16 | return { 17 | td: container.querySelector('tr')?.firstElementChild, 18 | getByText 19 | }; 20 | } 21 | 22 | it('renders TableDataCell', () => { 23 | const { td } = mountInTable(); 24 | expect(td?.tagName).toBe('TD'); 25 | }); 26 | 27 | it('renders children', () => { 28 | const { getByText } = mountInTable(children); 29 | expect(getByText('children')).toBeInTheDocument(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/Table/TableDataCell.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { CommonStyledProps } from '../types'; 4 | 5 | type TableDataCellProps = { 6 | children?: React.ReactNode; 7 | } & React.HTMLAttributes & 8 | CommonStyledProps; 9 | 10 | const StyledTd = styled.td` 11 | padding: 0 8px; 12 | `; 13 | 14 | const TableDataCell = forwardRef( 15 | function TableDataCell({ children, ...otherProps }, ref) { 16 | return ( 17 | 18 | {children} 19 | 20 | ); 21 | } 22 | ); 23 | 24 | TableDataCell.displayName = 'TableDataCell'; 25 | 26 | export { TableDataCell, TableDataCellProps }; 27 | -------------------------------------------------------------------------------- /src/Table/TableHead.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { TableHead } from './TableHead'; 6 | 7 | describe('', () => { 8 | function mountInTable(node: React.ReactNode) { 9 | const { container, getByTestId } = renderWithTheme({node}
); 10 | return { 11 | tbody: container.querySelector('table')?.firstElementChild, 12 | getByTestId 13 | }; 14 | } 15 | 16 | it('renders TableHead', () => { 17 | const { tbody } = mountInTable(); 18 | 19 | expect(tbody).toBeInTheDocument(); 20 | expect(tbody?.tagName).toBe('THEAD'); 21 | }); 22 | 23 | it('renders children', () => { 24 | const children = ; 25 | const { getByTestId } = mountInTable({children}); 26 | expect(getByTestId('tr')).toBeInTheDocument(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/Table/TableHead.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { CommonStyledProps } from '../types'; 4 | 5 | type TableHeadProps = { 6 | children?: React.ReactNode; 7 | } & React.HTMLAttributes & 8 | CommonStyledProps; 9 | 10 | const StyledTableHead = styled.thead` 11 | display: table-header-group; 12 | `; 13 | const TableHead = forwardRef( 14 | function TableHead({ children, ...otherProps }, ref) { 15 | return ( 16 | 17 | {children} 18 | 19 | ); 20 | } 21 | ); 22 | 23 | TableHead.displayName = 'TableHead'; 24 | 25 | export { TableHead, TableHeadProps }; 26 | -------------------------------------------------------------------------------- /src/Table/TableHeadCell.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { TableHeadCell } from './TableHeadCell'; 6 | 7 | describe('', () => { 8 | function mountInTable(node: React.ReactNode) { 9 | const { container, getByText } = renderWithTheme( 10 | 11 | 12 | {node} 13 | 14 |
15 | ); 16 | return { 17 | th: container.querySelector('tr')?.firstElementChild as HTMLElement, 18 | getByText 19 | }; 20 | } 21 | 22 | it('renders TableHeadCell', () => { 23 | const { th } = mountInTable(); 24 | expect(th?.tagName).toBe('TH'); 25 | }); 26 | 27 | it('renders children', () => { 28 | const { getByText } = mountInTable(children); 29 | expect(getByText('children')).toBeInTheDocument(); 30 | }); 31 | 32 | describe('prop: sort', () => { 33 | it('should render without aria-sort attribute by default', () => { 34 | const { th } = mountInTable(); 35 | expect(th).not.toHaveAttribute('aria-sort'); 36 | }); 37 | 38 | it('should render aria-sort="ascending" when prop sort="asc" provided', () => { 39 | const { th } = mountInTable(); 40 | expect(th).toHaveAttribute('aria-sort', 'ascending'); 41 | }); 42 | 43 | it('should render aria-sort="descending" when prop sort="desc" provided', () => { 44 | const { th } = mountInTable(); 45 | expect(th).toHaveAttribute('aria-sort', 'descending'); 46 | }); 47 | }); 48 | 49 | describe('prop: disabled', () => { 50 | it('should disable th element', () => { 51 | const handleChange = jest.fn(); 52 | 53 | const { th } = mountInTable( 54 | 55 | ); 56 | expect(th).toHaveAttribute('aria-disabled', 'true'); 57 | 58 | th?.click?.(); 59 | expect(handleChange).not.toHaveBeenCalled(); 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /src/Table/TableRow.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { renderWithTheme } from '../../test/utils'; 3 | 4 | import { TableRow } from './TableRow'; 5 | 6 | describe('', () => { 7 | function mountInTable(node: React.ReactNode) { 8 | const { container, getByTestId } = renderWithTheme( 9 | 10 | {node} 11 |
12 | ); 13 | return { 14 | tr: container.querySelector('tbody')?.firstElementChild, 15 | getByTestId 16 | }; 17 | } 18 | 19 | it('renders TableRow', () => { 20 | const { tr } = mountInTable(); 21 | expect(tr?.tagName).toBe('TR'); 22 | }); 23 | 24 | it('renders children', () => { 25 | const children = ; 26 | const { getByTestId } = mountInTable({children}); 27 | expect(getByTestId('td')).toBeInTheDocument(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/Table/TableRow.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { blockSizes } from '../common/system'; 4 | 5 | type TableRowProps = { 6 | children?: React.ReactNode; 7 | } & React.HTMLAttributes; 8 | 9 | const StyledTr = styled.tr` 10 | color: inherit; 11 | display: table-row; 12 | height: calc(${blockSizes.md} - 2px); 13 | line-height: calc(${blockSizes.md} - 2px); 14 | vertical-align: middle; 15 | outline: none; 16 | 17 | color: ${({ theme }) => theme.canvasText}; 18 | &:hover { 19 | background: ${({ theme }) => theme.hoverBackground}; 20 | color: ${({ theme }) => theme.canvasTextInvert}; 21 | } 22 | `; 23 | 24 | const TableRow = forwardRef( 25 | function TableRow({ children, ...otherProps }, ref) { 26 | return ( 27 | 28 | {children} 29 | 30 | ); 31 | } 32 | ); 33 | 34 | TableRow.displayName = 'TableRow'; 35 | 36 | export { TableRow, TableRowProps }; 37 | -------------------------------------------------------------------------------- /src/Tabs/Tab.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | import { Tab } from './Tab'; 5 | 6 | describe('', () => { 7 | describe('prop: children', () => { 8 | it('should render passed child', () => { 9 | const child = 'Hey there!'; 10 | const { getByText } = renderWithTheme({child}); 11 | 12 | expect(getByText(child)).toBeInTheDocument(); 13 | }); 14 | }); 15 | 16 | describe('prop: selected', () => { 17 | it('should render with correct aria attribute', () => { 18 | const { getByRole } = renderWithTheme(); 19 | 20 | expect(getByRole('tab')).toHaveAttribute('aria-selected', 'true'); 21 | }); 22 | }); 23 | 24 | describe('prop: onClick', () => { 25 | it('should be called when a click is triggered', () => { 26 | const handleClick = jest.fn(); 27 | const { getByRole } = renderWithTheme(); 28 | 29 | getByRole('tab').click(); 30 | 31 | expect(handleClick).toHaveBeenCalledTimes(1); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/Tabs/TabBody.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | import { TabBody } from './TabBody'; 5 | 6 | describe('', () => { 7 | describe('prop: children', () => { 8 | it('should render passed child', () => { 9 | const child = 'Hey there!'; 10 | const { getByText } = renderWithTheme({child}); 11 | 12 | expect(getByText(child)).toBeInTheDocument(); 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/Tabs/TabBody.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | 3 | import styled from 'styled-components'; 4 | import { createBorderStyles, createBoxStyles } from '../common'; 5 | import { CommonStyledProps } from '../types'; 6 | 7 | type TabBodyProps = { 8 | children: React.ReactNode; 9 | } & React.HTMLAttributes & 10 | CommonStyledProps; 11 | 12 | const StyledTabBody = styled.div` 13 | ${createBoxStyles()} 14 | ${createBorderStyles()} 15 | position: relative; 16 | display: block; 17 | height: 100%; 18 | padding: 16px; 19 | font-size: 1rem; 20 | `; 21 | const TabBody = forwardRef( 22 | ({ children, ...otherProps }, ref) => { 23 | return ( 24 | 25 | {children} 26 | 27 | ); 28 | } 29 | ); 30 | 31 | TabBody.displayName = 'TabBody'; 32 | 33 | export { TabBody, TabBodyProps }; 34 | -------------------------------------------------------------------------------- /src/Toolbar/Toolbar.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import React from 'react'; 3 | 4 | import { Toolbar } from './Toolbar'; 5 | 6 | describe('', () => { 7 | it('should render', () => { 8 | const { container } = render(); 9 | const toolbar = container.firstChild; 10 | 11 | expect(toolbar).toBeInTheDocument(); 12 | }); 13 | 14 | it('should render children', () => { 15 | const { container } = render(A nice app bar); 16 | const toolbar = container.firstChild; 17 | 18 | expect(toolbar).toHaveTextContent('A nice app bar'); 19 | }); 20 | 21 | describe('prop: noPadding', () => { 22 | it('should apply 0 padding', () => { 23 | const { container } = render(); 24 | const toolbar = container.firstChild; 25 | 26 | expect(toolbar).toHaveStyleRule('padding', '0'); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/Toolbar/Toolbar.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | type ToolbarProps = { 5 | children?: React.ReactNode; 6 | noPadding?: boolean; 7 | } & React.HTMLAttributes; 8 | 9 | const StyledToolbar = styled.div` 10 | position: relative; 11 | display: flex; 12 | align-items: center; 13 | padding: ${props => (props.noPadding ? '0' : '4px')}; 14 | `; 15 | 16 | const Toolbar = forwardRef(function Toolbar( 17 | { children, noPadding = false, ...otherProps }, 18 | ref 19 | ) { 20 | return ( 21 | 22 | {children} 23 | 24 | ); 25 | }); 26 | 27 | Toolbar.displayName = 'Toolbar'; 28 | 29 | export { Toolbar }; 30 | -------------------------------------------------------------------------------- /src/Tooltip/Tooltip.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentMeta } from '@storybook/react'; 2 | import React from 'react'; 3 | import { Button, Tooltip } from 'react95'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.div` 7 | padding: 5rem; 8 | background: ${({ theme }) => theme.desktopBackground}; 9 | `; 10 | 11 | export default { 12 | title: 'Controls/Tooltip', 13 | component: Tooltip, 14 | decorators: [story => {story()}] 15 | } as ComponentMeta; 16 | 17 | export function Default() { 18 | return ( 19 | 20 | 21 | 22 | ); 23 | } 24 | 25 | Default.story = { 26 | name: 'default' 27 | }; 28 | -------------------------------------------------------------------------------- /src/Window/Window.spec.tsx: -------------------------------------------------------------------------------- 1 | import React, { createRef } from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { Window } from './Window'; 6 | 7 | describe('', () => { 8 | it('renders Window', () => { 9 | const { container } = renderWithTheme(); 10 | const window = container.firstChild; 11 | 12 | expect(window).toBeInTheDocument(); 13 | }); 14 | 15 | it('renders children', () => { 16 | const textContent = 'Hi there!'; 17 | const { getByText } = renderWithTheme( 18 | 19 | {textContent} 20 | 21 | ); 22 | expect(getByText(textContent)).toBeInTheDocument(); 23 | }); 24 | 25 | describe('prop: resizable', () => { 26 | it('does not render resize handle by default', () => { 27 | const { queryByTestId } = renderWithTheme(); 28 | 29 | expect(queryByTestId('resizeHandle')).not.toBeInTheDocument(); 30 | }); 31 | 32 | it('renders resize handle when set to true', () => { 33 | const { queryByTestId } = renderWithTheme(); 34 | 35 | expect(queryByTestId('resizeHandle')).toBeInTheDocument(); 36 | }); 37 | 38 | it('passes resizeRef to the resizable element', () => { 39 | const ref = createRef(); 40 | const { queryByTestId } = renderWithTheme( 41 | 42 | ); 43 | 44 | expect(queryByTestId('resizeHandle')).toBe(ref.current); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/Window/Window.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | import { createBorderStyles, createBoxStyles } from '../common'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type WindowProps = { 7 | children?: React.ReactNode; 8 | resizable?: boolean; 9 | resizeRef?: React.Ref; 10 | shadow?: boolean; 11 | } & React.HTMLAttributes & 12 | CommonStyledProps; 13 | 14 | const StyledWindow = styled.div` 15 | position: relative; 16 | padding: 4px; 17 | font-size: 1rem; 18 | ${createBorderStyles({ style: 'window' })} 19 | ${createBoxStyles()} 20 | `; 21 | 22 | const ResizeHandle = styled.span` 23 | ${({ theme }) => css` 24 | display: inline-block; 25 | position: absolute; 26 | bottom: 10px; 27 | right: 10px; 28 | width: 25px; 29 | height: 25px; 30 | background-image: linear-gradient( 31 | 135deg, 32 | ${theme.borderLightest} 16.67%, 33 | ${theme.material} 16.67%, 34 | ${theme.material} 33.33%, 35 | ${theme.borderDark} 33.33%, 36 | ${theme.borderDark} 50%, 37 | ${theme.borderLightest} 50%, 38 | ${theme.borderLightest} 66.67%, 39 | ${theme.material} 66.67%, 40 | ${theme.material} 83.33%, 41 | ${theme.borderDark} 83.33%, 42 | ${theme.borderDark} 100% 43 | ); 44 | background-size: 8.49px 8.49px; 45 | clip-path: polygon(100% 0px, 0px 100%, 100% 100%); 46 | cursor: nwse-resize; 47 | `} 48 | `; 49 | 50 | const Window = forwardRef( 51 | ( 52 | { children, resizable = false, resizeRef, shadow = true, ...otherProps }, 53 | ref 54 | ) => { 55 | return ( 56 | 57 | {children} 58 | {resizable && ( 59 | 60 | )} 61 | 62 | ); 63 | } 64 | ); 65 | 66 | Window.displayName = 'Window'; 67 | 68 | export * from './WindowContent'; 69 | 70 | export * from './WindowHeader'; 71 | 72 | export { Window, WindowProps }; 73 | -------------------------------------------------------------------------------- /src/Window/WindowContent.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme } from '../../test/utils'; 4 | 5 | import { WindowContent } from './WindowContent'; 6 | 7 | describe('', () => { 8 | it('renders WindowContent', () => { 9 | const { container } = renderWithTheme(); 10 | const windowContent = container.firstChild; 11 | 12 | expect(windowContent).toBeInTheDocument(); 13 | }); 14 | 15 | it('renders children', () => { 16 | const textContent = 'Hi there!'; 17 | const { getByText } = renderWithTheme( 18 | 19 | {textContent} 20 | 21 | ); 22 | expect(getByText(textContent)).toBeInTheDocument(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/Window/WindowContent.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled from 'styled-components'; 3 | import { CommonStyledProps } from '../types'; 4 | 5 | type WindowContentProps = { 6 | children?: React.ReactNode; 7 | } & React.HTMLAttributes & 8 | CommonStyledProps; 9 | 10 | const StyledWindowContent = styled.div` 11 | padding: 16px; 12 | `; 13 | 14 | const WindowContent = forwardRef( 15 | function WindowContent({ children, ...otherProps }, ref) { 16 | return ( 17 | 18 | {children} 19 | 20 | ); 21 | } 22 | ); 23 | 24 | WindowContent.displayName = 'WindowContent'; 25 | 26 | export { WindowContent, WindowContentProps }; 27 | -------------------------------------------------------------------------------- /src/Window/WindowHeader.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { renderWithTheme, theme } from '../../test/utils'; 4 | 5 | import { WindowHeader } from './WindowHeader'; 6 | 7 | describe('', () => { 8 | it('renders WindowHeader', () => { 9 | const { container } = renderWithTheme(); 10 | const windowHeader = container.firstChild; 11 | 12 | expect(windowHeader).toBeInTheDocument(); 13 | }); 14 | 15 | it('renders children', () => { 16 | const textContent = 'Hi there!'; 17 | const { getByText } = renderWithTheme( 18 | 19 | {textContent} 20 | 21 | ); 22 | expect(getByText(textContent)).toBeInTheDocument(); 23 | }); 24 | 25 | describe('prop: active', () => { 26 | it('displays active header by default', () => { 27 | const { container } = renderWithTheme(); 28 | const windowHeader = container.firstChild as HTMLDivElement; 29 | 30 | expect(windowHeader).toHaveStyleRule('color', theme.headerText); 31 | expect(windowHeader).toHaveStyleRule( 32 | 'background', 33 | theme.headerBackground 34 | ); 35 | }); 36 | 37 | it('displays active header when set to true', () => { 38 | const { container } = renderWithTheme(); 39 | const windowHeader = container.firstChild as HTMLDivElement; 40 | 41 | expect(windowHeader).toHaveStyleRule('color', theme.headerText); 42 | expect(windowHeader).toHaveStyleRule( 43 | 'background', 44 | theme.headerBackground 45 | ); 46 | }); 47 | 48 | it('renders non-active header when set to false', () => { 49 | const { container } = renderWithTheme(); 50 | const windowHeader = container.firstChild; 51 | 52 | expect(windowHeader).toHaveStyleRule('color', theme.headerNotActiveText); 53 | expect(windowHeader).toHaveStyleRule( 54 | 'background', 55 | theme.headerNotActiveBackground 56 | ); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /src/Window/WindowHeader.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | import { StyledButton } from '../Button/Button'; 4 | import { CommonStyledProps } from '../types'; 5 | 6 | type WindowHeaderProps = { 7 | children?: React.ReactNode; 8 | active?: boolean; 9 | } & React.HTMLAttributes & 10 | CommonStyledProps; 11 | 12 | const StyledWindowHeader = styled.div>` 13 | height: 33px; 14 | line-height: 33px; 15 | padding-left: 0.25rem; 16 | padding-right: 3px; 17 | font-weight: bold; 18 | border: 2px solid ${({ theme }) => theme.material}; 19 | ${({ active }) => 20 | active === false 21 | ? css` 22 | background: ${({ theme }) => theme.headerNotActiveBackground}; 23 | color: ${({ theme }) => theme.headerNotActiveText}; 24 | ` 25 | : css` 26 | background: ${({ theme }) => theme.headerBackground}; 27 | color: ${({ theme }) => theme.headerText}; 28 | `} 29 | 30 | ${StyledButton} { 31 | padding-left: 0; 32 | padding-right: 0; 33 | height: 27px; 34 | width: 31px; 35 | } 36 | `; 37 | 38 | // TODO - should we add some aria label indicating if window is currently active? 39 | const WindowHeader = forwardRef( 40 | function WindowHeader({ active = true, children, ...otherProps }, ref) { 41 | return ( 42 | 43 | {children} 44 | 45 | ); 46 | } 47 | ); 48 | 49 | WindowHeader.displayName = 'WindowHeader'; 50 | 51 | export { WindowHeader, WindowHeaderProps }; 52 | -------------------------------------------------------------------------------- /src/assets/fonts/dist/ms_sans_serif.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/fonts/dist/ms_sans_serif.woff -------------------------------------------------------------------------------- /src/assets/fonts/dist/ms_sans_serif.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/fonts/dist/ms_sans_serif.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/dist/ms_sans_serif_bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/fonts/dist/ms_sans_serif_bold.woff -------------------------------------------------------------------------------- /src/assets/fonts/dist/ms_sans_serif_bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/fonts/dist/ms_sans_serif_bold.woff2 -------------------------------------------------------------------------------- /src/assets/fonts/src/ms-sans-serif-bold/MS Sans Serif Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/fonts/src/ms-sans-serif-bold/MS Sans Serif Bold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/src/ms-sans-serif-bold/license.txt: -------------------------------------------------------------------------------- 1 | The FontStruction “MS Sans Serif Bold” 2 | (https://fontstruct.com/fontstructions/show/1384862) by “lou” is licensed 3 | under a Creative Commons Attribution Share Alike license 4 | (http://creativecommons.org/licenses/by-sa/3.0/). 5 | -------------------------------------------------------------------------------- /src/assets/fonts/src/ms-sans-serif-bold/readme.txt: -------------------------------------------------------------------------------- 1 | The font file in this archive was created using Fontstruct the free, online 2 | font-building tool. 3 | This font was created by “lou”. 4 | This font has a homepage where this archive and other versions may be found: 5 | https://fontstruct.com/fontstructions/show/1384862 6 | 7 | Try Fontstruct at http://fontstruct.com 8 | It’s easy and it’s fun. 9 | 10 | NOTE FOR FLASH USERS: Fontstruct fonts (fontstructions) are optimized for Flash. 11 | If the font in this archive is a pixel font, it is best displayed at a font-size 12 | of 11. 13 | 14 | Fontstruct is sponsored by FontShop. 15 | Visit them at https://fontshop.com 16 | FontShop is the original independent font retailer. We’ve been around since 17 | the dawn of digital type. Whether you need the right font or need to create the 18 | right font from scratch, let our 26 years of experience work for you. 19 | 20 | Fontstruct is copyright ©2017 Rob Meek 21 | 22 | LEGAL NOTICE: 23 | In using this font you must comply with the licensing terms described in the 24 | file “license.txt” included with this archive. 25 | If you redistribute the font file in this archive, it must be accompanied by all 26 | the other files from this archive, including this one. 27 | -------------------------------------------------------------------------------- /src/assets/fonts/src/ms-sans-serif/MS Sans Serif.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/fonts/src/ms-sans-serif/MS Sans Serif.ttf -------------------------------------------------------------------------------- /src/assets/fonts/src/ms-sans-serif/license.txt: -------------------------------------------------------------------------------- 1 | The FontStruction “MS Sans Serif” 2 | (https://fontstruct.com/fontstructions/show/1384746) by “lou” is licensed 3 | under a Creative Commons Attribution Share Alike license 4 | (http://creativecommons.org/licenses/by-sa/3.0/). 5 | -------------------------------------------------------------------------------- /src/assets/fonts/src/ms-sans-serif/readme.txt: -------------------------------------------------------------------------------- 1 | The font file in this archive was created using Fontstruct the free, online 2 | font-building tool. 3 | This font was created by “lou”. 4 | This font has a homepage where this archive and other versions may be found: 5 | https://fontstruct.com/fontstructions/show/1384746 6 | 7 | Try Fontstruct at http://fontstruct.com 8 | It’s easy and it’s fun. 9 | 10 | NOTE FOR FLASH USERS: Fontstruct fonts (fontstructions) are optimized for Flash. 11 | If the font in this archive is a pixel font, it is best displayed at a font-size 12 | of 11. 13 | 14 | Fontstruct is sponsored by FontShop. 15 | Visit them at https://fontshop.com 16 | FontShop is the original independent font retailer. We’ve been around since 17 | the dawn of digital type. Whether you need the right font or need to create the 18 | right font from scratch, let our 26 years of experience work for you. 19 | 20 | Fontstruct is copyright ©2017 Rob Meek 21 | 22 | LEGAL NOTICE: 23 | In using this font you must comply with the licensing terms described in the 24 | file “license.txt” included with this archive. 25 | If you redistribute the font file in this archive, it must be accompanied by all 26 | the other files from this archive, including this one. 27 | -------------------------------------------------------------------------------- /src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/images/logo.png -------------------------------------------------------------------------------- /src/assets/images/logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/assets/images/logo.psd -------------------------------------------------------------------------------- /src/common/SwitchBase.ts: -------------------------------------------------------------------------------- 1 | import styled, { css } from 'styled-components'; 2 | 3 | import { createDisabledTextStyles, focusOutline } from '.'; 4 | import { StyledMenuListItem } from '../MenuList/MenuList'; 5 | 6 | export const size = 20; 7 | 8 | export const StyledInput = styled.input` 9 | position: absolute; 10 | left: 0; 11 | margin: 0; 12 | width: ${size}px; 13 | height: ${size}px; 14 | opacity: 0; 15 | z-index: -1; 16 | `; 17 | 18 | export const StyledLabel = styled.label<{ $disabled: boolean }>` 19 | display: inline-flex; 20 | align-items: center; 21 | position: relative; 22 | margin: 8px 0; 23 | cursor: ${({ $disabled }) => (!$disabled ? 'pointer' : 'auto')}; 24 | user-select: none; 25 | font-size: 1rem; 26 | color: ${({ theme }) => theme.materialText}; 27 | ${props => props.$disabled && createDisabledTextStyles()} 28 | 29 | ${StyledMenuListItem} & { 30 | margin: 0; 31 | height: 100%; 32 | } 33 | ${StyledMenuListItem}:hover & { 34 | ${({ $disabled, theme }) => 35 | !$disabled && 36 | css` 37 | color: ${theme.materialTextInvert}; 38 | `}; 39 | } 40 | `; 41 | 42 | // TODO how to handle focus styles in 'menu' variant of Checkbox/Radio? 43 | export const LabelText = styled.span` 44 | display: inline-block; 45 | line-height: 1; 46 | padding: 2px; 47 | ${StyledInput}:focus ~ & { 48 | ${focusOutline} 49 | } 50 | ${StyledInput}:not(:disabled) ~ &:active { 51 | ${focusOutline} 52 | } 53 | `; 54 | -------------------------------------------------------------------------------- /src/common/constants.ts: -------------------------------------------------------------------------------- 1 | export const KEYBOARD_KEY_CODES = { 2 | ARROW_DOWN: 'ArrowDown', 3 | ARROW_LEFT: 'ArrowLeft', 4 | ARROW_RIGHT: 'ArrowRight', 5 | ARROW_UP: 'ArrowUp', 6 | END: 'End', 7 | ENTER: 'Enter', 8 | ESC: 'Escape', 9 | HOME: 'Home', 10 | SPACE: 'Space', 11 | TAB: 'Tab' 12 | }; 13 | -------------------------------------------------------------------------------- /src/common/hooks/useControlledOrUncontrolled.ts: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback } from 'react'; 2 | 3 | export default function useControlledOrUncontrolled({ 4 | defaultValue, 5 | onChange, 6 | onChangePropName = 'onChange', 7 | readOnly, 8 | value, 9 | valuePropName = 'value' 10 | }: { 11 | defaultValue: T; 12 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 13 | onChange?: (...args: any[]) => void; 14 | onChangePropName?: string; 15 | readOnly?: boolean; 16 | value: T | undefined; 17 | valuePropName?: string; 18 | }): [T, (newValue: React.SetStateAction) => void] { 19 | const isControlled = value !== undefined; 20 | const [controlledValue, setControlledValue] = useState(defaultValue); 21 | const handleChangeIfUncontrolled = useCallback( 22 | (newValue: React.SetStateAction) => { 23 | if (!isControlled) { 24 | setControlledValue(newValue); 25 | } 26 | }, 27 | [isControlled] 28 | ); 29 | 30 | // Because we provide `onChange` even to uncontrolled components, React's 31 | // default uncontrolled warning must be reimplemented. This also deals with 32 | // props that are different from `value`. 33 | if (isControlled && typeof onChange !== 'function' && !readOnly) { 34 | const message = `Warning: You provided a \`${valuePropName}\` prop to a component without an \`${onChangePropName}\` handler.${ 35 | valuePropName === 'value' 36 | ? `This will render a read-only field. If the field should be mutable use \`defaultValue\`. Otherwise, set either \`${onChangePropName}\` or \`readOnly\`.` 37 | : `This breaks the component state. You must provide an \`${onChangePropName}\` function that updates \`${valuePropName}\`.` 38 | }`; 39 | 40 | // eslint-disable-next-line no-console 41 | console.warn(message); 42 | } 43 | 44 | return [isControlled ? value : controlledValue, handleChangeIfUncontrolled]; 45 | } 46 | -------------------------------------------------------------------------------- /src/common/hooks/useEventCallback.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | const useEnhancedEffect = 4 | typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect; 5 | 6 | /** 7 | * https://github.com/facebook/react/issues/14099#issuecomment-440013892 8 | */ 9 | export default function useEventCallback( 10 | fn: (...args: Args) => Return 11 | ): (...args: Args) => Return { 12 | const ref = React.useRef(fn); 13 | useEnhancedEffect(() => { 14 | ref.current = fn; 15 | }); 16 | return React.useCallback( 17 | (...args: Args) => 18 | // @ts-expect-error hide `this` 19 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 20 | (0, ref.current!)(...args), 21 | [] 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src/common/hooks/useForkRef.ts: -------------------------------------------------------------------------------- 1 | // Straight out copied from https://github.com/mui-org/material-ui 😂 2 | 3 | import { useMemo } from 'react'; 4 | 5 | function setRef( 6 | ref: React.RefCallback | React.MutableRefObject | null, 7 | value: T 8 | ) { 9 | if (typeof ref === 'function') { 10 | ref(value); 11 | } else if (ref) { 12 | // eslint-disable-next-line no-param-reassign 13 | ref.current = value; 14 | } 15 | } 16 | 17 | export default function useForkRef( 18 | refA: React.RefCallback | React.MutableRefObject | null, 19 | refB: React.RefCallback | React.MutableRefObject | null 20 | ): React.RefCallback | null { 21 | /** 22 | * This will create a new function if the ref props change and are defined. 23 | * This means react will call the old forkRef with `null` and the new forkRef 24 | * with the ref. Cleanup naturally emerges from this behavior 25 | */ 26 | return useMemo(() => { 27 | if (refA == null && refB == null) { 28 | return null; 29 | } 30 | return refValue => { 31 | setRef(refA, refValue); 32 | setRef(refB, refValue); 33 | }; 34 | }, [refA, refB]); 35 | } 36 | -------------------------------------------------------------------------------- /src/common/hooks/useId.spec.ts: -------------------------------------------------------------------------------- 1 | import { renderHook } from '@testing-library/react-hooks'; 2 | import { useId } from './useId'; 3 | 4 | describe(useId, () => { 5 | it('returns a random string of 10 digits', () => { 6 | const { result } = renderHook(() => useId()); 7 | expect(result.current).toMatch(/^[0-9a-z]{10}$/i); 8 | }); 9 | 10 | it('returns the passed ID', () => { 11 | const { result } = renderHook(() => useId('test')); 12 | expect(result.current).toEqual('test'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/common/hooks/useId.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | 3 | function makeId() { 4 | const chars = 5 | '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 6 | let id = ''; 7 | for (let i = 0; i < 10; i += 1) { 8 | id += chars[Math.floor(Math.random() * chars.length)]; 9 | } 10 | return id; 11 | } 12 | 13 | export const useId = (id?: string) => { 14 | return useMemo(() => id ?? makeId(), [id]); 15 | }; 16 | -------------------------------------------------------------------------------- /src/common/system.ts: -------------------------------------------------------------------------------- 1 | // TODO - implement styled-system 2 | 3 | import { Sizes } from '../types'; 4 | 5 | export const blockSizes: Record = { 6 | sm: '28px', 7 | md: '36px', 8 | lg: '44px' 9 | }; 10 | -------------------------------------------------------------------------------- /src/common/themes/aiee.ts: -------------------------------------------------------------------------------- 1 | /* "AIEE" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Aiee-668092636 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'aiee', 9 | anchor: 'rgb(0,0,128)', 10 | anchorVisited: 'rgb(0,0,128)', 11 | borderDark: 'rgb(211,214,217)', 12 | borderDarkest: 'rgb(65,187,241)', 13 | borderLight: 'rgb(238,244,252)', 14 | borderLightest: 'rgb(250,254,255)', 15 | canvas: 'rgb(255,255,255)', 16 | canvasText: 'rgb(0,62,1090)', 17 | canvasTextDisabled: 'rgb(211,214,217)', 18 | canvasTextDisabledShadow: 'rgb(250,254,255)', 19 | canvasTextInvert: 'rgb(0,62,109)', 20 | checkmark: 'rgb(0,62,1090)', 21 | checkmarkDisabled: 'rgb(88,152,231)', 22 | desktopBackground: 'rgb(68,125,183)', 23 | flatDark: 'rgb(211,214,217)', 24 | flatLight: 'rgb(238,244,252)', 25 | focusSecondary: 'rgb(250,254,255)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(4,118,180), rgb(251,211,61))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(0,159,223), rgb(0,207,247))', 30 | headerNotActiveText: 'rgb(0,62,109)', 31 | headerText: 'rgb(255,255,255)', 32 | hoverBackground: 'rgb(251,211,61)', 33 | material: 'rgb(227,238,251)', 34 | materialDark: 'rgb(0,159,223)', 35 | materialText: 'rgb(0,62,109)', 36 | materialTextDisabled: 'rgb(211,214,217)', 37 | materialTextDisabledShadow: 'rgb(250,254,255)', 38 | materialTextInvert: 'rgb(0,62,109)', 39 | progress: 'rgb(251,211,61)', 40 | tooltip: 'rgb(255,243,185)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/ash.ts: -------------------------------------------------------------------------------- 1 | /* "Ash" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Ash-575566643 3 | */ 4 | import { Theme } from './types'; 5 | 6 | export default { 7 | name: 'ash', 8 | anchor: 'rgb(192, 192, 192)', 9 | anchorVisited: 'rgb(192, 192, 192)', 10 | borderDark: 'rgb(63, 63, 63)', 11 | borderDarkest: 'rgb(0, 0, 0)', 12 | borderLight: 'rgb(115, 115, 115)', 13 | borderLightest: 'rgb(175, 175, 175)', 14 | canvas: 'rgb(64, 64, 64)', 15 | canvasText: 'rgb(0, 0, 0)', 16 | canvasTextDisabled: 'rgb(63, 63, 63)', 17 | canvasTextDisabledShadow: 'rgb(175, 175, 175)', 18 | canvasTextInvert: 'rgb(255, 255, 255)', 19 | checkmark: 'rgb(0, 0, 0)', 20 | checkmarkDisabled: 'rgb(128, 128, 128)', 21 | desktopBackground: 'rgb(0, 0, 0)', 22 | flatDark: 'rgb(63, 63, 63)', 23 | flatLight: 'rgb(96, 96, 96)', 24 | focusSecondary: 'rgb(175, 175, 175)', 25 | headerBackground: 'linear-gradient(to right, rgb(0, 0, 0), rgb(0, 0, 0))', 26 | headerNotActiveBackground: 27 | 'linear-gradient(to right, rgb(63, 63, 63), rgb(0, 0, 0))', 28 | headerNotActiveText: 'rgb(128, 128, 128)', 29 | headerText: 'rgb(255, 255, 255)', 30 | hoverBackground: 'rgb(0, 0, 0)', 31 | material: 'rgb(96, 96, 96)', 32 | materialDark: 'rgb(63, 63, 63)', 33 | materialText: 'rgb(0, 0, 0)', 34 | materialTextDisabled: 'rgb(63, 63, 63)', 35 | materialTextDisabledShadow: 'rgb(175, 175, 175)', 36 | materialTextInvert: 'rgb(255, 255, 255)', 37 | progress: 'rgb(0, 0, 0)', 38 | tooltip: 'rgb(0, 0, 0)' 39 | } as Theme; 40 | -------------------------------------------------------------------------------- /src/common/themes/azureOrange.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'azureOrange', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#05427f', 9 | borderDarkest: '#000000', 10 | borderLight: '#2b8fff', 11 | borderLightest: '#7ebfff', 12 | canvas: '#ffffff', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#05427f', 15 | canvasTextDisabledShadow: '#7ebfff', 16 | canvasTextInvert: '#000000', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#05427f', 19 | desktopBackground: '#ff7d01', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#171123', 23 | headerBackground: '#171123', 24 | headerNotActiveBackground: '#4E6766', 25 | headerNotActiveText: '#0180ff', 26 | headerText: '#ffffff', 27 | hoverBackground: '#F46036', 28 | material: '#0180ff', 29 | materialDark: '#9a9e9c', 30 | materialText: '#000000', 31 | materialTextDisabled: '#05427f', 32 | materialTextDisabledShadow: '#7ebfff', 33 | materialTextInvert: '#000000', 34 | progress: '#F46036', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/bee.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'bee', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#846d06', 9 | borderDarkest: '#0C1618', 10 | borderLight: '#e7c221', 11 | borderLightest: '#f8df6e', 12 | canvas: '#ffffff', 13 | canvasText: '#0C1618', 14 | canvasTextDisabled: '#846d06', 15 | canvasTextDisabledShadow: '#f8df6e', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#0C1618', 18 | checkmarkDisabled: '#846d06', 19 | desktopBackground: '#977800', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#0C1618', 24 | headerNotActiveBackground: '#7F7B82', 25 | headerNotActiveText: '#e5bd03', 26 | headerText: '#f8df6e', 27 | hoverBackground: '#0C1618', 28 | material: '#e5bd03', 29 | materialDark: '#7F7B82', 30 | materialText: '#0C1618', 31 | materialTextDisabled: '#846d06', 32 | materialTextDisabledShadow: '#f8df6e', 33 | materialTextInvert: '#ffffff', 34 | progress: '#0C1618', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/blackAndWhite.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'blackAndWhite', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#888c8f', 9 | borderDarkest: '#000000', 10 | borderLight: '#dfe0e3', 11 | borderLightest: '#888c8f', 12 | canvas: '#ffffff', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#888c8f', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#888c8f', 19 | desktopBackground: '#ffffff', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#000000', 24 | headerNotActiveBackground: '#ffffff', 25 | headerNotActiveText: '#000000', 26 | headerText: '#ffffff', 27 | hoverBackground: '#000000', 28 | material: '#ffffff', 29 | materialDark: '#9a9e9c', 30 | materialText: '#000000', 31 | materialTextDisabled: '#888c8f', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#000000', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/blue.ts: -------------------------------------------------------------------------------- 1 | /* "Blue" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Blue-525167751 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'blue', 9 | anchor: 'rgb(0, 0, 128)', 10 | anchorVisited: 'rgb(0, 0, 128)', 11 | borderDark: 'rgb(49, 131, 221)', 12 | borderDarkest: 'rgb(0, 0, 0)', 13 | borderLight: 'rgb(166, 202, 240)', 14 | borderLightest: 'rgb(211, 228, 248)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(49, 131, 221)', 18 | canvasTextDisabledShadow: 'rgb(211, 228, 248)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(49, 131, 221)', 22 | desktopBackground: 'rgb(58, 110, 165)', 23 | flatDark: 'rgb(49, 131, 221)', 24 | flatLight: 'rgb(166, 202, 240)', 25 | focusSecondary: 'rgb(211, 228, 248)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(0, 0, 128), rgb(16, 132, 208))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(49, 131, 221), rgb(49, 131, 221))', 30 | headerNotActiveText: 'rgb(0, 0, 128)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(51, 153, 255)', 33 | material: 'rgb(166, 202, 240)', 34 | materialDark: 'rgb(49, 131, 221)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(49, 131, 221)', 37 | materialTextDisabledShadow: 'rgb(211, 228, 248)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(51, 153, 255)', 40 | tooltip: 'rgb(225, 225, 255)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/brick.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'brick', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#6c684b', 9 | borderDarkest: '#020000', 10 | borderLight: '#e2ddc9', 11 | borderLightest: '#ffffff', 12 | canvas: '#ffffff', 13 | canvasText: '#020000', 14 | canvasTextDisabled: '#6c684b', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#020000', 18 | checkmarkDisabled: '#6c684b', 19 | desktopBackground: '#420000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#8e0101', 24 | headerNotActiveBackground: '#90885c', 25 | headerNotActiveText: '#c2bfa3', 26 | headerText: '#ffffff', 27 | hoverBackground: '#8e0101', 28 | material: '#c2bfa3', 29 | materialDark: '#9a9e9c', 30 | materialText: '#020000', 31 | materialTextDisabled: '#6c684b', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#8e0101', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/candy.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'candy', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#d1579e', 9 | borderDarkest: '#44132f', 10 | borderLight: '#f1acd5', 11 | borderLightest: '#EFF1F3', 12 | canvas: '#EFF1F3', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#d1579e', 15 | canvasTextDisabledShadow: '#EFF1F3', 16 | canvasTextInvert: '#EFF1F3', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#d1579e', 19 | desktopBackground: '#b477bd', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#87255B', 24 | headerNotActiveBackground: '#a08796', 25 | headerNotActiveText: '#EBD2BE', 26 | headerText: '#EFF1F3', 27 | hoverBackground: '#256EFF', 28 | material: '#E5A4CB', 29 | materialDark: '#9a9e9c', 30 | materialText: '#000000', 31 | materialTextDisabled: '#d1579e', 32 | materialTextDisabledShadow: '#EFF1F3', 33 | materialTextInvert: '#EFF1F3', 34 | progress: '#256EFF', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/cherry.ts: -------------------------------------------------------------------------------- 1 | /* "Cherry" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Cherry-747961418 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'cherry', 9 | anchor: 'rgb(128, 0, 1)', 10 | anchorVisited: 'rgb(128, 0, 1)', 11 | borderDark: 'rgb(128, 128, 128)', 12 | borderDarkest: 'rgb(64, 64, 64)', 13 | borderLight: 'rgb(200, 212, 208)', 14 | borderLightest: 'rgb(255, 255, 255)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(128, 128, 128)', 18 | canvasTextDisabledShadow: 'rgb(255, 255, 255)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(128, 128, 128)', 22 | desktopBackground: 'rgb(165, 58, 109)', 23 | flatDark: 'rgb(128, 128, 128)', 24 | flatLight: 'rgb(200, 212, 208)', 25 | focusSecondary: 'rgb(255, 255, 255)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(106, 10, 36), rgb(240, 166, 202))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(128, 128, 128), rgb(192, 192, 192))', 30 | headerNotActiveText: 'rgb(212, 208, 200)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(106, 10, 36)', 33 | material: 'rgb(200, 212, 208)', 34 | materialDark: 'rgb(128, 128, 128)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(128, 128, 128)', 37 | materialTextDisabledShadow: 'rgb(255, 255, 255)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(106, 10, 36)', 40 | tooltip: 'rgb(225, 254, 255)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/coldGray.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'coldGray', 5 | 6 | anchor: '#8d88c2', 7 | anchorVisited: '#440381', 8 | background: '#4C6663', 9 | borderDark: '#5b57a1', 10 | borderDarkest: '#010601', 11 | borderLight: '#a4a7c8', 12 | borderLightest: '#c7c7df', 13 | canvas: '#c7c7df', 14 | canvasText: '#050608', 15 | canvasTextDisabled: '#888c8f', 16 | canvasTextDisabledShadow: '#ffffff', 17 | canvasTextInvert: '#ffffff', 18 | checkmark: '#010601', 19 | checkmarkDisabled: '#5b57a1', 20 | desktopBackground: '#606286', 21 | flatDark: '#5b57a1', 22 | flatLight: '#a4a7c8', 23 | focusSecondary: '#fefe03', 24 | headerBackground: '#3B3D64', 25 | headerNotActiveBackground: '#6063a5', 26 | headerNotActiveText: '#a1a3ca', 27 | headerText: '#010601', 28 | hoverBackground: '#8d88c2', 29 | material: '#a1a3ca', 30 | materialDark: '#6063a5', 31 | materialText: '#010601', 32 | materialTextDisabled: '#5b57a1', 33 | materialTextDisabledShadow: '#c7c7df', 34 | materialTextInvert: '#c7c7df', 35 | progress: '#8d88c2', 36 | tooltip: '#fefbcc' 37 | } as Theme; 38 | -------------------------------------------------------------------------------- /src/common/themes/counterStrike.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'counterStrike', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#2c3125', 9 | borderDarkest: '#0a0a0a', 10 | borderLight: '#5d6d54', 11 | borderLightest: '#788475', 12 | canvas: '#3e4639', 13 | canvasText: '#f6fbf5', 14 | canvasTextDisabled: '#2c3125', 15 | canvasTextDisabledShadow: '#788475', 16 | canvasTextInvert: '#f6fbf5', 17 | checkmark: '#f6fbf5', 18 | checkmarkDisabled: '#2c3125', 19 | desktopBackground: '#bcbd52', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#4b5844', 24 | headerNotActiveBackground: '#4b5844', 25 | headerNotActiveText: '#74806e', 26 | headerText: '#fefefe', 27 | hoverBackground: '#978830', 28 | material: '#4b5844', 29 | materialDark: '#2f3428', 30 | materialText: '#f6fbf5', 31 | materialTextDisabled: '#2c3125', 32 | materialTextDisabledShadow: '#788475', 33 | materialTextInvert: '#fefefe', 34 | progress: '#978830', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/darkTeal.ts: -------------------------------------------------------------------------------- 1 | /* "Teal for Shelbi - Dark" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Teal-for-Shelbi-Dark-631177772 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'darkTeal', 9 | anchor: 'rgb(0, 132, 132)', 10 | anchorVisited: 'rgb(0, 132, 132)', 11 | borderDark: 'rgb(21, 43, 43)', 12 | borderDarkest: 'rgb(0, 0, 0)', 13 | borderLight: 'rgb(32, 64, 64)', 14 | borderLightest: 'rgb(88, 139, 139)', 15 | canvas: 'rgb(0, 48, 48)', 16 | canvasText: 'rgb(255, 255, 255)', 17 | canvasTextDisabled: 'rgb(21, 43, 43)', 18 | canvasTextDisabledShadow: 'rgb(88, 139, 139)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(255, 255, 255)', 21 | checkmarkDisabled: 'rgb(64, 128, 128)', 22 | desktopBackground: 'rgb(0, 64, 64)', 23 | flatDark: 'rgb(21, 43, 43)', 24 | flatLight: 'rgb(32, 64, 64)', 25 | focusSecondary: 'rgb(88, 139, 139)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(0, 96, 96), rgb(0, 132, 132))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(24, 50, 50), rgb(92, 112, 112))', 30 | headerNotActiveText: 'rgb(192, 204, 204)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(0, 128, 128)', 33 | material: 'rgb(32, 64, 64)', 34 | materialDark: 'rgb(24, 50, 50)', 35 | materialText: 'rgb(255, 255, 255)', 36 | materialTextDisabled: 'rgb(21, 43, 43)', 37 | materialTextDisabledShadow: 'rgb(88, 139, 139)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(0, 128, 128)', 40 | tooltip: 'rgb(0, 32, 32)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/denim.ts: -------------------------------------------------------------------------------- 1 | /* "Denim" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Denim-870494744 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'denim', 9 | anchor: 'rgb(0, 0, 128)', 10 | anchorVisited: 'rgb(0, 0, 128)', 11 | borderDark: 'rgb(0, 0, 255)', 12 | borderDarkest: 'rgb(64, 64, 64)', 13 | borderLight: 'rgb(128, 128, 255)', 14 | borderLightest: 'rgb(191, 191, 255)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(0, 0, 255)', 18 | canvasTextDisabledShadow: 'rgb(191, 191, 255)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(0, 0, 255)', 22 | desktopBackground: 'rgb(0, 64, 128)', 23 | flatDark: 'rgb(0, 0, 255)', 24 | flatLight: 'rgb(128, 128, 255)', 25 | focusSecondary: 'rgb(191, 191, 255)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(10, 36, 106), rgb(148, 190, 237))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(0, 0, 255), rgb(180, 180, 180))', 30 | headerNotActiveText: 'rgb(192, 192, 192)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(10, 36, 106)', 33 | material: 'rgb(128, 128, 255)', 34 | materialDark: 'rgb(0, 0, 255)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(0, 0, 255)', 37 | materialTextDisabledShadow: 'rgb(191, 191, 255)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(10, 36, 106)', 40 | tooltip: 'rgb(255, 255, 225)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/eggplant.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'eggplant', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#526d67', 9 | borderDarkest: '#050608', 10 | borderLight: '#a2c7c0', 11 | borderLightest: '#cee8e3', 12 | canvas: '#ffffff', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#526d67', 15 | canvasTextDisabledShadow: '#cee8e3', 16 | canvasTextInvert: '#cee8e3', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#526d67', 19 | desktopBackground: '#400040', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#4b8178', 24 | headerNotActiveBackground: '#89b0a8', 25 | headerNotActiveText: '#4b8178', 26 | headerText: '#ffffff', 27 | hoverBackground: '#4b8178', 28 | material: '#89b0a8', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#526d67', 32 | materialTextDisabledShadow: '#cee8e3', 33 | materialTextInvert: '#ffffff', 34 | progress: '#4b8178', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/fxDev.ts: -------------------------------------------------------------------------------- 1 | /* "FxDev" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/FxDev-701274128 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'fxDev', 9 | anchor: 'rgb(47, 138, 202)', 10 | anchorVisited: 'rgb(47, 138, 202)', 11 | borderDark: 'rgb(27, 33, 39)', 12 | borderDarkest: 'rgb(7, 9, 10)', 13 | borderLight: 'rgb(69, 82, 94)', 14 | borderLightest: 'rgb(107, 113, 122)', 15 | canvas: 'rgb(23, 27, 31)', 16 | canvasText: 'rgb(245, 247, 250)', 17 | canvasTextDisabled: 'rgb(27, 33, 39)', 18 | canvasTextDisabledShadow: 'rgb(107, 113, 122)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(245, 247, 250)', 21 | checkmarkDisabled: 'rgb(133, 136, 140)', 22 | desktopBackground: 'rgb(26, 58, 99)', 23 | flatDark: 'rgb(27, 33, 39)', 24 | flatLight: 'rgb(57, 66, 77)', 25 | focusSecondary: 'rgb(107, 113, 122)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(26, 70, 102), rgb(26, 70, 102))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(28, 33, 38), rgb(28, 33, 38))', 30 | headerNotActiveText: 'rgb(245, 247, 250)', 31 | headerText: 'rgb(245, 247, 250)', 32 | hoverBackground: 'rgb(7, 77, 117)', 33 | material: 'rgb(57, 66, 77)', 34 | materialDark: 'rgb(28, 33, 38)', 35 | materialText: 'rgb(255, 255, 255)', 36 | materialTextDisabled: 'rgb(27, 33, 39)', 37 | materialTextDisabledShadow: 'rgb(107, 113, 122)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(7, 77, 117)', 40 | tooltip: 'rgb(243, 242, 219)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/highContrast.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'highContrast', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#888c8f', 9 | borderDarkest: '#ffffff', 10 | borderLight: '#dfe0e3', 11 | borderLightest: '#ffffff', 12 | canvas: '#353535', 13 | canvasText: '#ffffff', 14 | canvasTextDisabled: '#888c8f', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#ffffff', 18 | checkmarkDisabled: '#888c8f', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#8e0284', 24 | headerNotActiveBackground: '#7f7f7f', 25 | headerNotActiveText: '#ced0cf', 26 | headerText: '#ffffff', 27 | hoverBackground: '#8e0284', 28 | material: '#000000', 29 | materialDark: '#9a9e9c', 30 | materialText: '#ffffff', 31 | materialTextDisabled: '#888c8f', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#8e0284', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/honey.ts: -------------------------------------------------------------------------------- 1 | /* "Honey" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Honey-632126512 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'honey', 9 | anchor: 'rgb(128, 128, 0)', 10 | anchorVisited: 'rgb(128, 128, 0)', 11 | borderDark: 'rgb(170, 123, 0)', 12 | borderDarkest: 'rgb(64, 64, 64)', 13 | borderLight: 'rgb(255, 186, 0)', 14 | borderLightest: 'rgb(255, 220, 128)', 15 | canvas: 'rgb(255, 220, 128)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(170, 123, 0)', 18 | canvasTextDisabledShadow: 'rgb(255, 220, 128)', 19 | canvasTextInvert: 'rgb(255, 255, 0)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(170, 123, 0)', 22 | desktopBackground: 'rgb(170, 123, 0)', 23 | flatDark: 'rgb(170, 123, 0)', 24 | flatLight: 'rgb(255, 186, 0)', 25 | focusSecondary: 'rgb(255, 220, 128)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(255, 255, 0), rgb(255, 186, 0))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(255, 186, 0), rgb(255, 220, 128))', 30 | headerNotActiveText: 'rgb(170, 123, 0)', 31 | headerText: 'rgb(0, 0, 0)', 32 | hoverBackground: 'rgb(170, 123, 0)', 33 | material: 'rgb(255, 186, 0)', 34 | materialDark: 'rgb(255, 186, 0)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(170, 123, 0)', 37 | materialTextDisabledShadow: 'rgb(255, 220, 128)', 38 | materialTextInvert: 'rgb(255, 255, 0)', 39 | progress: 'rgb(170, 123, 0)', 40 | tooltip: 'rgb(255, 220, 128)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/hotChocolate.ts: -------------------------------------------------------------------------------- 1 | /* "Hot Chocolate" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Hot-Chocolate-654380979 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'hotChocolate', 9 | anchor: 'rgb(128, 96, 64)', 10 | anchorVisited: 'rgb(128, 96, 64)', 11 | borderDark: 'rgb(128, 96, 64)', 12 | borderDarkest: 'rgb(64, 64, 64)', 13 | borderLight: 'rgb(181, 143, 106)', 14 | borderLightest: 'rgb(219, 200, 181)', 15 | canvas: 'rgb(219, 200, 181)', 16 | canvasText: 'rgb(57, 43, 28)', 17 | canvasTextDisabled: 'rgb(128, 96, 64)', 18 | canvasTextDisabledShadow: 'rgb(219, 200, 181)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(57, 43, 28)', 21 | checkmarkDisabled: 'rgb(128, 96, 64)', 22 | desktopBackground: 'rgb(109, 82, 54)', 23 | flatDark: 'rgb(128, 96, 64)', 24 | flatLight: 'rgb(181, 143, 106)', 25 | focusSecondary: 'rgb(219, 200, 181)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(128, 96, 64), rgb(208, 183, 157))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(128, 96, 64), rgb(128, 96, 64))', 30 | headerNotActiveText: 'rgb(219, 200, 181)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(128, 96, 64)', 33 | material: 'rgb(181, 143, 106)', 34 | materialDark: 'rgb(128, 96, 64)', 35 | materialText: 'rgb(57, 43, 28)', 36 | materialTextDisabled: 'rgb(128, 96, 64)', 37 | materialTextDisabledShadow: 'rgb(219, 200, 181)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(128, 96, 64)', 40 | tooltip: 'rgb(219, 200, 181)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/hotdogStand.ts: -------------------------------------------------------------------------------- 1 | /* "Hotdog Stand" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Hotdog-Stand-525606846 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'hotdogStand', 9 | anchor: 'rgb(255, 255, 0)', 10 | anchorVisited: 'rgb(255, 255, 0)', 11 | borderDark: 'rgb(0, 0, 0)', 12 | borderDarkest: 'rgb(0, 0, 0)', 13 | borderLight: 'rgb(0, 0, 0)', 14 | borderLightest: 'rgb(0, 0, 0)', 15 | canvas: 'rgb(255, 0, 0)', 16 | canvasText: 'rgb(255, 255, 255)', 17 | canvasTextDisabled: 'rgb(0, 0, 0)', 18 | canvasTextDisabledShadow: 'rgb(0, 0, 0)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(255, 255, 255)', 21 | checkmarkDisabled: 'rgb(128, 128, 128)', 22 | desktopBackground: 'rgb(255, 255, 0)', 23 | flatDark: 'rgb(0, 0, 0)', 24 | flatLight: 'rgb(0, 0, 0)', 25 | focusSecondary: 'rgb(0, 0, 0)', 26 | headerBackground: 'linear-gradient(to right, rgb(0, 0, 0), rgb(0, 0, 0))', 27 | headerNotActiveBackground: 28 | 'linear-gradient(to right, rgb(255, 0, 0), rgb(255, 0, 0))', 29 | headerNotActiveText: 'rgb(255, 255, 255)', 30 | headerText: 'rgb(255, 255, 255)', 31 | hoverBackground: 'rgb(0, 0, 0)', 32 | material: 'rgb(255, 0, 0)', 33 | materialDark: 'rgb(255, 0, 0)', 34 | materialText: 'rgb(255, 255, 255)', 35 | materialTextDisabled: 'rgb(0, 0, 0)', 36 | materialTextDisabledShadow: 'rgb(0, 0, 0)', 37 | materialTextInvert: 'rgb(255, 255, 255)', 38 | progress: 'rgb(0, 0, 0)', 39 | tooltip: 'rgb(255, 255, 225)' 40 | } as Theme; 41 | -------------------------------------------------------------------------------- /src/common/themes/lilac.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'lilac', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#5f549b', 9 | borderDarkest: '#1c1449', 10 | borderLight: '#bcb4e9', 11 | borderLightest: '#d3ccf4', 12 | canvas: '#ffffff', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#5f549b', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#5f549b', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#5e4dba', 24 | headerNotActiveBackground: '#7f7f81', 25 | headerNotActiveText: '#ced0cf', 26 | headerText: '#ffffff', 27 | hoverBackground: '#5e4dba', 28 | material: '#b1a7df', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#5f549b', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#5e4dba', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/lilacRoseDark.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'lilacRoseDark', 5 | 6 | anchor: '#a65387', 7 | anchorVisited: '#440381', 8 | background: '#3B3B58', 9 | borderDark: '#7F3163', 10 | borderDarkest: '#190000', 11 | borderLight: '#E597C9', 12 | borderLightest: '#FFCAFC', 13 | canvas: '#dab1c7', 14 | canvasText: '#000000', 15 | canvasTextDisabled: '#000000', 16 | canvasTextDisabledShadow: '#000000', 17 | canvasTextInvert: '#ecbfe3', 18 | checkmark: '#010601', 19 | checkmarkDisabled: '#7F3163', 20 | desktopBackground: '#663956', 21 | flatDark: '#7F3163', 22 | flatLight: '#E597C9', 23 | focusSecondary: '#fefe03', 24 | headerBackground: '#4C0030', 25 | headerNotActiveBackground: '#763a60', 26 | headerNotActiveText: '#b26496', 27 | headerText: '#010601', 28 | hoverBackground: '#713259', 29 | material: '#b26496', 30 | materialDark: '#763a60', 31 | materialText: '#000000', 32 | materialTextDisabled: '#82416d', 33 | materialTextDisabledShadow: '#ecbfe3', 34 | materialTextInvert: '#ecbfe3', 35 | progress: '#713259', 36 | tooltip: '#fefbcc' 37 | } as Theme; 38 | -------------------------------------------------------------------------------- /src/common/themes/maple.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'maple', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#ab9042', 9 | borderDarkest: '#2a1801', 10 | borderLight: '#f5e2bb', 11 | borderLightest: '#ffffff', 12 | canvas: '#ffffff', 13 | canvasText: '#2a1801', 14 | canvasTextDisabled: '#ab9042', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#2a1801', 18 | checkmarkDisabled: '#ab9042', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#8e0101', 24 | headerNotActiveBackground: '#a1a0a5', 25 | headerNotActiveText: '#f5e2bb', 26 | headerText: '#ffffff', 27 | hoverBackground: '#8e0101', 28 | material: '#e5cc90', 29 | materialDark: '#9a9e9c', 30 | materialText: '#2a1801', 31 | materialTextDisabled: '#ab9042', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#8e0101', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/marine.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'marine', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#3c8d88', 9 | borderDarkest: '#050608', 10 | borderLight: '#98d2cb', 11 | borderLightest: '#b1dfdf', 12 | canvas: '#c3e2da', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#3c8d88', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#3c8d88', 19 | desktopBackground: '#2c4e47', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#000080', 24 | headerNotActiveBackground: '#7f7f7f', 25 | headerNotActiveText: '#ced0cf', 26 | headerText: '#ffffff', 27 | hoverBackground: '#000080', 28 | material: '#75c1ba', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#3c8d88', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#000080', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/matrix.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'matrix', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#282828', 9 | borderDarkest: '#000000', 10 | borderLight: '#656565', 11 | borderLightest: '#a7a7a7', 12 | canvas: '#c0c0c0', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#282828', 15 | canvasTextDisabledShadow: '#ff0000', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#282828', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#35FF69', 23 | headerBackground: '#000000', 24 | headerNotActiveBackground: '#7f7f7f', 25 | headerNotActiveText: '#535353', 26 | headerText: '#a7a7a7', 27 | hoverBackground: '#000000', 28 | material: '#535353', 29 | materialDark: '#282828', 30 | materialText: '#35FF69', 31 | materialTextDisabled: '#282828', 32 | materialTextDisabledShadow: '#a7a7a7', 33 | materialTextInvert: '#ffffff', 34 | progress: '#000000', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/millenium.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'millenium', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#828282', 9 | borderDarkest: 'black', 10 | borderLight: '#e5e5e5', 11 | borderLightest: '#ffffff', 12 | canvas: '#ffffff', 13 | canvasText: 'black', 14 | canvasTextDisabled: '#828282', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: 'black', 18 | checkmarkDisabled: '#828282', 19 | desktopBackground: '#3a6ea5', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: 'linear-gradient(to right, #012470, #a5c7e7)', 24 | headerNotActiveBackground: '#7f7f7f', 25 | headerNotActiveText: '#d6cfc7', 26 | headerText: '#ffffff', 27 | hoverBackground: '#00256e', 28 | material: '#d6cfc7', 29 | materialDark: '#9a9e9c', 30 | materialText: 'black', 31 | materialTextDisabled: '#828282', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#00256e', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/modernDark.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'modernDark', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#121317', 9 | borderDarkest: '#000000', 10 | borderLight: '#31323c', 11 | borderLightest: '#4b4d58', 12 | canvas: '#4b4d58', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#4b4d58', 15 | canvasTextDisabledShadow: '#4b4d58', 16 | canvasTextInvert: '#202127', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#121317', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#4b4d58', 24 | headerNotActiveBackground: 'transparent', 25 | headerNotActiveText: '#4b4d58', 26 | headerText: '#202127', 27 | hoverBackground: '#f88702', 28 | material: '#202127', 29 | materialDark: '#9a9e9c', 30 | materialText: '#f88702', 31 | materialTextDisabled: '#4b4d58', 32 | materialTextDisabledShadow: '#121317', 33 | materialTextInvert: '#202127', 34 | progress: '#f88702', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/molecule.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'molecule', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#993845', 9 | borderDarkest: '#4b4d4e', 10 | borderLight: '#dfe0e3', 11 | borderLightest: '#d79099', 12 | canvas: '#f1f5f6', 13 | canvasText: '#020102', 14 | canvasTextDisabled: '#993845', 15 | canvasTextDisabledShadow: '#d79099', 16 | canvasTextInvert: '#f1f5f6', 17 | checkmark: '#020102', 18 | checkmarkDisabled: '#993845', 19 | desktopBackground: '#3a6ea5', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#a03d49', 24 | headerNotActiveBackground: '#7f7f7f', 25 | headerNotActiveText: '#c2c1c2', 26 | headerText: '#f1f5f6', 27 | hoverBackground: '#70a3ce', 28 | material: '#c2c1c2', 29 | materialDark: '#9a9e9c', 30 | materialText: '#020102', 31 | materialTextDisabled: '#993845', 32 | materialTextDisabledShadow: '#d79099', 33 | materialTextInvert: '#f1f5f6', 34 | progress: '#a03d49', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/monochrome.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react95-io/React95/871d5335daebdda1469f66f81266523f4191a595/src/common/themes/monochrome.ts -------------------------------------------------------------------------------- /src/common/themes/ninjaTurtles.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'ninjaTurtles', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#017401', 9 | borderDarkest: '#000000', 10 | borderLight: '#1dbc1b', 11 | borderLightest: '#55fd55', 12 | canvas: '#ffffff', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#017401', 15 | canvasTextDisabledShadow: '#55fd55', 16 | canvasTextInvert: '#000000', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#017401', 19 | desktopBackground: '#045424', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#FF1D15', 24 | headerNotActiveBackground: '#7f7f7f', 25 | headerNotActiveText: '#000000', 26 | headerText: '#ffffff', 27 | hoverBackground: '#FABC3C', 28 | material: '#00a800', 29 | materialDark: '#9a9e9c', 30 | materialText: '#000000', 31 | materialTextDisabled: '#017401', 32 | materialTextDisabledShadow: '#55fd55', 33 | materialTextInvert: '#000000', 34 | progress: '#FF1D15', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/olive.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'olive', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#4f4c02', 9 | borderDarkest: '#000000', 10 | borderLight: '#9d9d11', 11 | borderLightest: '#fcfd3e', 12 | canvas: '#ffffff', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#4f4c02', 15 | canvasTextDisabledShadow: '#fcfd3e', 16 | canvasTextInvert: '#000000', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#4f4c02', 19 | desktopBackground: '#666633', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#000000', 23 | headerBackground: '#F3DE2C', 24 | headerNotActiveBackground: '#4f4c02', 25 | headerNotActiveText: '#807f00', 26 | headerText: '#000000', 27 | hoverBackground: '#F3DE2C', 28 | material: '#807f00', 29 | materialDark: '#4f4c02', 30 | materialText: '#000000', 31 | materialTextDisabled: '#4f4c02', 32 | materialTextDisabledShadow: '#fcfd3e', 33 | materialTextInvert: '#000000', 34 | progress: '#F3DE2C', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/original.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'original', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#848584', 9 | borderDarkest: '#0a0a0a', 10 | borderLight: '#dfdfdf', 11 | borderLightest: '#fefefe', 12 | canvas: '#ffffff', 13 | canvasText: '#0a0a0a', 14 | canvasTextDisabled: '#848584', 15 | canvasTextDisabledShadow: '#fefefe', 16 | canvasTextInvert: '#fefefe', 17 | checkmark: '#0a0a0a', 18 | checkmarkDisabled: '#848584', 19 | desktopBackground: '#008080', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#060084', 24 | headerNotActiveBackground: '#7f787f', 25 | headerNotActiveText: '#c6c6c6', 26 | headerText: '#fefefe', 27 | hoverBackground: '#060084', 28 | material: '#c6c6c6', 29 | materialDark: '#9a9e9c', 30 | materialText: '#0a0a0a', 31 | materialTextDisabled: '#848584', 32 | materialTextDisabledShadow: '#fefefe', 33 | materialTextInvert: '#fefefe', 34 | progress: '#060084', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/pamelaAnderson.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'pamelaAnderson', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#7e0541', 9 | borderDarkest: '#000000', 10 | borderLight: '#ff308f', 11 | borderLightest: '#ff7ebf', 12 | canvas: '#F5CCE8', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#7e0541', 15 | canvasTextDisabledShadow: '#ff7ebf', 16 | canvasTextInvert: '#F1E4E8', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#7e0541', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#FF8CC6', 24 | headerNotActiveBackground: '#95818D', 25 | headerNotActiveText: '#ff0080', 26 | headerText: '#000000', 27 | hoverBackground: '#004FFF', 28 | material: '#ff0080', 29 | materialDark: '#95818D', 30 | materialText: '#000000', 31 | materialTextDisabled: '#7e0541', 32 | materialTextDisabledShadow: '#ff7ebf', 33 | materialTextInvert: '#F1E4E8', 34 | progress: '#004FFF', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/peggysPastels.ts: -------------------------------------------------------------------------------- 1 | /* "Peggy's Pastels" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Peggy-s-Pastels-505540096 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'peggysPastels', 9 | anchor: 'rgb(0, 128, 128)', 10 | anchorVisited: 'rgb(0, 128, 128)', 11 | borderDark: 'rgb(222, 69, 96)', 12 | borderDarkest: 'rgb(64, 64, 64)', 13 | borderLight: 'rgb(247, 219, 215)', 14 | borderLightest: 'rgb(250, 224, 228)', 15 | canvas: 'rgb(244, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(222, 69, 96)', 18 | canvasTextDisabledShadow: 'rgb(250, 224, 228)', 19 | canvasTextInvert: 'rgb(0, 0, 0)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(222, 69, 96)', 22 | desktopBackground: 'rgb(162, 219, 210)', 23 | flatDark: 'rgb(222, 69, 96)', 24 | flatLight: 'rgb(247, 219, 215)', 25 | focusSecondary: 'rgb(250, 224, 228)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(0, 191, 188), rgb(202, 156, 185))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(0, 187, 169), rgb(236, 145, 162))', 30 | headerNotActiveText: 'rgb(0, 85, 77)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(162, 219, 210)', 33 | material: 'rgb(244, 193, 202)', 34 | materialDark: 'rgb(0, 187, 169)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(222, 69, 96)', 37 | materialTextDisabledShadow: 'rgb(250, 224, 228)', 38 | materialTextInvert: 'rgb(0, 0, 0)', 39 | progress: 'rgb(162, 219, 210)', 40 | tooltip: 'rgb(204, 255, 255)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/plum.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'plum', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#7b5f5b', 9 | borderDarkest: '#050608', 10 | borderLight: '#c3b1aa', 11 | borderLightest: '#e8dad6', 12 | canvas: '#dad0c7', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#7b5f5b', 15 | canvasTextDisabledShadow: '#e8dad6', 16 | canvasTextInvert: '#e8dad6', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#7b5f5b', 19 | desktopBackground: '#402840', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#483f63', 24 | headerNotActiveBackground: '#7d5e58', 25 | headerNotActiveText: '#e8dad6', 26 | headerText: '#ffffff', 27 | hoverBackground: '#483f63', 28 | material: '#ac978f', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#7b5f5b', 32 | materialTextDisabledShadow: '#e8dad6', 33 | materialTextInvert: '#ffffff', 34 | progress: '#483f63', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/polarized.ts: -------------------------------------------------------------------------------- 1 | /* "Polarized" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Polarized-557712217 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'polarized', 9 | anchor: 'rgb(160, 160, 128)', 10 | anchorVisited: 'rgb(160, 160, 128)', 11 | borderDark: 'rgb(60, 60, 194)', 12 | borderDarkest: 'rgb(60, 60, 194)', 13 | borderLight: 'rgb(60, 60, 194)', 14 | borderLightest: 'rgb(60, 60, 194)', 15 | canvas: 'rgb(52, 52, 204)', 16 | canvasText: 'rgb(255, 255, 0)', 17 | canvasTextDisabled: 'rgb(60, 60, 194)', 18 | canvasTextDisabledShadow: 'rgb(60, 60, 194)', 19 | canvasTextInvert: 'rgb(0, 0, 255)', 20 | checkmark: 'rgb(255, 255, 0)', 21 | checkmarkDisabled: 'rgb(101, 101, 154)', 22 | desktopBackground: 'rgb(180, 180, 76)', 23 | flatDark: 'rgb(60, 60, 194)', 24 | flatLight: 'rgb(60, 60, 194)', 25 | focusSecondary: 'rgb(60, 60, 194)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(192, 192, 64), rgb(192, 192, 64))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(64, 64, 192), rgb(170, 170, 84))', 30 | headerNotActiveText: 'rgb(192, 192, 192)', 31 | headerText: 'rgb(0, 0, 255)', 32 | hoverBackground: 'rgb(192, 192, 64)', 33 | material: 'rgb(120, 120, 136)', 34 | materialDark: 'rgb(64, 64, 192)', 35 | materialText: 'rgb(255, 255, 0)', 36 | materialTextDisabled: 'rgb(60, 60, 194)', 37 | materialTextDisabledShadow: 'rgb(60, 60, 194)', 38 | materialTextInvert: 'rgb(0, 0, 255)', 39 | progress: 'rgb(192, 192, 64)', 40 | tooltip: 'rgb(16, 16, 240)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/powerShell.ts: -------------------------------------------------------------------------------- 1 | /* "PowerShell" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/PowerShell-646065752 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'powerShell', 9 | anchor: 'rgb(0, 192, 0)', 10 | anchorVisited: 'rgb(0, 192, 0)', 11 | borderDark: 'rgb(128, 128, 128)', 12 | borderDarkest: 'rgb(128, 128, 128)', 13 | borderLight: 'rgb(128, 128, 128)', 14 | borderLightest: 'rgb(128, 128, 128)', 15 | canvas: 'rgb(1, 36, 86)', 16 | canvasText: 'rgb(238, 237, 240)', 17 | canvasTextDisabled: 'rgb(128, 128, 128)', 18 | canvasTextDisabledShadow: 'rgb(128, 128, 128)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(238, 237, 240)', 21 | checkmarkDisabled: 'rgb(180, 180, 180)', 22 | desktopBackground: 'rgb(1, 36, 86)', 23 | flatDark: 'rgb(128, 128, 128)', 24 | flatLight: 'rgb(128, 128, 128)', 25 | focusSecondary: 'rgb(128, 128, 128)', 26 | headerBackground: 'linear-gradient(to right, rgb(1, 36, 86), rgb(1, 36, 86))', 27 | headerNotActiveBackground: 28 | 'linear-gradient(to right, rgb(1, 36, 86), rgb(1, 36, 86))', 29 | headerNotActiveText: 'rgb(192, 192, 192)', 30 | headerText: 'rgb(255, 255, 255)', 31 | hoverBackground: 'rgb(0, 128, 128)', 32 | material: 'rgb(1, 36, 86)', 33 | materialDark: 'rgb(1, 36, 86)', 34 | materialText: 'rgb(255, 255, 255)', 35 | materialTextDisabled: 'rgb(128, 128, 128)', 36 | materialTextDisabledShadow: 'rgb(128, 128, 128)', 37 | materialTextInvert: 'rgb(255, 255, 255)', 38 | progress: 'rgb(0, 128, 128)', 39 | tooltip: 'rgb(255, 255, 225)' 40 | } as Theme; 41 | -------------------------------------------------------------------------------- /src/common/themes/rainyDay.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'rainyDay', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#3d5367', 9 | borderDarkest: '#16233b', 10 | borderLight: '#91abc2', 11 | borderLightest: '#b7cee5', 12 | canvas: '#ffffff', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#3d5367', 15 | canvasTextDisabledShadow: '#b7cee5', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#3d5367', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#4b6480', 24 | headerNotActiveBackground: '#7f7f81', 25 | headerNotActiveText: '#ced0d9', 26 | headerText: '#ffffff', 27 | hoverBackground: '#4b6480', 28 | material: '#7a99b3', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#3d5367', 32 | materialTextDisabledShadow: '#b7cee5', 33 | materialTextInvert: '#ffffff', 34 | progress: '#4b6480', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/raspberry.ts: -------------------------------------------------------------------------------- 1 | /* "Raspberry" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Raspberry-539289720 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'raspberry', 9 | anchor: 'rgb(10, 36, 106)', 10 | anchorVisited: 'rgb(10, 36, 106)', 11 | borderDark: 'rgb(92, 101, 107)', 12 | borderDarkest: 'rgb(64, 64, 64)', 13 | borderLight: 'rgb(142, 151, 157)', 14 | borderLightest: 'rgb(200, 204, 206)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(92, 101, 107)', 18 | canvasTextDisabledShadow: 'rgb(200, 204, 206)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(92, 101, 107)', 22 | desktopBackground: 'rgb(0, 64, 128)', 23 | flatDark: 'rgb(92, 101, 107)', 24 | flatLight: 'rgb(142, 151, 157)', 25 | focusSecondary: 'rgb(200, 204, 206)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(10, 36, 106), rgb(153, 0, 51))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(92, 101, 107), rgb(92, 101, 107))', 30 | headerNotActiveText: 'rgb(212, 208, 200)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(10, 36, 106)', 33 | material: 'rgb(142, 151, 157)', 34 | materialDark: 'rgb(92, 101, 107)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(92, 101, 107)', 37 | materialTextDisabledShadow: 'rgb(200, 204, 206)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(10, 36, 106)', 40 | tooltip: 'rgb(255, 255, 225)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/redWine.ts: -------------------------------------------------------------------------------- 1 | /* "Red Wine" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Red-Wine-545729607 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'redWine', 9 | anchor: 'rgb(255, 0, 0)', 10 | anchorVisited: 'rgb(255, 0, 0)', 11 | borderDark: 'rgb(67, 9, 5)', 12 | borderDarkest: 'rgb(64, 32, 32)', 13 | borderLight: 'rgb(102, 12, 8)', 14 | borderLightest: 'rgb(192, 64, 56)', 15 | canvas: 'rgb(64, 0, 0)', 16 | canvasText: 'rgb(255, 255, 255)', 17 | canvasTextDisabled: 'rgb(67, 9, 5)', 18 | canvasTextDisabledShadow: 'rgb(192, 64, 56)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(255, 255, 255)', 21 | checkmarkDisabled: 'rgb(192, 64, 64)', 22 | desktopBackground: 'rgb(147, 9, 0)', 23 | flatDark: 'rgb(67, 9, 5)', 24 | flatLight: 'rgb(102, 12, 8)', 25 | focusSecondary: 'rgb(192, 64, 56)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(64, 0, 12), rgb(217, 11, 0))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(0, 0, 0), rgb(134, 4, 2))', 30 | headerNotActiveText: 'rgb(239, 44, 33)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(192, 0, 0)', 33 | material: 'rgb(102, 12, 8)', 34 | materialDark: 'rgb(0, 0, 0)', 35 | materialText: 'rgb(255, 255, 255)', 36 | materialTextDisabled: 'rgb(67, 9, 5)', 37 | materialTextDisabledShadow: 'rgb(192, 64, 56)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(192, 0, 0)', 40 | tooltip: 'rgb(64, 0, 0)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/rose.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'rose', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#8a5b68', 9 | borderDarkest: '#26030b', 10 | borderLight: '#e5bec8', 11 | borderLightest: '#f1d4dc', 12 | canvas: '#ffffff', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#8a5b68', 15 | canvasTextDisabledShadow: '#f1d4dc', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#8a5b68', 19 | desktopBackground: '#808080', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#ab5a71', 24 | headerNotActiveBackground: '#a19fa5', 25 | headerNotActiveText: '#615f68', 26 | headerText: '#ffffff', 27 | hoverBackground: '#ab5a71', 28 | material: '#d6adb8', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#8a5b68', 32 | materialTextDisabledShadow: '#f1d4dc', 33 | materialTextInvert: '#ffffff', 34 | progress: '#ab5a71', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/seawater.ts: -------------------------------------------------------------------------------- 1 | /* "Seawater" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Seawater-736002425 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'seawater', 9 | anchor: 'rgb(0, 0, 128)', 10 | anchorVisited: 'rgb(0, 0, 128)', 11 | borderDark: 'rgb(167, 194, 224)', 12 | borderDarkest: 'rgb(167, 194, 224)', 13 | borderLight: 'rgb(167, 194, 224)', 14 | borderLightest: 'rgb(167, 194, 224)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(167, 194, 224)', 18 | canvasTextDisabledShadow: 'rgb(167, 194, 224)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(47, 88, 134)', 22 | desktopBackground: 'rgb(0, 128, 128)', 23 | flatDark: 'rgb(167, 194, 224)', 24 | flatLight: 'rgb(167, 194, 224)', 25 | focusSecondary: 'rgb(167, 194, 224)', 26 | headerBackground: 'linear-gradient(to right, rgb(0, 0, 128), rgb(0, 0, 128))', 27 | headerNotActiveBackground: 28 | 'linear-gradient(to right, rgb(0, 85, 170), rgb(0, 85, 170))', 29 | headerNotActiveText: 'rgb(192, 192, 192)', 30 | headerText: 'rgb(255, 255, 255)', 31 | hoverBackground: 'rgb(0, 128, 128)', 32 | material: 'rgb(79, 133, 193)', 33 | materialDark: 'rgb(0, 85, 170)', 34 | materialText: 'rgb(0, 0, 0)', 35 | materialTextDisabled: 'rgb(167, 194, 224)', 36 | materialTextDisabledShadow: 'rgb(167, 194, 224)', 37 | materialTextInvert: 'rgb(255, 255, 255)', 38 | progress: 'rgb(0, 128, 128)', 39 | tooltip: 'rgb(255, 255, 225)' 40 | } as Theme; 41 | -------------------------------------------------------------------------------- /src/common/themes/shelbiTeal.ts: -------------------------------------------------------------------------------- 1 | /* "Teal for Shelbi" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Teal-for-Shelbi-506118460 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'shelbiTeal', 9 | anchor: 'rgb(0, 128, 128)', 10 | anchorVisited: 'rgb(0, 128, 128)', 11 | borderDark: 'rgb(96, 128, 128)', 12 | borderDarkest: 'rgb(0, 0, 0)', 13 | borderLight: 'rgb(192, 204, 204)', 14 | borderLightest: 'rgb(204, 224, 224)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(96, 128, 128)', 18 | canvasTextDisabledShadow: 'rgb(204, 224, 224)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(96, 128, 128)', 22 | desktopBackground: 'rgb(0, 128, 128)', 23 | flatDark: 'rgb(96, 128, 128)', 24 | flatLight: 'rgb(192, 204, 204)', 25 | focusSecondary: 'rgb(204, 224, 224)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(0, 128, 128), rgb(0, 204, 204))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(96, 128, 128), rgb(160, 192, 192))', 30 | headerNotActiveText: 'rgb(192, 204, 204)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(0, 128, 128)', 33 | material: 'rgb(168, 192, 192)', 34 | materialDark: 'rgb(96, 128, 128)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(96, 128, 128)', 37 | materialTextDisabledShadow: 'rgb(204, 224, 224)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(0, 128, 128)', 40 | tooltip: 'rgb(224, 255, 255)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/slate.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'slate', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#446b7c', 9 | borderDarkest: '#000814', 10 | borderLight: '#adc8da', 11 | borderLightest: '#c3d9e9', 12 | canvas: '#f2ffff', 13 | canvasText: '#00010f', 14 | canvasTextDisabled: '#446b7c', 15 | canvasTextDisabledShadow: '#c3d9e9', 16 | canvasTextInvert: '#f2ffff', 17 | checkmark: '#00010f', 18 | checkmarkDisabled: '#446b7c', 19 | desktopBackground: '#414141', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#448199', 24 | headerNotActiveBackground: '#807f80', 25 | headerNotActiveText: '#c2c1c2', 26 | headerText: '#f2ffff', 27 | hoverBackground: '#448199', 28 | material: '#97b9cb', 29 | materialDark: '#9a9e9c', 30 | materialText: '#00010f', 31 | materialTextDisabled: '#446b7c', 32 | materialTextDisabledShadow: '#c3d9e9', 33 | materialTextInvert: '#f2ffff', 34 | progress: '#448199', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/solarizedDark.ts: -------------------------------------------------------------------------------- 1 | /* "Solarized Dark" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Solarized-Dark-592122068 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'solarizedDark', 9 | anchor: 'rgb(38, 139, 210)', 10 | anchorVisited: 'rgb(38, 139, 210)', 11 | borderDark: 'rgb(0, 43, 54)', 12 | borderDarkest: 'rgb(0, 43, 54)', 13 | borderLight: 'rgb(0, 43, 54)', 14 | borderLightest: 'rgb(0, 43, 54)', 15 | canvas: 'rgb(0, 43, 54)', 16 | canvasText: 'rgb(131, 148, 150)', 17 | canvasTextDisabled: 'rgb(0, 43, 54)', 18 | canvasTextDisabledShadow: 'rgb(0, 43, 54)', 19 | canvasTextInvert: 'rgb(238, 232, 213)', 20 | checkmark: 'rgb(131, 148, 150)', 21 | checkmarkDisabled: 'rgb(88, 110, 117)', 22 | desktopBackground: 'rgb(0, 43, 54)', 23 | flatDark: 'rgb(0, 43, 54)', 24 | flatLight: 'rgb(0, 43, 54)', 25 | focusSecondary: 'rgb(0, 43, 54)', 26 | headerBackground: 'linear-gradient(to right, rgb(0, 43, 54), rgb(0, 43, 54))', 27 | headerNotActiveBackground: 28 | 'linear-gradient(to right, rgb(7, 54, 66), rgb(7, 54, 66))', 29 | headerNotActiveText: 'rgb(131, 148, 150)', 30 | headerText: 'rgb(108, 113, 196)', 31 | hoverBackground: 'rgb(211, 54, 130)', 32 | material: 'rgb(7, 54, 66)', 33 | materialDark: 'rgb(7, 54, 66)', 34 | materialText: 'rgb(131, 148, 150)', 35 | materialTextDisabled: 'rgb(0, 43, 54)', 36 | materialTextDisabledShadow: 'rgb(0, 43, 54)', 37 | materialTextInvert: 'rgb(238, 232, 213)', 38 | progress: 'rgb(211, 54, 130)', 39 | tooltip: 'rgb(253, 246, 227)' 40 | } as Theme; 41 | -------------------------------------------------------------------------------- /src/common/themes/solarizedLight.ts: -------------------------------------------------------------------------------- 1 | /* "Solarized Light" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Solarized-Light-592124935 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'solarizedLight', 9 | anchor: 'rgb(38, 139, 210)', 10 | anchorVisited: 'rgb(38, 139, 210)', 11 | borderDark: 'rgb(253, 246, 227)', 12 | borderDarkest: 'rgb(253, 246, 227)', 13 | borderLight: 'rgb(253, 246, 227)', 14 | borderLightest: 'rgb(253, 246, 227)', 15 | canvas: 'rgb(253, 246, 227)', 16 | canvasText: 'rgb(101, 123, 131)', 17 | canvasTextDisabled: 'rgb(253, 246, 227)', 18 | canvasTextDisabledShadow: 'rgb(253, 246, 227)', 19 | canvasTextInvert: 'rgb(238, 232, 213)', 20 | checkmark: 'rgb(101, 123, 131)', 21 | checkmarkDisabled: 'rgb(88, 110, 117)', 22 | desktopBackground: 'rgb(253, 246, 227)', 23 | flatDark: 'rgb(253, 246, 227)', 24 | flatLight: 'rgb(253, 246, 227)', 25 | focusSecondary: 'rgb(253, 246, 227)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(253, 246, 227), rgb(253, 246, 227))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(238, 232, 213), rgb(238, 232, 213))', 30 | headerNotActiveText: 'rgb(101, 123, 131)', 31 | headerText: 'rgb(108, 113, 196)', 32 | hoverBackground: 'rgb(211, 54, 130)', 33 | material: 'rgb(238, 232, 213)', 34 | materialDark: 'rgb(238, 232, 213)', 35 | materialText: 'rgb(101, 123, 131)', 36 | materialTextDisabled: 'rgb(253, 246, 227)', 37 | materialTextDisabledShadow: 'rgb(253, 246, 227)', 38 | materialTextInvert: 'rgb(238, 232, 213)', 39 | progress: 'rgb(211, 54, 130)', 40 | tooltip: 'rgb(253, 246, 227)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/spruce.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'spruce', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#477b5e', 9 | borderDarkest: '#001004', 10 | borderLight: '#b0d2bb', 11 | borderLightest: '#cdead2', 12 | canvas: '#fcfff6', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#3d5367', 15 | canvasTextDisabledShadow: '#cdead2', 16 | canvasTextInvert: '#fcfff6', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#477b5e', 19 | desktopBackground: '#213f21', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#3d9961', 24 | headerNotActiveBackground: '#807f80', 25 | headerNotActiveText: '#d4deda', 26 | headerText: '#fcfff6', 27 | hoverBackground: '#3d9961', 28 | material: '#99c9a8', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#3d5367', 32 | materialTextDisabledShadow: '#cdead2', 33 | materialTextInvert: '#fcfff6', 34 | progress: '#3d9961', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/stormClouds.ts: -------------------------------------------------------------------------------- 1 | /* "Storm Clouds" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Storm-Clouds-613198674 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'stormClouds', 9 | anchor: 'rgb(64, 64, 255)', 10 | anchorVisited: 'rgb(64, 64, 255)', 11 | borderDark: 'rgb(47, 52, 53)', 12 | borderDarkest: 'rgb(0, 0, 0)', 13 | borderLight: 'rgb(70, 80, 81)', 14 | borderLightest: 'rgb(159, 171, 172)', 15 | canvas: 'rgb(47, 52, 53)', 16 | canvasText: 'rgb(255, 255, 255)', 17 | canvasTextDisabled: 'rgb(47, 52, 53)', 18 | canvasTextDisabledShadow: 'rgb(159, 171, 172)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(255, 255, 255)', 21 | checkmarkDisabled: 'rgb(128, 128, 128)', 22 | desktopBackground: 'rgb(45, 87, 87)', 23 | flatDark: 'rgb(47, 52, 53)', 24 | flatLight: 'rgb(70, 80, 81)', 25 | focusSecondary: 'rgb(159, 171, 172)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(0, 0, 168), rgb(16, 132, 208))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(47, 52, 53), rgb(128, 128, 128))', 30 | headerNotActiveText: 'rgb(192, 199, 200)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(128, 128, 0)', 33 | material: 'rgb(70, 80, 81)', 34 | materialDark: 'rgb(47, 52, 53)', 35 | materialText: 'rgb(255, 255, 255)', 36 | materialTextDisabled: 'rgb(47, 52, 53)', 37 | materialTextDisabledShadow: 'rgb(159, 171, 172)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(128, 128, 0)', 40 | tooltip: 'rgb(48, 64, 80)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/theSixtiesUSA.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'theSixtiesUSA', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#6c1f71', 9 | borderDarkest: '#010001', 10 | borderLight: '#d982de', 11 | borderLightest: '#df9be7', 12 | canvas: '#ffffff', 13 | canvasText: '#010001', 14 | canvasTextDisabled: '#6c1f71', 15 | canvasTextDisabledShadow: '#df9be7', 16 | canvasTextInvert: '#010001', 17 | checkmark: '#010001', 18 | checkmarkDisabled: '#6c1f71', 19 | desktopBackground: '#92458a', // original: #000000 20 | flatDark: '#d067d7', 21 | flatLight: '#df9be7', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#050080', 24 | headerNotActiveBackground: '#a130a9', 25 | headerNotActiveText: '#df9be7', 26 | headerText: '#ffffff', 27 | hoverBackground: '#0f0', 28 | material: '#d067d7', 29 | materialDark: '#9a9e9c', 30 | materialText: '#010001', 31 | materialTextDisabled: '#6c1f71', 32 | materialTextDisabledShadow: '#df9be7', 33 | materialTextInvert: '#010001', 34 | progress: '#0f0', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/tokyoDark.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'tokyoDark', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#1f2223', 9 | borderDarkest: '#070809', 10 | borderLight: '#5e696a', 11 | borderLightest: '#93a0a1', 12 | canvas: '#2f3435', 13 | canvasText: '#F4F4ED', 14 | canvasTextDisabled: '#1f2223', 15 | canvasTextDisabledShadow: '#93a0a1', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#F4F4ED', 18 | checkmarkDisabled: '#1f2223', 19 | desktopBackground: '#181a1b', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#20FC8F', 23 | headerBackground: '#1f2223', 24 | headerNotActiveBackground: '#5e696a', 25 | headerNotActiveText: '#F4F4ED', 26 | headerText: '#F4F4ED', 27 | hoverBackground: '#F61067', 28 | material: '#465051', 29 | materialDark: '#1f2223', 30 | materialText: '#F4F4ED', 31 | materialTextDisabled: '#1f2223', 32 | materialTextDisabledShadow: '#93a0a1', 33 | materialTextInvert: '#ffffff', 34 | progress: '#F61067', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/toner.ts: -------------------------------------------------------------------------------- 1 | /* "Toner" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Toner-871968986 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'toner', 9 | anchor: 'rgb(0, 0, 128)', 10 | anchorVisited: 'rgb(0, 0, 128)', 11 | borderDark: 'rgb(0, 0, 0)', 12 | borderDarkest: 'rgb(128, 128, 128)', 13 | borderLight: 'rgb(0, 0, 0)', 14 | borderLightest: 'rgb(127, 127, 127)', 15 | canvas: 'rgb(128, 128, 128)', 16 | canvasText: 'rgb(255, 255, 255)', 17 | canvasTextDisabled: 'rgb(0, 0, 0)', 18 | canvasTextDisabledShadow: 'rgb(127, 127, 127)', 19 | canvasTextInvert: 'rgb(0, 0, 0)', 20 | checkmark: 'rgb(255, 255, 255)', 21 | checkmarkDisabled: 'rgb(64, 64, 64)', 22 | desktopBackground: 'rgb(128, 128, 128)', 23 | flatDark: 'rgb(0, 0, 0)', 24 | flatLight: 'rgb(0, 0, 0)', 25 | focusSecondary: 'rgb(127, 127, 127)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(128, 128, 128), rgb(128, 128, 128))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(0, 0, 0), rgb(128, 128, 128))', 30 | headerNotActiveText: 'rgb(128, 128, 128)', 31 | headerText: 'rgb(0, 0, 0)', 32 | hoverBackground: 'rgb(255, 255, 255)', 33 | material: 'rgb(0, 0, 0)', 34 | materialDark: 'rgb(0, 0, 0)', 35 | materialText: 'rgb(255, 255, 255)', 36 | materialTextDisabled: 'rgb(0, 0, 0)', 37 | materialTextDisabledShadow: 'rgb(127, 127, 127)', 38 | materialTextInvert: 'rgb(0, 0, 0)', 39 | progress: 'rgb(255, 255, 255)', 40 | tooltip: 'rgb(128, 128, 128)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/tooSexy.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'tooSexy', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#5a0302', 9 | borderDarkest: '#000000', 10 | borderLight: '#c81d19', 11 | borderLightest: '#fe5757', 12 | canvas: '#FFF1D0', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#5a0302', 15 | canvasTextDisabledShadow: '#FFF1D0', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#5a0302', 19 | desktopBackground: '#000000', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#161B33', 24 | headerNotActiveBackground: '#5a0302', 25 | headerNotActiveText: '#B80100', 26 | headerText: '#FFF1D0', 27 | hoverBackground: '#474973', 28 | material: '#B80100', 29 | materialDark: '#9a9e9c', 30 | materialText: '#000000', 31 | materialTextDisabled: '#5a0302', 32 | materialTextDisabledShadow: '#fe5757', 33 | materialTextInvert: '#ffffff', 34 | progress: '#474973', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/travel.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'travel', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#695f50', 9 | borderDarkest: '#28251e', 10 | borderLight: '#9d8f80', 11 | borderLightest: '#baae9f', 12 | canvas: '#d8d0c8', 13 | canvasText: '#28251e', 14 | canvasTextDisabled: '#695f50', 15 | canvasTextDisabledShadow: '#baae9f', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#28251e', 18 | checkmarkDisabled: '#695f50', 19 | desktopBackground: '#7c654c', // original: #000000 20 | flatDark: '#695f50', 21 | flatLight: '#9d8f80', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#404878', 24 | headerNotActiveBackground: '#605848', 25 | headerNotActiveText: '#908070', 26 | headerText: '#d8d0c8', 27 | hoverBackground: '#48604f', 28 | material: '#908070', 29 | materialDark: '#9a9e9c', 30 | materialText: '#28251e', 31 | materialTextDisabled: '#695f50', 32 | materialTextDisabledShadow: '#baae9f', 33 | materialTextInvert: '#ffffff', 34 | progress: '#48604f', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/types.ts: -------------------------------------------------------------------------------- 1 | export type Color = string; 2 | 3 | export type Theme = { 4 | name: string; 5 | anchor: Color; 6 | anchorVisited: Color; 7 | borderDark: Color; 8 | borderDarkest: Color; 9 | borderLight: Color; 10 | borderLightest: Color; 11 | canvas: Color; 12 | canvasText: Color; 13 | canvasTextDisabled: Color; 14 | canvasTextDisabledShadow: Color; 15 | canvasTextInvert: Color; 16 | checkmark: Color; 17 | checkmarkDisabled: Color; 18 | desktopBackground: Color; 19 | flatDark: Color; 20 | flatLight: Color; 21 | focusSecondary: Color; 22 | headerBackground: Color; 23 | headerNotActiveBackground: Color; 24 | headerNotActiveText: Color; 25 | headerText: Color; 26 | hoverBackground: Color; 27 | material: Color; 28 | materialDark: Color; 29 | materialText: Color; 30 | materialTextDisabled: Color; 31 | materialTextDisabledShadow: Color; 32 | materialTextInvert: Color; 33 | progress: Color; 34 | tooltip: Color; 35 | }; 36 | 37 | export type WindowsTheme = { 38 | ActiveBorder: Color; 39 | ActiveTitle: Color; 40 | AppWorkspace: Color; 41 | Background: Color; 42 | ButtonAlternateFace: Color; 43 | ButtonDkShadow: Color; 44 | ButtonFace: Color; 45 | ButtonHilight: Color; 46 | ButtonLight: Color; 47 | ButtonShadow: Color; 48 | ButtonText: Color; 49 | GradientActiveTitle: Color; 50 | GradientInactiveTitle: Color; 51 | GrayText: Color; 52 | Hilight: Color; 53 | HilightText: Color; 54 | HotTrackingColor: Color; 55 | InactiveBorder: Color; 56 | InactiveTitle: Color; 57 | InactiveTitleText: Color; 58 | InfoText: Color; 59 | InfoWindow: Color; 60 | Menu: Color; 61 | MenuBar: Color; 62 | MenuHilight: Color; 63 | MenuText: Color; 64 | Scrollbar: Color; 65 | TitleText: Color; 66 | Window: Color; 67 | WindowFrame: Color; 68 | WindowText: Color; 69 | }; 70 | -------------------------------------------------------------------------------- /src/common/themes/vaporTeal.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'vaporTeal', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#00706f', 9 | borderDarkest: '#000000', 10 | borderLight: '#2fcecd', 11 | borderLightest: '#58ffff', 12 | canvas: '#98DFEA', 13 | canvasText: '#000000', 14 | canvasTextDisabled: '#00706f', 15 | canvasTextDisabledShadow: '#58ffff', 16 | canvasTextInvert: '#000000', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#00706f', 19 | desktopBackground: '#008080', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#FCF6BD', 23 | headerBackground: '#246A73', 24 | headerNotActiveBackground: '#2fcecd', 25 | headerNotActiveText: '#246A73', 26 | headerText: '#58ffff', 27 | hoverBackground: '#FF99C8', 28 | material: '#01a8a8', 29 | materialDark: '#246A73', 30 | materialText: '#000000', 31 | materialTextDisabled: '#00706f', 32 | materialTextDisabledShadow: '#58ffff', 33 | materialTextInvert: '#000000', 34 | progress: '#FF99C8', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/vermillion.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'vermillion', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#7f2120', 9 | borderDarkest: '#130405', 10 | borderLight: '#d25051', 11 | borderLightest: '#e59697', 12 | canvas: '#EFE9F4', 13 | canvasText: '#130405', 14 | canvasTextDisabled: '#7f2120', 15 | canvasTextDisabledShadow: '#e59697', 16 | canvasTextInvert: '#EFE9F4', 17 | checkmark: '#130405', 18 | checkmarkDisabled: '#7f2120', 19 | desktopBackground: '#b22930', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#000103', 24 | headerNotActiveBackground: '#7f2120', 25 | headerNotActiveText: '#EFE9F4', 26 | headerText: '#EFE9F4', 27 | hoverBackground: '#000103', 28 | material: '#cf4545', 29 | materialDark: '#7f2120', 30 | materialText: '#130405', 31 | materialTextDisabled: '#7f2120', 32 | materialTextDisabledShadow: '#e59697', 33 | materialTextInvert: '#EFE9F4', 34 | progress: '#000103', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/violetDark.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'violetDark', 5 | 6 | anchor: '#1034a6', 7 | anchorVisited: '#440381', 8 | borderDark: '#3c1f3e', 9 | borderDarkest: '#18051a', 10 | borderLight: '#945b9b', 11 | borderLightest: '#c47bcc', 12 | canvas: '#c47bcc', 13 | canvasText: '#18051a', 14 | canvasTextDisabled: '#000000', 15 | canvasTextDisabledShadow: '#000000', 16 | canvasTextInvert: '#c57ece', 17 | checkmark: '#000000', 18 | checkmarkDisabled: '#3c1f3e', 19 | desktopBackground: '#3b1940', 20 | flatDark: '#3c1f3e', 21 | flatLight: '#945b9b', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#1034a6', 24 | headerNotActiveBackground: '#210e23', 25 | headerNotActiveText: '#652a6d', 26 | headerText: '#010601', 27 | hoverBackground: '#512155', 28 | material: '#652a6d', 29 | materialDark: '#210e23', 30 | materialText: '#c57ece', 31 | materialTextDisabled: '#3c1f3e', 32 | materialTextDisabledShadow: '#c47bcc', 33 | materialTextInvert: '#c47bcc', 34 | progress: '#000080', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/vistaesqueMidnight.ts: -------------------------------------------------------------------------------- 1 | /* "Vista-esque Midnight" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Vista-esque-Midnight-557498234 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'vistaesqueMidnight', 9 | anchor: 'rgb(64, 64, 192)', 10 | anchorVisited: 'rgb(64, 64, 192)', 11 | borderDark: 'rgb(21, 21, 21)', 12 | borderDarkest: 'rgb(0, 0, 0)', 13 | borderLight: 'rgb(32, 32, 32)', 14 | borderLightest: 'rgb(128, 128, 128)', 15 | canvas: 'rgb(0, 0, 0)', 16 | canvasText: 'rgb(255, 255, 255)', 17 | canvasTextDisabled: 'rgb(21, 21, 21)', 18 | canvasTextDisabledShadow: 'rgb(128, 128, 128)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(255, 255, 255)', 21 | checkmarkDisabled: 'rgb(32, 32, 32)', 22 | desktopBackground: 'rgb(31, 60, 89)', 23 | flatDark: 'rgb(21, 21, 21)', 24 | flatLight: 'rgb(32, 32, 32)', 25 | focusSecondary: 'rgb(128, 128, 128)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(81, 132, 188), rgb(100, 168, 60))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(22, 46, 101), rgb(18, 91, 30))', 30 | headerNotActiveText: 'rgb(192, 192, 192)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(49, 106, 197)', 33 | material: 'rgb(32, 32, 32)', 34 | materialDark: 'rgb(22, 46, 101)', 35 | materialText: 'rgb(255, 255, 255)', 36 | materialTextDisabled: 'rgb(21, 21, 21)', 37 | materialTextDisabledShadow: 'rgb(128, 128, 128)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(49, 106, 197)', 40 | tooltip: 'rgb(0, 0, 30)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/themes/water.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from './types'; 2 | 3 | export default { 4 | name: 'water', 5 | 6 | anchor: '#72b3b4', 7 | anchorVisited: '#440381', 8 | borderDark: '#888c8f', 9 | borderDarkest: '#050608', 10 | borderLight: '#dfe0e3', 11 | borderLightest: '#ffffff', 12 | canvas: '#ffffff', 13 | canvasText: '#050608', 14 | canvasTextDisabled: '#888c8f', 15 | canvasTextDisabledShadow: '#ffffff', 16 | canvasTextInvert: '#ffffff', 17 | checkmark: '#050608', 18 | checkmarkDisabled: '#888c8f', 19 | desktopBackground: '#3a6ea5', 20 | flatDark: '#9e9e9e', 21 | flatLight: '#d8d8d8', 22 | focusSecondary: '#fefe03', 23 | headerBackground: '#72b3b4', 24 | headerNotActiveBackground: '#9a9e9c', 25 | headerNotActiveText: '#ced0cf', 26 | headerText: '#ffffff', 27 | hoverBackground: '#72b3b4', 28 | material: '#ced0cf', 29 | materialDark: '#9a9e9c', 30 | materialText: '#050608', 31 | materialTextDisabled: '#888c8f', 32 | materialTextDisabledShadow: '#ffffff', 33 | materialTextInvert: '#ffffff', 34 | progress: '#72b3b4', 35 | tooltip: '#fefbcc' 36 | } as Theme; 37 | -------------------------------------------------------------------------------- /src/common/themes/white.ts: -------------------------------------------------------------------------------- 1 | /* "White" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/White-870495714 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'white', 9 | anchor: 'rgb(0, 0, 128)', 10 | anchorVisited: 'rgb(0, 0, 128)', 11 | borderDark: 'rgb(0, 0, 0)', 12 | borderDarkest: 'rgb(255, 255, 255)', 13 | borderLight: 'rgb(0, 0, 0)', 14 | borderLightest: 'rgb(255, 255, 255)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(0, 0, 0)', 18 | canvasTextDisabledShadow: 'rgb(255, 255, 255)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(128, 128, 128)', 22 | desktopBackground: 'rgb(0, 128, 128)', 23 | flatDark: 'rgb(0, 0, 0)', 24 | flatLight: 'rgb(0, 0, 0)', 25 | focusSecondary: 'rgb(255, 255, 255)', 26 | headerBackground: 'linear-gradient(to right, rgb(0, 0, 128), rgb(0, 0, 128))', 27 | headerNotActiveBackground: 28 | 'linear-gradient(to right, rgb(128, 128, 128), rgb(128, 128, 128))', 29 | headerNotActiveText: 'rgb(192, 192, 192)', 30 | headerText: 'rgb(255, 255, 255)', 31 | hoverBackground: 'rgb(0, 0, 128)', 32 | material: 'rgb(255, 255, 255)', 33 | materialDark: 'rgb(128, 128, 128)', 34 | materialText: 'rgb(0, 0, 0)', 35 | materialTextDisabled: 'rgb(0, 0, 0)', 36 | materialTextDisabledShadow: 'rgb(255, 255, 255)', 37 | materialTextInvert: 'rgb(255, 255, 255)', 38 | progress: 'rgb(0, 0, 128)', 39 | tooltip: 'rgb(255, 255, 128)' 40 | } as Theme; 41 | -------------------------------------------------------------------------------- /src/common/themes/windows1.ts: -------------------------------------------------------------------------------- 1 | /* "Windows 1" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/Windows-1-573195578 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'windows1', 9 | anchor: 'rgb(0, 0, 85)', 10 | anchorVisited: 'rgb(0, 0, 85)', 11 | borderDark: 'rgb(0, 0, 0)', 12 | borderDarkest: 'rgb(255, 255, 255)', 13 | borderLight: 'rgb(0, 0, 0)', 14 | borderLightest: 'rgb(255, 255, 255)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(0, 0, 0)', 18 | canvasTextDisabledShadow: 'rgb(255, 255, 255)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(85, 85, 85)', 22 | desktopBackground: 'rgb(85, 254, 120)', 23 | flatDark: 'rgb(0, 0, 0)', 24 | flatLight: 'rgb(0, 0, 0)', 25 | focusSecondary: 'rgb(255, 255, 255)', 26 | headerBackground: 'linear-gradient(to right, rgb(0, 0, 0), rgb(85, 85, 255))', 27 | headerNotActiveBackground: 28 | 'linear-gradient(to right, rgb(0, 0, 0), rgb(109, 109, 199))', 29 | headerNotActiveText: 'rgb(255, 255, 255)', 30 | headerText: 'rgb(255, 255, 255)', 31 | hoverBackground: 'rgb(0, 0, 0)', 32 | material: 'rgb(255, 255, 255)', 33 | materialDark: 'rgb(0, 0, 0)', 34 | materialText: 'rgb(0, 0, 0)', 35 | materialTextDisabled: 'rgb(0, 0, 0)', 36 | materialTextDisabledShadow: 'rgb(255, 255, 255)', 37 | materialTextInvert: 'rgb(255, 255, 255)', 38 | progress: 'rgb(0, 0, 0)', 39 | tooltip: 'rgb(255, 255, 85)' 40 | } as Theme; 41 | -------------------------------------------------------------------------------- /src/common/themes/wmii.ts: -------------------------------------------------------------------------------- 1 | /* "WMII" by tPenguinLTG 2 | * https://www.deviantart.com/tpenguinltg/art/wmii-683233676 3 | */ 4 | 5 | import { Theme } from './types'; 6 | 7 | export default { 8 | name: 'wmii', 9 | anchor: 'rgb(129, 101, 79)', 10 | anchorVisited: 'rgb(129, 101, 79)', 11 | borderDark: 'rgb(145, 148, 75)', 12 | borderDarkest: 'rgb(64, 64, 64)', 13 | borderLight: 'rgb(193, 196, 139)', 14 | borderLightest: 'rgb(224, 225, 198)', 15 | canvas: 'rgb(255, 255, 255)', 16 | canvasText: 'rgb(0, 0, 0)', 17 | canvasTextDisabled: 'rgb(145, 148, 75)', 18 | canvasTextDisabledShadow: 'rgb(224, 225, 198)', 19 | canvasTextInvert: 'rgb(255, 255, 255)', 20 | checkmark: 'rgb(0, 0, 0)', 21 | checkmarkDisabled: 'rgb(145, 148, 75)', 22 | desktopBackground: 'rgb(51, 51, 51)', 23 | flatDark: 'rgb(145, 148, 75)', 24 | flatLight: 'rgb(193, 196, 139)', 25 | focusSecondary: 'rgb(224, 225, 198)', 26 | headerBackground: 27 | 'linear-gradient(to right, rgb(129, 101, 79), rgb(129, 101, 79))', 28 | headerNotActiveBackground: 29 | 'linear-gradient(to right, rgb(145, 148, 75), rgb(145, 148, 75))', 30 | headerNotActiveText: 'rgb(193, 196, 139)', 31 | headerText: 'rgb(255, 255, 255)', 32 | hoverBackground: 'rgb(0, 0, 0)', 33 | material: 'rgb(193, 196, 139)', 34 | materialDark: 'rgb(145, 148, 75)', 35 | materialText: 'rgb(0, 0, 0)', 36 | materialTextDisabled: 'rgb(145, 148, 75)', 37 | materialTextDisabledShadow: 'rgb(224, 225, 198)', 38 | materialTextInvert: 'rgb(255, 255, 255)', 39 | progress: 'rgb(0, 0, 0)', 40 | tooltip: 'rgb(255, 255, 225)' 41 | } as Theme; 42 | -------------------------------------------------------------------------------- /src/common/utils/events.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const focusEventTypes = ['blur', 'focus']; 4 | 5 | export const keyboardEventTypes = ['keydown', 'keypress', 'keyup']; 6 | 7 | export const mouseEventTypes = [ 8 | 'click', 9 | 'contextmenu', 10 | 'doubleclick', 11 | 'drag', 12 | 'dragend', 13 | 'dragenter', 14 | 'dragexit', 15 | 'dragleave', 16 | 'dragover', 17 | 'dragstart', 18 | 'drop', 19 | 'mousedown', 20 | 'mouseenter', 21 | 'mouseleave', 22 | 'mousemove', 23 | 'mouseout', 24 | 'mouseover', 25 | 'mouseup' 26 | ]; 27 | 28 | export function isReactFocusEvent( 29 | event: React.SyntheticEvent | Event 30 | ): event is React.FocusEvent { 31 | return 'nativeEvent' in event && focusEventTypes.includes(event.type); 32 | } 33 | 34 | export function isReactKeyboardEvent( 35 | event: React.SyntheticEvent | Event 36 | ): event is React.KeyboardEvent { 37 | return 'nativeEvent' in event && keyboardEventTypes.includes(event.type); 38 | } 39 | 40 | export function isReactMouseEvent( 41 | event: React.SyntheticEvent | Event 42 | ): event is React.MouseEvent { 43 | return 'nativeEvent' in event && mouseEventTypes.includes(event.type); 44 | } 45 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* common */ 2 | export { default as styleReset } from './common/styleReset'; 3 | export { createScrollbars } from './common/index'; 4 | 5 | /* components */ 6 | export * from './Anchor/Anchor'; 7 | export * from './AppBar/AppBar'; 8 | export * from './Avatar/Avatar'; 9 | export * from './Button/Button'; 10 | export * from './Checkbox/Checkbox'; 11 | export * from './ColorInput/ColorInput'; 12 | export * from './Counter/Counter'; 13 | export * from './DatePicker/DatePicker'; 14 | export * from './Frame/Frame'; 15 | export * from './GroupBox/GroupBox'; 16 | export * from './Handle/Handle'; 17 | export * from './Hourglass/Hourglass'; 18 | export * from './MenuList/MenuList'; 19 | export * from './Monitor/Monitor'; 20 | export * from './NumberInput/NumberInput'; 21 | export * from './ProgressBar/ProgressBar'; 22 | export * from './Radio/Radio'; 23 | export * from './ScrollView/ScrollView'; 24 | export * from './Select/Select'; 25 | export * from './Separator/Separator'; 26 | export * from './Slider/Slider'; 27 | export * from './Table/Table'; 28 | export * from './Tabs/Tabs'; 29 | export * from './TextInput/TextInput'; 30 | export * from './Toolbar/Toolbar'; 31 | export * from './Tooltip/Tooltip'; 32 | export * from './TreeView/TreeView'; 33 | export * from './Window/Window'; 34 | 35 | /* deprecated components */ 36 | export * from './legacy/Bar'; 37 | export * from './legacy/Cutout'; 38 | export * from './legacy/Desktop'; 39 | export * from './legacy/Divider'; 40 | export * from './legacy/Fieldset'; 41 | export * from './legacy/List'; 42 | export * from './legacy/ListItem'; 43 | export * from './legacy/NumberField'; 44 | export * from './legacy/Panel'; 45 | export * from './legacy/Progress'; 46 | export * from './legacy/TextField'; 47 | export * from './legacy/Tree'; 48 | -------------------------------------------------------------------------------- /src/legacy/Bar.tsx: -------------------------------------------------------------------------------- 1 | import { Handle, HandleProps } from '../Handle/Handle'; 2 | 3 | /** @deprecated Use `HandleProps` */ 4 | export type BarProps = HandleProps; 5 | 6 | /** @deprecated Use `Handle` */ 7 | export const Bar = Handle; 8 | -------------------------------------------------------------------------------- /src/legacy/Cutout.tsx: -------------------------------------------------------------------------------- 1 | import { ScrollView, ScrollViewProps } from '../ScrollView/ScrollView'; 2 | 3 | /** @deprecated Use `ScrollViewProps` */ 4 | export type CutoutProps = ScrollViewProps; 5 | 6 | /** @deprecated Use `ScrollView` */ 7 | export const Cutout = ScrollView; 8 | -------------------------------------------------------------------------------- /src/legacy/Desktop.tsx: -------------------------------------------------------------------------------- 1 | import { Monitor, MonitorProps } from '../Monitor/Monitor'; 2 | 3 | /** @deprecated Use `MonitorProps` */ 4 | export type DesktopProps = MonitorProps; 5 | 6 | /** @deprecated Use `Monitor` */ 7 | export const Desktop = Monitor; 8 | -------------------------------------------------------------------------------- /src/legacy/Divider.tsx: -------------------------------------------------------------------------------- 1 | import { Separator, SeparatorProps } from '../Separator/Separator'; 2 | 3 | /** @deprecated Use `SeparatorProps` */ 4 | export type DividerProps = SeparatorProps; 5 | 6 | /** @deprecated Use `Separator` */ 7 | export const Divider = Separator; 8 | -------------------------------------------------------------------------------- /src/legacy/Fieldset.tsx: -------------------------------------------------------------------------------- 1 | import { GroupBox, GroupBoxProps } from '../GroupBox/GroupBox'; 2 | 3 | /** @deprecated Use `GroupBoxProps` */ 4 | export type FieldsetProps = GroupBoxProps; 5 | 6 | /** @deprecated Use `GroupBox` */ 7 | export const Fieldset = GroupBox; 8 | -------------------------------------------------------------------------------- /src/legacy/List.tsx: -------------------------------------------------------------------------------- 1 | import { MenuList, MenuListProps } from '../MenuList/MenuList'; 2 | 3 | /** @deprecated Use `MenuListProps` */ 4 | export type ListProps = MenuListProps; 5 | 6 | /** @deprecated Use `MenuList` */ 7 | export const List = MenuList; 8 | -------------------------------------------------------------------------------- /src/legacy/ListItem.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | MenuListItem, 3 | MenuListItemProps, 4 | StyledMenuListItem 5 | } from '../MenuList/MenuList'; 6 | 7 | /** @deprecated Use `MenuListItemProps` */ 8 | export type ListItemProps = MenuListItemProps; 9 | 10 | /** @deprecated Use `MenuListItem` */ 11 | export const ListItem = MenuListItem; 12 | 13 | /** @deprecated Use `StyledMenuListItem` */ 14 | export const StyledListItem = StyledMenuListItem; 15 | -------------------------------------------------------------------------------- /src/legacy/NumberField.tsx: -------------------------------------------------------------------------------- 1 | import { NumberInput, NumberInputProps } from '../NumberInput/NumberInput'; 2 | 3 | /** @deprecated Use `NumberInputProps` */ 4 | export type NumberFieldProps = NumberInputProps; 5 | 6 | /** @deprecated Use `NumberInput` */ 7 | export const NumberField = NumberInput; 8 | -------------------------------------------------------------------------------- /src/legacy/Panel.tsx: -------------------------------------------------------------------------------- 1 | import { Frame, FrameProps } from '../Frame/Frame'; 2 | 3 | /** @deprecated Use `FrameProps` */ 4 | export type PanelProps = FrameProps; 5 | 6 | /** @deprecated Use `Frame` */ 7 | export const Panel = Frame; 8 | -------------------------------------------------------------------------------- /src/legacy/Progress.tsx: -------------------------------------------------------------------------------- 1 | import { ProgressBar, ProgressBarProps } from '../ProgressBar/ProgressBar'; 2 | 3 | /** @deprecated Use `ProgressBarProps` */ 4 | export type ProgressProps = ProgressBarProps; 5 | 6 | /** @deprecated Use `ProgressBar` */ 7 | export const Progress = ProgressBar; 8 | -------------------------------------------------------------------------------- /src/legacy/TextField.tsx: -------------------------------------------------------------------------------- 1 | import { TextInput, TextInputProps } from '../TextInput/TextInput'; 2 | 3 | /** @deprecated Use `TextInputProps` */ 4 | export type TextFieldProps = TextInputProps; 5 | 6 | /** @deprecated Use `TextInput` */ 7 | export const TextField = TextInput; 8 | -------------------------------------------------------------------------------- /src/legacy/Tree.tsx: -------------------------------------------------------------------------------- 1 | import { TreeView, TreeViewProps } from '../TreeView/TreeView'; 2 | 3 | /** @deprecated Use `TreeViewProps` */ 4 | export type TreeProps = TreeViewProps; 5 | 6 | /** @deprecated Use `TreeView` */ 7 | export const Tree = TreeView; 8 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { ComponentType } from 'react'; 2 | 3 | import { Color, Theme, WindowsTheme } from './common/themes/types'; 4 | 5 | export type Sizes = 'sm' | 'md' | 'lg'; 6 | 7 | export type Orientation = 'horizontal' | 'vertical'; 8 | 9 | export type Direction = 'up' | 'down' | 'left' | 'right'; 10 | 11 | export type DimensionValue = undefined | number | string; 12 | 13 | export type CommonStyledProps = { 14 | /** 15 | * "as" polymorphic prop allows to render a different HTML element or React component 16 | * @see {@link https://styled-components.com/docs/api#as-polymorphic-prop} 17 | */ 18 | as?: string | ComponentType; // eslint-disable-line @typescript-eslint/no-explicit-any 19 | }; 20 | 21 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 22 | export type HTMLDataAttributes = Record<`data-${string}`, any>; 23 | 24 | export type CommonThemeProps = { 25 | 'data-testid'?: string; 26 | $disabled?: boolean; 27 | shadow?: boolean; 28 | }; 29 | 30 | export { Color, Theme, WindowsTheme }; 31 | -------------------------------------------------------------------------------- /test/setup-test.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import 'jest-styled-components'; 3 | -------------------------------------------------------------------------------- /test/utils.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import React from 'react'; 3 | import { ThemeProvider } from 'styled-components'; 4 | 5 | import themes from '../src/common/themes'; 6 | 7 | export const theme = themes.original; 8 | 9 | export const renderWithTheme = (component: React.ReactNode) => 10 | render({component}); 11 | 12 | export class Touch { 13 | #identifier: number; 14 | 15 | #clientX = 0; 16 | 17 | #clientY = 0; 18 | 19 | #pageX = 0; 20 | 21 | #pageY = 0; 22 | 23 | constructor({ 24 | identifier, 25 | clientX = 0, 26 | clientY = 0, 27 | pageX = 0, 28 | pageY = 0 29 | }: { 30 | identifier: number; 31 | clientX?: number; 32 | clientY?: number; 33 | pageX?: number; 34 | pageY?: number; 35 | }) { 36 | this.#identifier = identifier; 37 | this.#clientX = clientX; 38 | this.#clientY = clientY; 39 | this.#pageX = pageX; 40 | this.#pageY = pageY; 41 | } 42 | 43 | get identifier() { 44 | return this.#identifier; 45 | } 46 | 47 | get pageX() { 48 | return this.#pageX; 49 | } 50 | 51 | get pageY() { 52 | return this.#pageY; 53 | } 54 | 55 | get clientX() { 56 | return this.#clientX; 57 | } 58 | 59 | get clientY() { 60 | return this.#clientY; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tsconfig.build.index.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "emitDeclarationOnly": true, 5 | "outDir": "./dist", 6 | "rootDir": "./src", 7 | "sourceMap": false 8 | }, 9 | "include": [ 10 | "types/global.d.ts", 11 | "types/themes.d.ts", 12 | "src/**/*.ts", 13 | "src/*/*.tsx" 14 | ], 15 | "exclude": [ 16 | "**/*.spec.ts", 17 | "**/*.spec.tsx", 18 | "**/*.stories.ts", 19 | "**/*.stories.tsx", 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.build.themes.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "emitDeclarationOnly": true, 5 | "outDir": "./dist/themes", 6 | "rootDir": "./src/common/themes", 7 | "sourceMap": false 8 | }, 9 | "include": [ 10 | "src/common/themes/*.ts", 11 | "src/common/themes/*.tsx" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "alwaysStrict": true, 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "importHelpers": true, 10 | "jsx": "react", 11 | "lib": [ 12 | "ESNext", 13 | "DOM" 14 | ], 15 | "module": "Node16", 16 | "moduleResolution": "Node", 17 | "noEmitOnError": true, 18 | "noFallthroughCasesInSwitch": true, 19 | "noImplicitAny": true, 20 | "noImplicitReturns": true, 21 | "noImplicitThis": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "outDir": "./lib", 25 | "paths": { 26 | "react95": [ 27 | "./src" 28 | ] 29 | }, 30 | "resolveJsonModule": true, 31 | "rootDir": "./", 32 | "skipLibCheck": true, 33 | "sourceMap": true, 34 | "strict": true, 35 | "strictFunctionTypes": true, 36 | "strictNullChecks": true, 37 | "strictPropertyInitialization": true, 38 | "target": "ES2018" 39 | }, 40 | "include": [ 41 | "**/*.ts", 42 | "**/*.tsx" 43 | ], 44 | "exclude": [ 45 | "coverage", 46 | "dist", 47 | "node_modules", 48 | "storybook" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /types/globals.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png' { 2 | const value: string; 3 | export = value; 4 | } 5 | 6 | declare module '*.woff2' { 7 | const value: string; 8 | export = value; 9 | } 10 | -------------------------------------------------------------------------------- /types/themes.d.ts: -------------------------------------------------------------------------------- 1 | // import original module declarations 2 | import { Theme } from '../src/types'; 3 | import 'styled-components'; 4 | 5 | // and extend them! 6 | declare module 'styled-components' { 7 | export interface DefaultTheme extends Theme {} 8 | } 9 | --------------------------------------------------------------------------------