mirror of
https://github.com/XFox111/PasswordGeneratorExtension.git
synced 2026-04-22 08:08:01 +03:00
Minor 3.1.0 (#308)
* - Minor code refactoring (#288) - Migrated last SCSS file to Griffel to get rid of SASS dependency - Migrated deprecated FUI components - Fixed FUI unmet peer dependency warning * Bump vite-plugin-web-extension from 4.1.0 to 4.1.1 (#283) Bumps [vite-plugin-web-extension](https://github.com/aklinker1/vite-plugin-web-extension) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/aklinker1/vite-plugin-web-extension/releases) - [Commits](https://github.com/aklinker1/vite-plugin-web-extension/compare/v4.1.0...v4.1.1) --- updated-dependencies: - dependency-name: vite-plugin-web-extension dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump vite from 5.0.10 to 5.0.12 (#287) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.10 to 5.0.12. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @typescript-eslint/eslint-plugin from 6.16.0 to 6.20.0 (#292) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.16.0 to 6.20.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.20.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump vite from 5.0.10 to 5.0.12 (#293) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.10 to 5.0.12. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @fluentui/react-components from 9.43.3 to 9.46.3 (#295) Bumps [@fluentui/react-components](https://github.com/microsoft/fluentui) from 9.43.3 to 9.46.3. - [Release notes](https://github.com/microsoft/fluentui/releases) - [Changelog](https://github.com/microsoft/fluentui/blob/master/azure-pipelines.release-fluentui.yml) - [Commits](https://github.com/microsoft/fluentui/compare/@fluentui/react-components_v9.43.3...@fluentui/react-components_v9.46.3) --- updated-dependencies: - dependency-name: "@fluentui/react-components" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @types/react from 18.2.45 to 18.2.48 (#296) Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.45 to 18.2.48. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/react" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @vitejs/plugin-react-swc from 3.5.0 to 3.6.0 (#297) Bumps [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/vitejs/vite-plugin-react-swc/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react-swc/blob/main/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react-swc/compare/v3.5.0...v3.6.0) --- updated-dependencies: - dependency-name: "@vitejs/plugin-react-swc" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump vite-plugin-static-copy from 1.0.0 to 1.0.1 (#298) Bumps [vite-plugin-static-copy](https://github.com/sapphi-red/vite-plugin-static-copy) from 1.0.0 to 1.0.1. - [Release notes](https://github.com/sapphi-red/vite-plugin-static-copy/releases) - [Changelog](https://github.com/sapphi-red/vite-plugin-static-copy/blob/main/CHANGELOG.md) - [Commits](https://github.com/sapphi-red/vite-plugin-static-copy/compare/vite-plugin-static-copy@1.0.0...vite-plugin-static-copy@1.0.1) --- updated-dependencies: - dependency-name: vite-plugin-static-copy dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eugene Fox <eugene.xfox@outlook.com> * Bump @fluentui/react-icons from 2.0.224 to 2.0.226 (#299) Bumps [@fluentui/react-icons](https://github.com/microsoft/fluentui-system-icons) from 2.0.224 to 2.0.226. - [Commits](https://github.com/microsoft/fluentui-system-icons/commits) --- updated-dependencies: - dependency-name: "@fluentui/react-icons" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eugene Fox <eugene.xfox@outlook.com> * Bump wdzeng/edge-addon from 1.2.2 to 1.2.3 (#289) Bumps [wdzeng/edge-addon](https://github.com/wdzeng/edge-addon) from 1.2.2 to 1.2.3. - [Release notes](https://github.com/wdzeng/edge-addon/releases) - [Commits](https://github.com/wdzeng/edge-addon/compare/v1.2.2...v1.2.3) --- updated-dependencies: - dependency-name: wdzeng/edge-addon dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump wdzeng/chrome-extension from 1.2.1 to 1.2.2 (#290) Bumps [wdzeng/chrome-extension](https://github.com/wdzeng/chrome-extension) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/wdzeng/chrome-extension/releases) - [Commits](https://github.com/wdzeng/chrome-extension/compare/v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: wdzeng/chrome-extension dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump wdzeng/firefox-addon from 1.0.3 to 1.0.4 (#291) Bumps [wdzeng/firefox-addon](https://github.com/wdzeng/firefox-addon) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/wdzeng/firefox-addon/releases) - [Commits](https://github.com/wdzeng/firefox-addon/compare/v1.0.3...v1.0.4) --- updated-dependencies: - dependency-name: wdzeng/firefox-addon dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @typescript-eslint/parser from 6.16.0 to 6.20.0 (#294) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.16.0 to 6.20.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.20.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eugene Fox <eugene.xfox@outlook.com> * Bump @types/react from 18.2.48 to 18.2.55 (#301) Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.48 to 18.2.55. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/react" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump vite from 5.0.12 to 5.1.0 (#302) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.12 to 5.1.0. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/create-vite@5.1.0/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @fluentui/react-components from 9.46.3 to 9.46.4 (#306) Bumps [@fluentui/react-components](https://github.com/microsoft/fluentui) from 9.46.3 to 9.46.4. - [Release notes](https://github.com/microsoft/fluentui/releases) - [Changelog](https://github.com/microsoft/fluentui/blob/master/azure-pipelines.release-fluentui.yml) - [Commits](https://github.com/microsoft/fluentui/compare/@fluentui/react-components_v9.46.3...@fluentui/react-components_v9.46.4) --- updated-dependencies: - dependency-name: "@fluentui/react-components" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Improved quick adjustment panel: (#300) - Added length slider range setting (#286) - Added more character options for quick adjustment - QA panel now collapses when settings panel is open * Bump @types/react-dom from 18.2.18 to 18.2.19 (#303) Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 18.2.18 to 18.2.19. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom) --- updated-dependencies: - dependency-name: "@types/react-dom" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eugene Fox <eugene.xfox@outlook.com> * Bump @typescript-eslint/eslint-plugin from 6.20.0 to 6.21.0 (#304) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 6.20.0 to 6.21.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.21.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump @typescript-eslint/parser from 6.20.0 to 6.21.0 (#305) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.20.0 to 6.21.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.21.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update pt-BR (#307) * Improved quick adjustment panel: - Added length slider range setting (#286) - Added more character options for quick adjustment - QA panel now collapses when settings panel is open * Update pt-BR Update pt-BR * Update messages.json * Update messages.json * Update New * Update Final * Update Fix --------- Co-authored-by: Eugene Fox <eugene@xfox111.net> * Update package.json --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maison da Silva <maisonmdsgreen@hotmail.com>
This commit is contained in:
@@ -105,7 +105,7 @@ jobs:
|
||||
with:
|
||||
name: packed-chrome
|
||||
|
||||
- uses: wdzeng/chrome-extension@v1.2.1
|
||||
- uses: wdzeng/chrome-extension@v1.2.2
|
||||
with:
|
||||
extension-id: jnjobgjobffgmgfnkpkjfjkkfhfikmfl
|
||||
zip-path: PasswordGenerator-chrome.zip
|
||||
@@ -123,7 +123,7 @@ jobs:
|
||||
with:
|
||||
name: packed-chrome
|
||||
|
||||
- uses: wdzeng/edge-addon@v1.2.2
|
||||
- uses: wdzeng/edge-addon@v1.2.3
|
||||
with:
|
||||
product-id: ${{ secrets.EDGE_PRODUCT_ID }}
|
||||
zip-path: PasswordGenerator-chrome.zip
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
with:
|
||||
name: packed-firefox
|
||||
|
||||
- uses: wdzeng/firefox-addon@v1.0.3
|
||||
- uses: wdzeng/firefox-addon@v1.0.4
|
||||
with:
|
||||
addon-guid: ${{ secrets.FIREFOX_EXT_UUID }}
|
||||
xpi-path: PasswordGenerator-firefox.zip
|
||||
|
||||
Vendored
+1
-1
@@ -15,7 +15,7 @@
|
||||
"editor.insertSpaces": false,
|
||||
"files.insertFinalNewline": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
"source.organizeImports": "explicit"
|
||||
},
|
||||
"files.eol": "\n",
|
||||
"files.trimFinalNewlines": true,
|
||||
|
||||
+13
-13
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "password-generator",
|
||||
"version": "3.0.2",
|
||||
"version": "3.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -9,32 +9,32 @@
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluentui/react-components": "^9.43.3",
|
||||
"@fluentui/react-icons": "^2.0.224",
|
||||
"@fluentui/react-components": "^9.46.4",
|
||||
"@fluentui/react-icons": "^2.0.226",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.45",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/react": "^18.2.55",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"@types/webextension-polyfill": "^0.10.7",
|
||||
"@typescript-eslint/eslint-plugin": "^6.16.0",
|
||||
"@typescript-eslint/parser": "^6.16.0",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"@vitejs/plugin-react-swc": "^3.6.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"sass": "^1.69.5",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.10",
|
||||
"vite-plugin-static-copy": "^1.0.0",
|
||||
"vite": "^5.1.0",
|
||||
"vite-plugin-static-copy": "^1.0.1",
|
||||
"vite-plugin-svgr": "^4.2.0",
|
||||
"vite-plugin-web-extension": "^4.1.0",
|
||||
"vite-plugin-web-extension": "^4.1.1",
|
||||
"webextension-polyfill": "^0.10.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"postcss": "^8.4.31",
|
||||
"tough-cookie": "^4.1.3"
|
||||
"tough-cookie": "^4.1.3",
|
||||
"scheduler": "^0.20.0"
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -6,18 +6,24 @@ import SettingsSection from "./Components/SettingsSection";
|
||||
import Specials from "./Specials/Specials";
|
||||
import { StorageProvider } from "./Utils/Storage";
|
||||
import { useTheme } from "./Utils/Theme";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function App(): JSX.Element
|
||||
{
|
||||
const theme = useTheme();
|
||||
const cls = useStyles();
|
||||
const [selection, setSelection] = useState<string[]>([]);
|
||||
|
||||
return (
|
||||
<FluentProvider theme={ theme }>
|
||||
<main className={ cls.root }>
|
||||
<StorageProvider loader={ <Spinner size="large" className={ cls.spinner } /> }>
|
||||
<GeneratorView />
|
||||
<Accordion collapsible className={ cls.accordionAnimation }>
|
||||
<GeneratorView collapse={ selection.includes("settings") } />
|
||||
<Accordion
|
||||
openItems={ selection }
|
||||
onToggle={ (_, e) => setSelection(e.openItems as string[]) }
|
||||
collapsible
|
||||
className={ cls.accordionAnimation }>
|
||||
<SettingsSection />
|
||||
<AboutSection />
|
||||
</Accordion>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useStyles } from "./AboutSection.styles";
|
||||
|
||||
export default function AboutSection(): JSX.Element
|
||||
{
|
||||
const theme = useTheme(bmcLightTheme, bmcDarkTheme);
|
||||
const bmcTheme = useTheme(bmcLightTheme, bmcDarkTheme);
|
||||
const cls = useStyles();
|
||||
|
||||
const link = (text: string, href: string): JSX.Element => (
|
||||
@@ -54,7 +54,7 @@ export default function AboutSection(): JSX.Element
|
||||
<fui.Button { ...buttonProps(GetFeedbackLink(), <PersonFeedbackRegular />) }>
|
||||
{ loc("about@feedback") }
|
||||
</fui.Button>
|
||||
<fui.FluentProvider theme={ theme }>
|
||||
<fui.FluentProvider theme={ bmcTheme }>
|
||||
<fui.Button { ...buttonProps(PersonalLink.BuyMeACoffee, <BuyMeACoffee />) }>
|
||||
{ loc("about@sponsor") }
|
||||
</fui.Button>
|
||||
|
||||
@@ -17,17 +17,6 @@ export const useStyles = makeStyles({
|
||||
alignItems: "center",
|
||||
paddingRight: tokens.spacingHorizontalM,
|
||||
},
|
||||
optionsSpacing:
|
||||
{
|
||||
...shorthands.padding(tokens.spacingVerticalS, tokens.spacingHorizontalS),
|
||||
},
|
||||
optionsLabel:
|
||||
{
|
||||
"> div[role=note].fui-InfoButton__info":
|
||||
{
|
||||
zIndex: 1,
|
||||
},
|
||||
},
|
||||
copyIcon:
|
||||
{
|
||||
animationName: "scaleUpIn",
|
||||
@@ -39,5 +28,20 @@ export const useStyles = makeStyles({
|
||||
animationName: "spin",
|
||||
animationDuration: tokens.durationSlow,
|
||||
animationTimingFunction: tokens.curveEasyEaseMax,
|
||||
}
|
||||
},
|
||||
msgBar:
|
||||
{
|
||||
...shorthands.padding(tokens.spacingVerticalMNudge, tokens.spacingHorizontalM),
|
||||
},
|
||||
options:
|
||||
{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
...shorthands.padding(tokens.spacingVerticalS, tokens.spacingHorizontalS),
|
||||
},
|
||||
characterOptionsContainer:
|
||||
{
|
||||
display: "flex",
|
||||
...shorthands.gap(tokens.spacingHorizontalXS),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Button, Checkbox, Input, Slider, Text, Tooltip, mergeClasses } from "@fluentui/react-components";
|
||||
import { Alert, InfoLabel } from "@fluentui/react-components/unstable";
|
||||
import { ArrowClockwiseRegular, ArrowUndoRegular, CheckmarkRegular, CopyRegular } from "@fluentui/react-icons";
|
||||
import * as fui from "@fluentui/react-components";
|
||||
import * as Icons from "@fluentui/react-icons";
|
||||
import { useEffect, useState } from "react";
|
||||
import GeneratorOptions from "../Models/GeneratorOptions";
|
||||
import { GetLocaleString as loc } from "../Utils/Localization";
|
||||
@@ -9,22 +8,24 @@ import { useStorage } from "../Utils/Storage";
|
||||
import { useTimeout } from "../Utils/Timeout";
|
||||
import { useStyles } from "./GeneratorView.styles";
|
||||
|
||||
type QuickOptions = Pick<GeneratorOptions, "Length" | "Special" | "ExcludeAmbiguous">;
|
||||
|
||||
export default function GeneratorView(): JSX.Element
|
||||
export default function GeneratorView(props: { collapse: boolean; }): JSX.Element
|
||||
{
|
||||
const { generatorOptions } = useStorage();
|
||||
const { generatorOptions, extOptions } = useStorage();
|
||||
const [password, setPassword] = useState<string>("");
|
||||
const [quickOpts, _setOpts] = useState<QuickOptions>(generatorOptions);
|
||||
const [quickOpts, _setOpts] = useState<GeneratorOptions>(generatorOptions);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const [refreshTimer, copyTimer] = [useTimeout(310), useTimeout(1000)];
|
||||
const checkedOptions = Object.keys(quickOpts).filter(k => quickOpts[k as keyof GeneratorOptions] as boolean);
|
||||
const cls = useStyles();
|
||||
|
||||
const IncludeIcon: Icons.FluentIcon = Icons.bundleIcon(Icons.AddCircleFilled, Icons.AddCircleRegular);
|
||||
const ExcludeIcon: Icons.FluentIcon = Icons.bundleIcon(Icons.SubtractCircleFilled, Icons.SubtractCircleRegular);
|
||||
|
||||
const resetOptions = (): void =>
|
||||
_setOpts(generatorOptions);
|
||||
|
||||
const setOptions = (opts: Partial<QuickOptions>) =>
|
||||
const setOptions = (opts: Partial<GeneratorOptions>) =>
|
||||
_setOpts({ ...quickOpts, ...opts });
|
||||
|
||||
function RefreshPassword(): void
|
||||
@@ -42,64 +43,129 @@ export default function GeneratorView(): JSX.Element
|
||||
copyTimer.trigger();
|
||||
}
|
||||
|
||||
function OnCheckedValueChange(_: unknown, e: fui.MenuCheckedValueChangeData): void
|
||||
{
|
||||
const opts: Partial<Omit<GeneratorOptions, "Length">> = {};
|
||||
|
||||
let keys = Object.keys(quickOpts).filter(i => i !== "Length") as (keyof Omit<GeneratorOptions, "Length">)[];
|
||||
|
||||
if (e.name === "include")
|
||||
keys = keys.filter(i => !i.startsWith("Exclude"));
|
||||
else
|
||||
keys = keys.filter(i => i.startsWith("Exclude"));
|
||||
|
||||
for (const key of keys)
|
||||
opts[key] = e.checkedItems.includes(key);
|
||||
|
||||
setOptions(opts);
|
||||
}
|
||||
|
||||
useEffect(resetOptions, [generatorOptions]);
|
||||
useEffect(RefreshPassword, [generatorOptions, quickOpts]);
|
||||
useEffect(refreshTimer.trigger, [password]);
|
||||
|
||||
const actionButtons: JSX.Element = <>
|
||||
<Tooltip content={ loc("generator@copy") } relationship="label">
|
||||
<Button
|
||||
appearance="subtle" onClick={ CopyPassword }
|
||||
icon={
|
||||
copyTimer.isActive ?
|
||||
<CheckmarkRegular className={ cls.copyIcon } /> :
|
||||
<CopyRegular className={ cls.copyIcon } />
|
||||
} />
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content={ loc("generator@refresh") } relationship="label">
|
||||
<Button
|
||||
appearance="subtle" onClick={ RefreshPassword }
|
||||
icon={
|
||||
<ArrowClockwiseRegular className={ mergeClasses(refreshTimer.isActive && cls.refreshIcon) } />
|
||||
} />
|
||||
</Tooltip>
|
||||
</>;
|
||||
|
||||
return (
|
||||
<section className={ cls.root }>
|
||||
{ error ?
|
||||
<Alert intent="warning">{ error }</Alert> :
|
||||
<Input readOnly contentAfter={ actionButtons } value={ password } className={ cls.input } />
|
||||
<fui.MessageBar intent="warning" className={ cls.msgBar }>
|
||||
<fui.MessageBarBody>{ error }</fui.MessageBarBody>
|
||||
</fui.MessageBar>
|
||||
:
|
||||
<fui.Input
|
||||
className={ cls.input }
|
||||
readOnly value={ password }
|
||||
contentAfter={ <>
|
||||
<fui.Tooltip content={ loc("generator@copy") } relationship="label">
|
||||
<fui.Button
|
||||
appearance="subtle" onClick={ CopyPassword }
|
||||
icon={
|
||||
copyTimer.isActive ?
|
||||
<Icons.CheckmarkRegular className={ cls.copyIcon } /> :
|
||||
<Icons.CopyRegular className={ cls.copyIcon } />
|
||||
} />
|
||||
</fui.Tooltip>
|
||||
|
||||
<fui.Tooltip content={ loc("generator@refresh") } relationship="label">
|
||||
<fui.Button
|
||||
appearance="subtle" onClick={ RefreshPassword }
|
||||
icon={
|
||||
<Icons.ArrowClockwiseRegular className={ fui.mergeClasses(refreshTimer.isActive && cls.refreshIcon) } />
|
||||
} />
|
||||
</fui.Tooltip>
|
||||
</> } />
|
||||
}
|
||||
|
||||
<div className={ mergeClasses(cls.root, cls.optionsSpacing) }>
|
||||
<InfoLabel info={ loc("generator@quickOptions__hint") } className={ cls.optionsLabel }>
|
||||
{ loc("generator@quickOptions") }
|
||||
</InfoLabel>
|
||||
{ !props.collapse &&
|
||||
<div className={ cls.options }>
|
||||
<fui.InfoLabel info={ loc("generator@quickOptions__hint") }>
|
||||
{ loc("generator@quickOptions") }
|
||||
</fui.InfoLabel>
|
||||
|
||||
<div className={ cls.lengthContainer }>
|
||||
<Slider
|
||||
min={ 6 } max={ Math.max(32, generatorOptions.Length) }
|
||||
value={ quickOpts.Length } onChange={ (_, e) => setOptions({ Length: e.value }) } />
|
||||
<Text>{ quickOpts.Length }</Text>
|
||||
<div className={ cls.lengthContainer }>
|
||||
<fui.Slider
|
||||
min={ extOptions.MinLength } max={ Math.max(extOptions.MaxLength, generatorOptions.Length) }
|
||||
value={ quickOpts.Length } onChange={ (_, e) => setOptions({ Length: e.value }) } />
|
||||
<fui.Text>{ quickOpts.Length }</fui.Text>
|
||||
</div>
|
||||
|
||||
<div className={ cls.characterOptionsContainer }>
|
||||
<fui.Menu
|
||||
positioning="after" hasCheckmarks
|
||||
checkedValues={ { include: checkedOptions } }
|
||||
onCheckedValueChange={ OnCheckedValueChange }>
|
||||
|
||||
<fui.MenuTrigger disableButtonEnhancement>
|
||||
<fui.MenuButton appearance="subtle" icon={ <IncludeIcon /> }>{ loc("generator@include") }</fui.MenuButton>
|
||||
</fui.MenuTrigger>
|
||||
|
||||
<fui.MenuPopover>
|
||||
<fui.MenuList>
|
||||
<fui.MenuItemCheckbox name="include" value="Uppercase" icon={ <Icons.TextCaseUppercaseRegular /> }>
|
||||
{ loc("settings@uppercase") }
|
||||
</fui.MenuItemCheckbox>
|
||||
<fui.MenuItemCheckbox name="include" value="Lowercase" icon={ <Icons.TextCaseLowercaseRegular /> }>
|
||||
{ loc("settings@lowercase") }
|
||||
</fui.MenuItemCheckbox>
|
||||
<fui.MenuItemCheckbox name="include" value="Numeric" icon={ <Icons.NumberSymbolRegular /> }>
|
||||
{ loc("settings@numeric") }
|
||||
</fui.MenuItemCheckbox>
|
||||
<fui.MenuItemCheckbox name="include" value="Special" icon={ <Icons.MathSymbolsRegular /> }>
|
||||
{ loc("settings@special") }
|
||||
</fui.MenuItemCheckbox>
|
||||
</fui.MenuList>
|
||||
</fui.MenuPopover>
|
||||
</fui.Menu>
|
||||
|
||||
<fui.Menu
|
||||
positioning="before"
|
||||
checkedValues={ { exclude: checkedOptions } }
|
||||
onCheckedValueChange={ OnCheckedValueChange }>
|
||||
|
||||
<fui.MenuTrigger disableButtonEnhancement>
|
||||
<fui.MenuButton appearance="subtle" icon={ <ExcludeIcon /> }>{ loc("generator@exclude") }</fui.MenuButton>
|
||||
</fui.MenuTrigger>
|
||||
|
||||
<fui.MenuPopover>
|
||||
<fui.MenuList>
|
||||
<fui.MenuItemCheckbox name="exclude" value="ExcludeSimilar">
|
||||
{ loc("settings@similar") }
|
||||
</fui.MenuItemCheckbox>
|
||||
<fui.MenuItemCheckbox name="exclude" value="ExcludeAmbiguous" disabled={ !quickOpts.Special }>
|
||||
{ loc("settings@ambiguous") }
|
||||
</fui.MenuItemCheckbox>
|
||||
<fui.MenuItemCheckbox name="exclude" value="ExcludeRepeating">
|
||||
{ loc("settings@repeating") }
|
||||
</fui.MenuItemCheckbox>
|
||||
</fui.MenuList>
|
||||
</fui.MenuPopover>
|
||||
</fui.Menu>
|
||||
|
||||
<fui.Tooltip content={ loc("generator@reset") } relationship="label">
|
||||
<fui.Button appearance="subtle" icon={ <Icons.ArrowUndoRegular /> } onClick={ resetOptions } />
|
||||
</fui.Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Checkbox
|
||||
label={ loc("settings@special") }
|
||||
checked={ quickOpts.Special }
|
||||
onChange={ (_, e) => setOptions({ Special: e.checked as boolean }) } />
|
||||
<Checkbox
|
||||
label={ loc("settings@ambiguous") } disabled={ !quickOpts.Special }
|
||||
checked={ !quickOpts.ExcludeAmbiguous }
|
||||
onChange={ (_, e) => setOptions({ ExcludeAmbiguous: !e.checked }) } />
|
||||
|
||||
<Tooltip content={ loc("generator@reset") } relationship="label">
|
||||
<Button appearance="subtle" icon={ <ArrowUndoRegular /> } onClick={ resetOptions } />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,4 +12,15 @@ export const useStyles = makeStyles({
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
rangeContainer:
|
||||
{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr auto 1fr auto",
|
||||
alignItems: "center",
|
||||
...shorthands.gap(tokens.spacingHorizontalS),
|
||||
},
|
||||
rangeInput:
|
||||
{
|
||||
width: "100%",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as fui from "@fluentui/react-components";
|
||||
import { InfoLabel } from "@fluentui/react-components/unstable";
|
||||
import { SettingsRegular } from "@fluentui/react-icons";
|
||||
import { ArrowUndoRegular, SettingsRegular } from "@fluentui/react-icons";
|
||||
import ExtensionOptions from "../Models/ExtensionOptions";
|
||||
import GeneratorOptions from "../Models/GeneratorOptions";
|
||||
import { GetLocaleString as loc } from "../Utils/Localization";
|
||||
@@ -13,12 +12,12 @@ import { useStyles } from "./SettingsSection.styles";
|
||||
|
||||
export default function SettingsSection(): JSX.Element
|
||||
{
|
||||
const { generatorOptions, updateStorage } = useStorage();
|
||||
const { extOptions, generatorOptions, updateStorage } = useStorage();
|
||||
const cls = useStyles();
|
||||
|
||||
const infoLabel = (content: string, hint: string) => ({
|
||||
children: (_: unknown, slotProps: fui.LabelProps) => (
|
||||
<InfoLabel { ...slotProps } info={ hint }>{ content }</InfoLabel>
|
||||
<fui.InfoLabel { ...slotProps } info={ hint }>{ content }</fui.InfoLabel>
|
||||
)
|
||||
});
|
||||
|
||||
@@ -26,6 +25,21 @@ export default function SettingsSection(): JSX.Element
|
||||
(_: unknown, args: fui.CheckboxOnChangeData) =>
|
||||
updateStorage({ [option]: args.checked } );
|
||||
|
||||
const updateNumberField = (key: keyof (ExtensionOptions & GeneratorOptions), defaultValue: number) =>
|
||||
(_: unknown, e: fui.InputOnChangeData): void =>
|
||||
{
|
||||
if (e.value.length < 1)
|
||||
{
|
||||
updateStorage({ [key]: defaultValue });
|
||||
return;
|
||||
}
|
||||
|
||||
const value = parseInt(e.value);
|
||||
|
||||
if (!isNaN(value) && value >= 0)
|
||||
updateStorage({ [key]: value });
|
||||
};
|
||||
|
||||
return (
|
||||
<fui.AccordionItem value="settings">
|
||||
<fui.AccordionHeader as="h2" icon={ <SettingsRegular /> }>{ loc("settings@title") }</fui.AccordionHeader>
|
||||
@@ -34,9 +48,30 @@ export default function SettingsSection(): JSX.Element
|
||||
|
||||
<fui.Field label={ loc("settings@length") } hint={ loc("settings@length__hint") }>
|
||||
<fui.Input
|
||||
type="number" min={ 6 }
|
||||
value={ generatorOptions.Length.toString() }
|
||||
onChange={ (_, e) => updateStorage({ Length: parseInt(e.value) }) } />
|
||||
onChange={ updateNumberField("Length", 0) } />
|
||||
</fui.Field>
|
||||
|
||||
<fui.Field label={ loc("settings@lengthRange") }>
|
||||
<div className={ cls.rangeContainer }>
|
||||
<fui.Input
|
||||
input={ { className: cls.rangeInput } }
|
||||
value={ extOptions.MinLength.toString() }
|
||||
onChange={ updateNumberField("MinLength", 4) } />
|
||||
|
||||
<fui.Divider />
|
||||
|
||||
<fui.Input
|
||||
input={ { className: cls.rangeInput } }
|
||||
value={ extOptions.MaxLength.toString() }
|
||||
onChange={ updateNumberField("MaxLength", 32) } />
|
||||
|
||||
<fui.Tooltip relationship="label" content={ loc("generator@reset") }>
|
||||
<fui.Button
|
||||
appearance="subtle" icon={ <ArrowUndoRegular /> }
|
||||
onClick={ () => updateStorage({ MinLength: 6, MaxLength: 32 }) } />
|
||||
</fui.Tooltip>
|
||||
</div>
|
||||
</fui.Field>
|
||||
|
||||
<fui.Divider />
|
||||
|
||||
@@ -85,14 +85,19 @@
|
||||
},
|
||||
"settings@length":
|
||||
{
|
||||
"message": "Password length",
|
||||
"message": "Default password length",
|
||||
"description": "Password length label in settings section"
|
||||
},
|
||||
"settings@length__hint":
|
||||
{
|
||||
"message": "Recommended length: 8—16",
|
||||
"message": "Recommended length: 8–16",
|
||||
"description": "Password length recommendatin in settings section"
|
||||
},
|
||||
"settings@lengthRange":
|
||||
{
|
||||
"message": "Quick adjustment length range",
|
||||
"description": "Quick adjustment length range label in settings section"
|
||||
},
|
||||
"settings@include":
|
||||
{
|
||||
"message": "Include symbols",
|
||||
@@ -167,5 +172,15 @@
|
||||
{
|
||||
"message": "These adjustments will not be saved",
|
||||
"description": "Quick options hint"
|
||||
},
|
||||
"generator@include":
|
||||
{
|
||||
"message": "Include",
|
||||
"description": "Include characters button label"
|
||||
},
|
||||
"generator@exclude":
|
||||
{
|
||||
"message": "Exclude",
|
||||
"description": "Exclude characters button label"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,14 +85,19 @@
|
||||
},
|
||||
"settings@length":
|
||||
{
|
||||
"message": "Długość hasła",
|
||||
"message": "Domyślna długość hasła",
|
||||
"description": "Password length label in settings section"
|
||||
},
|
||||
"settings@length__hint":
|
||||
{
|
||||
"message": "Zalecana długość: 8—16",
|
||||
"message": "Zalecana długość: 8–16",
|
||||
"description": "Password length recommendatin in settings section"
|
||||
},
|
||||
"settings@lengthRange":
|
||||
{
|
||||
"message": "Zakres długości dla szybkich ustawień",
|
||||
"description": "Quick adjustment length range label in settings section"
|
||||
},
|
||||
"settings@include":
|
||||
{
|
||||
"message": "Dodaj znaki",
|
||||
@@ -167,5 +172,15 @@
|
||||
{
|
||||
"message": "Te ustawienia nie zostaną zapisane",
|
||||
"description": "Quick options hint"
|
||||
},
|
||||
"generator@include":
|
||||
{
|
||||
"message": "Dodaj",
|
||||
"description": "Include characters button label"
|
||||
},
|
||||
"generator@exclude":
|
||||
{
|
||||
"message": "Wyklucz",
|
||||
"description": "Exclude characters button label"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
"description": "Error message when password length is less than 4 characters"
|
||||
},
|
||||
"error@noCharacters": {
|
||||
"message": "Pelo menos um conjunto de caracteres deve ser selecionado",
|
||||
"message": "É necessário selecionar pelo menos um conjunto de caracteres",
|
||||
"description": "Error message when no character set is selected"
|
||||
},
|
||||
"error@tooLong": {
|
||||
"message": "O comprimento é muito longo para gerar uma senha com caracteres exclusivos",
|
||||
"message": "O comprimento é muito longo para gerar uma senha com caracteres únicos",
|
||||
"description": "Error message when password length is too long to generate password with unique characters"
|
||||
},
|
||||
"about@title":
|
||||
@@ -45,7 +45,7 @@
|
||||
},
|
||||
"about@translationCta":
|
||||
{
|
||||
"message": "Encontrou um erro de digitação ou deseja uma tradução para o seu idioma?",
|
||||
"message": "Encontrou um erro ou quer uma tradução no seu idioma?",
|
||||
"description": "Translation CTA in about section"
|
||||
},
|
||||
"about@translationCtaButton":
|
||||
@@ -55,7 +55,7 @@
|
||||
},
|
||||
"about@website":
|
||||
{
|
||||
"message": "Meu website",
|
||||
"message": "Meu site",
|
||||
"description": "Website link in about section"
|
||||
},
|
||||
"about@sourceCode":
|
||||
@@ -70,12 +70,12 @@
|
||||
},
|
||||
"about@feedback":
|
||||
{
|
||||
"message": "Deixe um comentário",
|
||||
"message": "Enviar comentários",
|
||||
"description": "Feedback link in about section"
|
||||
},
|
||||
"about@sponsor":
|
||||
{
|
||||
"message": "Doar",
|
||||
"message": "Pague um café",
|
||||
"description": "Buy me a coffee donation link in about section"
|
||||
},
|
||||
"settings@title":
|
||||
@@ -85,14 +85,19 @@
|
||||
},
|
||||
"settings@length":
|
||||
{
|
||||
"message": "Comprimento da senha",
|
||||
"message": "Comprimento padrão da senha",
|
||||
"description": "Password length label in settings section"
|
||||
},
|
||||
"settings@length__hint":
|
||||
{
|
||||
"message": "Comprimento recomendado: 8—16",
|
||||
"message": "Comprimento recomendado: 8–16",
|
||||
"description": "Password length recommendatin in settings section"
|
||||
},
|
||||
"settings@lengthRange":
|
||||
{
|
||||
"message": "Intervalo do comprimento de ajuste rápido",
|
||||
"description": "Quick adjustment length range label in settings section"
|
||||
},
|
||||
"settings@include":
|
||||
{
|
||||
"message": "Incluir símbolos",
|
||||
@@ -167,5 +172,15 @@
|
||||
{
|
||||
"message": "Esses ajustes não serão salvos",
|
||||
"description": "Quick options hint"
|
||||
},
|
||||
"generator@include":
|
||||
{
|
||||
"message": "Incluir",
|
||||
"description": "Include characters button label"
|
||||
},
|
||||
"generator@exclude":
|
||||
{
|
||||
"message": "Excluir",
|
||||
"description": "Exclude characters button label"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,14 +85,19 @@
|
||||
},
|
||||
"settings@length":
|
||||
{
|
||||
"message": "Длина пароля",
|
||||
"message": "Длина пароля по умолчанию",
|
||||
"description": "Password length label in settings section"
|
||||
},
|
||||
"settings@length__hint":
|
||||
{
|
||||
"message": "Рекомендованная длина: 8—16",
|
||||
"message": "Рекомендованная длина: 8–16",
|
||||
"description": "Password length recommendatin in settings section"
|
||||
},
|
||||
"settings@lengthRange":
|
||||
{
|
||||
"message": "Диапазон длины для быстрых настроек",
|
||||
"description": "Quick adjustment length range label in settings section"
|
||||
},
|
||||
"settings@include":
|
||||
{
|
||||
"message": "Добавить символы",
|
||||
@@ -167,5 +172,15 @@
|
||||
{
|
||||
"message": "Эти настройки не будут сохранены",
|
||||
"description": "Quick options hint"
|
||||
},
|
||||
"generator@include":
|
||||
{
|
||||
"message": "Добавить",
|
||||
"description": "Include characters button label"
|
||||
},
|
||||
"generator@exclude":
|
||||
{
|
||||
"message": "Исключить",
|
||||
"description": "Exclude characters button label"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,14 +85,19 @@
|
||||
},
|
||||
"settings@length":
|
||||
{
|
||||
"message": "Довжина пароля",
|
||||
"message": "Довжина пароля за замовчуванням",
|
||||
"description": "Password length label in settings section"
|
||||
},
|
||||
"settings@length__hint":
|
||||
{
|
||||
"message": "Рекомендована довжина: 8—16",
|
||||
"message": "Рекомендована довжина: 8–16",
|
||||
"description": "Password length recommendatin in settings section"
|
||||
},
|
||||
"settings@lengthRange":
|
||||
{
|
||||
"message": "Діапазон довжини для швидких налаштувань",
|
||||
"description": "Quick adjustment length range label in settings section"
|
||||
},
|
||||
"settings@include":
|
||||
{
|
||||
"message": "Додати символи",
|
||||
@@ -167,5 +172,15 @@
|
||||
{
|
||||
"message": "Ці налаштування не будуть збережені",
|
||||
"description": "Quick options hint"
|
||||
},
|
||||
"generator@include":
|
||||
{
|
||||
"message": "Додати",
|
||||
"description": "Include characters button label"
|
||||
},
|
||||
"generator@exclude":
|
||||
{
|
||||
"message": "Виключити",
|
||||
"description": "Exclude characters button label"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
export default class ExtensionOptions { }
|
||||
export default class ExtensionOptions
|
||||
{
|
||||
public MinLength: number = 4;
|
||||
public MaxLength: number = 32;
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
.snow
|
||||
{
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.snowflake
|
||||
{
|
||||
--size: 1px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
|
||||
@media (prefers-color-scheme: light)
|
||||
{
|
||||
background: var(--colorPalettePlatinumBorderActive);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes snowfall
|
||||
{
|
||||
0%
|
||||
{
|
||||
transform: translate3d(var(--left-ini), 0, 0);
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
100%
|
||||
{
|
||||
transform: translate3d(var(--left-end), 610px, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 50
|
||||
{
|
||||
.snowflake:nth-child(#{$i})
|
||||
{
|
||||
--size: #{random(5)}px;
|
||||
--left-ini: #{random(20) - 10}vw;
|
||||
--left-end: #{random(20) - 10}vw;
|
||||
left: #{random(100)}vw;
|
||||
animation: snowfall #{5 + random(10)}s linear infinite;
|
||||
animation-delay: -#{random(10)}s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { GriffelStyle, makeStyles, shorthands, tokens } from "@fluentui/react-components";
|
||||
|
||||
const random = (max: number) => Math.floor(Math.random() * max);
|
||||
|
||||
export const useStyles = (count: number) => makeStyles({
|
||||
snow:
|
||||
{
|
||||
position: "absolute",
|
||||
...shorthands.overflow("hidden"),
|
||||
pointerEvents: "none",
|
||||
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
},
|
||||
snowflake:
|
||||
{
|
||||
"--size": "1px",
|
||||
width: "var(--size)",
|
||||
height: "var(--size)",
|
||||
backgroundColor: tokens.colorScrollbarOverlay,
|
||||
...shorthands.borderRadius(tokens.borderRadiusCircular),
|
||||
position: "absolute",
|
||||
top: "-5px",
|
||||
},
|
||||
...[...Array(count)].reduce(
|
||||
(acc, _, i): Record<string, GriffelStyle> => ({
|
||||
...acc,
|
||||
[`snowflake-${i}`]: {
|
||||
"--size": `${random(5)}px`,
|
||||
"--left-ini": `${random(20) - 10}vw`,
|
||||
"--left-end": `${random(20) - 10}vw`,
|
||||
left: `${random(100)}vw`,
|
||||
animationName: "snowfall",
|
||||
animationDuration: `${5 + random(10)}s`,
|
||||
animationTimingFunction: "linear",
|
||||
animationIterationCount: "infinite",
|
||||
animationDelay: `-${random(10)}s`,
|
||||
},
|
||||
}),
|
||||
{},
|
||||
),
|
||||
});
|
||||
+15
-8
@@ -1,11 +1,18 @@
|
||||
import "./Snow.scss";
|
||||
import { mergeClasses } from "@fluentui/react-components";
|
||||
import { useStyles } from "./Snow.styles";
|
||||
|
||||
const Snow = (): JSX.Element => (
|
||||
![0, 11].includes(new Date().getMonth()) ? <></> : // Only shows in December and January
|
||||
const SNOWFLAKES_NUM: number = 100;
|
||||
|
||||
<div className="snow">
|
||||
{ [...Array(50)].map((_, i) => <div key={ i } className="snowflake" />) }
|
||||
export default function Snow(): JSX.Element
|
||||
{
|
||||
const cls = useStyles(SNOWFLAKES_NUM)();
|
||||
|
||||
if (![0, 11].includes(new Date().getMonth()))
|
||||
return <></>;
|
||||
|
||||
return (
|
||||
<div className={ cls.snow }>
|
||||
{ [...Array(SNOWFLAKES_NUM)].map((_, i) => <div key={ i } className={ mergeClasses(cls.snowflake, cls[`snowflake-${i}`]) } />) }
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Snow;
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,3 +43,18 @@ p, ul, ol, li
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes snowfall
|
||||
{
|
||||
0%
|
||||
{
|
||||
transform: translate3d(var(--left-ini), 0, 0);
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
100%
|
||||
{
|
||||
transform: translate3d(var(--left-end), 610px, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user