Start working on using preact and TSX.
This commit is contained in:
parent
40bb264107
commit
a95c6d250f
File diff suppressed because one or more lines are too long
|
@ -50,7 +50,7 @@
|
|||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": {
|
||||
"extensions": [".js", ".ts"]
|
||||
"extensions": [".js", ".ts", ".tsx"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
node_modules
|
||||
package-lock.json
|
||||
dist
|
||||
dist
|
||||
.eslintcache
|
|
@ -29,6 +29,7 @@
|
|||
"mini-css-extract-plugin": "^1.6.0",
|
||||
"node-sass": "^6.0.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"preact": "^10.5.13",
|
||||
"prettier": "^2.3.0",
|
||||
"prismjs": "^1.23.0",
|
||||
"qr-scanner": "^1.2.0",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
npx eslint --cache -c .eslintrc.json "$@" --ext .js,.ts
|
||||
npx eslint --cache -c .eslintrc.json "$@" --ext .js,.ts,.tsx
|
36
src/elements/ReactTile.tsx
Normal file
36
src/elements/ReactTile.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { Component, JSX } from "preact";
|
||||
|
||||
export type TileParams = {
|
||||
condition?: boolean;
|
||||
color?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
icon?: string;
|
||||
iconText?: string;
|
||||
onclick: () => void;
|
||||
};
|
||||
|
||||
export class Tile extends Component<TileParams, unknown> {
|
||||
render(): JSX.Element {
|
||||
if (this.props.condition == false) return <></>;
|
||||
|
||||
return (
|
||||
<a class="uk-link-heading" onClick={this.props.onclick}>
|
||||
<div class={"uk-padding-small uk-background-" + (this.props.color || "primary")}>
|
||||
<p class="uk-h4">
|
||||
{this.props.title}
|
||||
{typeof this.props.icon == "string" && (
|
||||
<span
|
||||
class="uk-icon uk-margin-small-left"
|
||||
uk-icon={`icon: ${this.props.icon}`}
|
||||
role="img"
|
||||
aria-label={this.props.iconText}
|
||||
></span>
|
||||
)}
|
||||
</p>
|
||||
<span class="uk-text-muted">{this.props.description}</span>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -107,6 +107,9 @@ document.addEventListener(
|
|||
Object.entries(translations).map(([k, v]) => [k, { translation: v }]),
|
||||
),
|
||||
interpolation: {
|
||||
escape: (str) => {
|
||||
return str;
|
||||
},
|
||||
format: function (value: unknown, format, _): string {
|
||||
if (format === "until_date" && value instanceof Date)
|
||||
return formatDistance(new Date(), new Date(value), pageState.language);
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
import { Page } from "../types/Page";
|
||||
import { Tile } from "../elements/Tile";
|
||||
import { lookupSelf } from "../api/sys/lookupSelf";
|
||||
import { makeElement } from "z-makeelement";
|
||||
import { prePageChecks, setErrorText } from "../pageUtils";
|
||||
import i18next from "i18next";
|
||||
|
||||
export class HomePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
await this.router.setPageContent("");
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
|
||||
this.state.baseMount = "";
|
||||
this.state.secretPath = [];
|
||||
this.state.secretItem = "";
|
||||
this.state.secretVersion = null;
|
||||
|
||||
const homePageContent = makeElement({ tag: "div" });
|
||||
await this.router.setPageContent(homePageContent);
|
||||
const textList = makeElement({
|
||||
tag: "ul",
|
||||
class: "uk-nav",
|
||||
children: [
|
||||
makeElement({
|
||||
tag: "li",
|
||||
children: makeElement({
|
||||
tag: "span",
|
||||
html: i18next.t("home_vaulturl_text", { text: this.state.apiURL }),
|
||||
}),
|
||||
}),
|
||||
makeElement({
|
||||
tag: "li",
|
||||
children: makeElement({
|
||||
tag: "a",
|
||||
text: i18next.t("home_password_generator_btn"),
|
||||
onclick: async () => {
|
||||
await this.router.changePage("PW_GEN");
|
||||
},
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
homePageContent.appendChild(textList);
|
||||
|
||||
try {
|
||||
const selfTokenInfo = await lookupSelf();
|
||||
textList.appendChild(
|
||||
makeElement({
|
||||
tag: "li",
|
||||
text: i18next.t("home_your_token_expires_in", {
|
||||
date: new Date(selfTokenInfo.expire_time),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
if (error.message == "permission denied") {
|
||||
this.state.token = "";
|
||||
await this.router.changePage("LOGIN");
|
||||
}
|
||||
}
|
||||
|
||||
homePageContent.appendChild(
|
||||
makeElement({
|
||||
tag: "div",
|
||||
class:
|
||||
"uk-child-width-1-1@s uk-child-width-1-2@m uk-grid-small uk-grid-match uk-margin-top",
|
||||
attributes: { "uk-grid": "" },
|
||||
children: [
|
||||
Tile({
|
||||
title: i18next.t("home_secrets_title"),
|
||||
description: i18next.t("home_secrets_description"),
|
||||
icon: "file-edit",
|
||||
onclick: async () => {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
},
|
||||
}),
|
||||
Tile({
|
||||
title: i18next.t("home_access_title"),
|
||||
description: i18next.t("home_access_description"),
|
||||
icon: "users",
|
||||
onclick: async () => {
|
||||
await this.router.changePage("ACCESS_HOME");
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
get name(): string {
|
||||
return i18next.t("home_page_title");
|
||||
}
|
||||
}
|
86
src/pages/Home.tsx
Normal file
86
src/pages/Home.tsx
Normal file
|
@ -0,0 +1,86 @@
|
|||
import { Page } from "../types/Page";
|
||||
import { Tile } from "../elements/ReactTile";
|
||||
import { TokenInfo } from "../api/types/token";
|
||||
import { lookupSelf } from "../api/sys/lookupSelf";
|
||||
import { prePageChecks, setErrorText } from "../pageUtils";
|
||||
import { render } from "preact";
|
||||
import i18next from "i18next";
|
||||
|
||||
export class HomePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
await this.router.setPageContent("");
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
|
||||
this.state.baseMount = "";
|
||||
this.state.secretPath = [];
|
||||
this.state.secretItem = "";
|
||||
this.state.secretVersion = null;
|
||||
|
||||
let selfTokenInfo: TokenInfo;
|
||||
try {
|
||||
selfTokenInfo = await lookupSelf();
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
if (error.message == "permission denied") {
|
||||
this.state.token = "";
|
||||
await this.router.changePage("LOGIN");
|
||||
}
|
||||
}
|
||||
|
||||
render(
|
||||
<div>
|
||||
<ul id="textList" class="uk-nav">
|
||||
<li>
|
||||
<span>{i18next.t("home_vaulturl_text", { text: this.state.apiURL })}</span>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await this.router.changePage("PW_GEN");
|
||||
}}
|
||||
>
|
||||
{i18next.t("home_password_generator_btn")}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
{i18next.t("home_your_token_expires_in", {
|
||||
date: new Date(selfTokenInfo.expire_time),
|
||||
})}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div
|
||||
class="uk-child-width-1-1@s uk-child-width-1-2@m uk-grid-small uk-grid-match uk-margin-top"
|
||||
uk-grid
|
||||
>
|
||||
<Tile
|
||||
title={i18next.t("home_secrets_title")}
|
||||
description={i18next.t("home_secrets_description")}
|
||||
icon="file-edit"
|
||||
onclick={async () => {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
}}
|
||||
/>
|
||||
<Tile
|
||||
title={i18next.t("home_access_title")}
|
||||
description={i18next.t("home_access_description")}
|
||||
icon="users"
|
||||
onclick={async () => {
|
||||
await this.router.changePage("ACCESS_HOME");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("home_page_title");
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@
|
|||
"strictBindCallApply": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node"
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "preact",
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue