Add tsx syntax to PwGen.
This commit is contained in:
parent
2c87ceb24c
commit
651b490ea5
|
@ -13,7 +13,6 @@ export class Form extends Component<FormProps, unknown> {
|
||||||
<form
|
<form
|
||||||
onSubmit={(e: Event) => {
|
onSubmit={(e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log(this.ref.current);
|
|
||||||
this.props.onSubmit(new FormData(this.ref.current));
|
this.props.onSubmit(new FormData(this.ref.current));
|
||||||
}}
|
}}
|
||||||
ref={this.ref}
|
ref={this.ref}
|
||||||
|
|
|
@ -1,142 +0,0 @@
|
||||||
import { CopyableInputBox, CopyableInputBoxType } from "../elements/CopyableInputBox";
|
|
||||||
import { Form } from "../elements/Form";
|
|
||||||
import { Margin } from "../elements/Margin";
|
|
||||||
import { Option } from "../elements/Option";
|
|
||||||
import { Page } from "../types/Page";
|
|
||||||
import { makeElement } from "z-makeelement";
|
|
||||||
import i18next from "i18next";
|
|
||||||
|
|
||||||
const passwordLengthMin = 1;
|
|
||||||
const passwordLengthMax = 64;
|
|
||||||
const passwordLengthDefault = 24;
|
|
||||||
|
|
||||||
function random() {
|
|
||||||
if (
|
|
||||||
typeof window.crypto?.getRandomValues === "function" &&
|
|
||||||
typeof window.Uint32Array === "function"
|
|
||||||
) {
|
|
||||||
return window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.random();
|
|
||||||
}
|
|
||||||
|
|
||||||
const lowerCase = "abcdefghijklmnopqrstuvwxyz";
|
|
||||||
const upperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
const numbers = "1234567890";
|
|
||||||
const special = "!#$%&()*+,-./:;<=>?@[]^_{|}~";
|
|
||||||
|
|
||||||
const alphabets = {
|
|
||||||
SECURE: lowerCase + upperCase + numbers + special,
|
|
||||||
SMOL: lowerCase + numbers,
|
|
||||||
HEX: "123456789ABCDEF",
|
|
||||||
};
|
|
||||||
|
|
||||||
const passwordOptionsDefault = {
|
|
||||||
length: passwordLengthDefault,
|
|
||||||
alphabet: alphabets.SECURE,
|
|
||||||
};
|
|
||||||
|
|
||||||
function genPassword(options = passwordOptionsDefault) {
|
|
||||||
let pw = "";
|
|
||||||
options = { ...passwordOptionsDefault, ...options };
|
|
||||||
const pwArray = options.alphabet.split("");
|
|
||||||
for (let i = 0; i < options.length; i++) {
|
|
||||||
pw = pw.concat(pwArray[Math.floor(random() * pwArray.length)]);
|
|
||||||
}
|
|
||||||
return pw;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PwGenPage extends Page {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordBox: CopyableInputBoxType;
|
|
||||||
passwordLengthTitle: HTMLTitleElement;
|
|
||||||
passwordLengthRange: HTMLInputElement;
|
|
||||||
passwordAlphabet: HTMLSelectElement;
|
|
||||||
passwordForm: HTMLFormElement;
|
|
||||||
|
|
||||||
async render(): Promise<void> {
|
|
||||||
await this.router.setPageContent("");
|
|
||||||
this.passwordBox = CopyableInputBox(genPassword(passwordOptionsDefault));
|
|
||||||
|
|
||||||
this.passwordLengthTitle = makeElement({
|
|
||||||
tag: "h4",
|
|
||||||
text: this.getPasswordLengthText(),
|
|
||||||
}) as HTMLTitleElement;
|
|
||||||
|
|
||||||
this.passwordLengthRange = makeElement({
|
|
||||||
tag: "input",
|
|
||||||
name: "length",
|
|
||||||
class: ["uk-range", "uk-width-1-2"],
|
|
||||||
attributes: {
|
|
||||||
type: "range",
|
|
||||||
value: passwordLengthDefault.toString(),
|
|
||||||
max: passwordLengthMax.toString(),
|
|
||||||
min: passwordLengthMin.toString(),
|
|
||||||
},
|
|
||||||
}) as HTMLInputElement;
|
|
||||||
|
|
||||||
this.passwordLengthRange.addEventListener("input", this.updatePassword.bind(this));
|
|
||||||
|
|
||||||
this.passwordAlphabet = makeElement({
|
|
||||||
tag: "select",
|
|
||||||
class: ["uk-select", "uk-width-1-2"],
|
|
||||||
children: [
|
|
||||||
Option("a-z a-Z 0-9 specials", alphabets.SECURE),
|
|
||||||
Option("a-z 0-9", alphabets.SMOL),
|
|
||||||
Option("A-F 1-9", alphabets.HEX),
|
|
||||||
],
|
|
||||||
}) as HTMLSelectElement;
|
|
||||||
|
|
||||||
this.passwordForm = Form(
|
|
||||||
[
|
|
||||||
this.passwordLengthTitle,
|
|
||||||
Margin(this.passwordLengthRange),
|
|
||||||
Margin(this.passwordAlphabet),
|
|
||||||
Margin(this.passwordBox),
|
|
||||||
Margin(
|
|
||||||
makeElement({
|
|
||||||
tag: "button",
|
|
||||||
text: i18next.t("gen_password_btn"),
|
|
||||||
class: ["uk-button", "uk-button-primary", "uk-margin-bottom"],
|
|
||||||
attributes: { type: "submit" },
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
(_) => this.updatePassword(),
|
|
||||||
);
|
|
||||||
await this.router.setPageContent(this.passwordForm);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPasswordLengthText(): string {
|
|
||||||
return i18next.t("password_length_title", {
|
|
||||||
min: this?.passwordLengthRange?.value || 24,
|
|
||||||
max: passwordLengthMax,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePassword(): void {
|
|
||||||
this.passwordLengthTitle.innerText = this.getPasswordLengthText();
|
|
||||||
this.passwordBox.setText(
|
|
||||||
genPassword({
|
|
||||||
length: this.passwordLengthRange.value as unknown as number,
|
|
||||||
alphabet: this.passwordAlphabet.value,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async cleanup(): Promise<void> {
|
|
||||||
this.passwordBox = undefined;
|
|
||||||
this.passwordLengthTitle = undefined;
|
|
||||||
this.passwordLengthRange = undefined;
|
|
||||||
this.passwordAlphabet = undefined;
|
|
||||||
this.passwordForm = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name(): string {
|
|
||||||
return i18next.t("password_generator_title");
|
|
||||||
}
|
|
||||||
}
|
|
153
src/pages/PwGen.tsx
Normal file
153
src/pages/PwGen.tsx
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
import { Component, JSX, createRef, render } from "preact";
|
||||||
|
import { CopyableInputBox } from "../elements/ReactCopyableInputBox";
|
||||||
|
import { Form } from "../elements/ReactForm";
|
||||||
|
import { Margin } from "../elements/ReactMargin";
|
||||||
|
import { Page } from "../types/Page";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
const passwordLengthMin = 1;
|
||||||
|
const passwordLengthMax = 64;
|
||||||
|
const passwordLengthDefault = 24;
|
||||||
|
|
||||||
|
function random() {
|
||||||
|
if (
|
||||||
|
typeof window.crypto?.getRandomValues === "function" &&
|
||||||
|
typeof window.Uint32Array === "function"
|
||||||
|
) {
|
||||||
|
return window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.random();
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerCase = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const upperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
const numbers = "1234567890";
|
||||||
|
const special = "!#$%&()*+,-./:;<=>?@[]^_{|}~";
|
||||||
|
|
||||||
|
const alphabets = {
|
||||||
|
SECURE: lowerCase + upperCase + numbers + special,
|
||||||
|
SMOL: lowerCase + numbers,
|
||||||
|
HEX: "123456789ABCDEF",
|
||||||
|
};
|
||||||
|
|
||||||
|
const passwordOptionsDefault = {
|
||||||
|
length: passwordLengthDefault,
|
||||||
|
alphabet: alphabets.SECURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
function genPassword(options = passwordOptionsDefault) {
|
||||||
|
let pw = "";
|
||||||
|
options = { ...passwordOptionsDefault, ...options };
|
||||||
|
const pwArray = options.alphabet.split("");
|
||||||
|
for (let i = 0; i < options.length; i++) {
|
||||||
|
pw = pw.concat(pwArray[Math.floor(random() * pwArray.length)]);
|
||||||
|
}
|
||||||
|
return pw;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PasswordGeneratorState = {
|
||||||
|
length: number;
|
||||||
|
alphabet: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class PasswordGenerator extends Component<unknown, PasswordGeneratorState> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
length: passwordOptionsDefault.length,
|
||||||
|
alphabet: passwordOptionsDefault.alphabet,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
passwordLengthSlider = createRef<HTMLInputElement>();
|
||||||
|
alphabetSelector = createRef<HTMLSelectElement>();
|
||||||
|
|
||||||
|
getPasswordLengthText(length: number): string {
|
||||||
|
return i18next.t("password_length_title", {
|
||||||
|
min: length,
|
||||||
|
max: passwordLengthMax,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAlphabet(): void {
|
||||||
|
this.setState({
|
||||||
|
alphabet: this.alphabetSelector.current.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLength(): void {
|
||||||
|
this.setState({
|
||||||
|
length: parseInt(this.passwordLengthSlider.current.value, 10),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
this.updateLength();
|
||||||
|
this.updateAlphabet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// createRef
|
||||||
|
render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Form onSubmit={() => this.onSubmit()}>
|
||||||
|
<Margin>
|
||||||
|
<h4>{this.getPasswordLengthText(this.state.length)}</h4>
|
||||||
|
</Margin>
|
||||||
|
<Margin>
|
||||||
|
<input
|
||||||
|
class="uk-range uk-width-1-2"
|
||||||
|
name="length"
|
||||||
|
type="range"
|
||||||
|
value={this.state.length}
|
||||||
|
max={passwordLengthMax.toString()}
|
||||||
|
min={passwordLengthMin.toString()}
|
||||||
|
ref={this.passwordLengthSlider}
|
||||||
|
onInput={() => {
|
||||||
|
this.updateLength();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Margin>
|
||||||
|
<Margin>
|
||||||
|
<select
|
||||||
|
class="uk-select uk-width-1-2"
|
||||||
|
ref={this.alphabetSelector}
|
||||||
|
onInput={() => {
|
||||||
|
this.updateAlphabet();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value={alphabets.SECURE}>a-z a-Z 0-9 specials</option>
|
||||||
|
<option value={alphabets.SMOL}>a-z 0-9</option>
|
||||||
|
<option value={alphabets.HEX}>A-F 1-9</option>
|
||||||
|
</select>
|
||||||
|
</Margin>
|
||||||
|
|
||||||
|
<CopyableInputBox
|
||||||
|
text={genPassword({
|
||||||
|
length: this.state.length,
|
||||||
|
alphabet: this.state.alphabet,
|
||||||
|
})}
|
||||||
|
copyable
|
||||||
|
/>
|
||||||
|
<Margin>
|
||||||
|
<button class="uk-button uk-button-primary uk-margin-bottom" type="submit">
|
||||||
|
{i18next.t("gen_password_btn")}
|
||||||
|
</button>
|
||||||
|
</Margin>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PwGenPage extends Page {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async render(): Promise<void> {
|
||||||
|
render(<PasswordGenerator />, this.router.pageContentElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
get name(): string {
|
||||||
|
return i18next.t("password_generator_title");
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,10 +17,14 @@ $global-danger-background: #bf616a;
|
||||||
|
|
||||||
$button-primary-background: #5e81ac;
|
$button-primary-background: #5e81ac;
|
||||||
$progress-bar-background: #5e81ac;
|
$progress-bar-background: #5e81ac;
|
||||||
|
|
||||||
$form-radio-background: $global-secondary-background;
|
$form-radio-background: $global-secondary-background;
|
||||||
|
|
||||||
$form-select-option-color: $global-muted-color;
|
$form-select-option-color: $global-muted-color;
|
||||||
|
|
||||||
|
$form-range-track-background: $global-link-color;
|
||||||
|
$form-range-track-focus-background: $global-link-hover-color;
|
||||||
|
|
||||||
// Keep these in same order as https://github.com/uikit/uikit/blob/develop/src/scss/components/_import.scss
|
// Keep these in same order as https://github.com/uikit/uikit/blob/develop/src/scss/components/_import.scss
|
||||||
@import "uikit/src/scss/variables.scss";
|
@import "uikit/src/scss/variables.scss";
|
||||||
@import "uikit/src/scss/mixins.scss";
|
@import "uikit/src/scss/mixins.scss";
|
||||||
|
|
Loading…
Reference in a new issue