1
0
Fork 0

Start working on using preact and TSX.

This commit is contained in:
Kitteh 2021-05-22 09:50:55 +01:00
parent 40bb264107
commit a95c6d250f
11 changed files with 134 additions and 102 deletions

File diff suppressed because one or more lines are too long

View file

@ -50,7 +50,7 @@
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".ts"]
"extensions": [".js", ".ts", ".tsx"]
}
}
}

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
node_modules
package-lock.json
dist
.eslintcache

View file

@ -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",

View file

@ -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

View 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>
);
}
}

View file

@ -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);

View file

@ -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
View 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");
}
}

View file

@ -8,6 +8,8 @@
"strictBindCallApply": true,
"noImplicitThis": true,
"allowJs": true,
"moduleResolution": "node"
"moduleResolution": "node",
"jsx": "react-jsx",
"jsxImportSource": "preact",
}
}