diff --git a/packages/anastasis-webui/build.mjs b/packages/anastasis-webui/build.mjs
new file mode 100755
index 000000000..ebe914541
--- /dev/null
+++ b/packages/anastasis-webui/build.mjs
@@ -0,0 +1,147 @@
+#!/usr/bin/env node
+/*
+ This file is part of GNU Anastasis
+ (C) 2021-2022 Anastasis SARL
+
+ GNU Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ GNU Anastasis; see the file COPYING. If not, see
+ */
+/* eslint-disable no-undef */
+import esbuild from 'esbuild'
+import fs from 'fs';
+import path from "path"
+import sass from "sass";
+
+// eslint-disable-next-line no-undef
+const BASE = process.cwd();
+
+const preact = path.join(
+ BASE,
+ "node_modules",
+ "preact",
+ "compat",
+ "dist",
+ "compat.module.js",
+);
+
+const preactCompatPlugin = {
+ name: "preact-compat",
+ setup(build) {
+ build.onResolve({ filter: /^(react-dom|react)$/ }, (args) => {
+ return {
+ path: preact,
+ };
+ });
+ },
+};
+
+
+let GIT_ROOT = BASE
+while (!fs.existsSync(path.join(GIT_ROOT, '.git')) && GIT_ROOT !== '/') {
+ GIT_ROOT = path.join(GIT_ROOT, '../')
+}
+if (GIT_ROOT === '/') {
+ // eslint-disable-next-line no-undef
+ console.log("not found")
+ // eslint-disable-next-line no-undef
+ process.exit(1);
+}
+const GIT_HASH = GIT_ROOT === '/' ? undefined : git_hash()
+
+
+let _package = JSON.parse(fs.readFileSync(path.join(BASE, 'package.json')));
+
+function git_hash() {
+ const rev = fs.readFileSync(path.join(GIT_ROOT, '.git', 'HEAD')).toString().trim().split(/.*[: ]/).slice(-1)[0];
+ if (rev.indexOf('/') === -1) {
+ return rev;
+ } else {
+ return fs.readFileSync(path.join(GIT_ROOT, '.git', rev)).toString().trim();
+ }
+}
+
+const DEFAULT_SASS_FILTER = /\.(s[ac]ss|css)$/
+
+const buildSassPlugin = {
+ name: "custom-build-sass",
+ setup(build) {
+
+ build.onLoad({ filter: DEFAULT_SASS_FILTER }, ({ path: file }) => {
+ const resolveDir = path.dirname(file)
+ const { css: contents } = sass.compile(file, { loadPaths: ["./"] })
+
+ return {
+ resolveDir,
+ loader: 'css',
+ contents
+ }
+ });
+
+ },
+};
+
+function copyFilesPlugin(options) {
+ if (!options.basedir) {
+ options.basedir = process.cwd()
+ }
+ return {
+ name: "copy-files",
+ setup(build) {
+ build.onEnd(() => {
+ for (const fop of options) {
+ fs.copyFileSync(path.join(options.basedir, fop.src), path.join(options.basedir, fop.dest));
+ }
+ });
+ },
+ };
+}
+
+export const buildConfig = {
+ entryPoints: ['src/index.ts', 'src/stories.tsx'],
+ bundle: true,
+ outdir: 'dist',
+ minify: false,
+ loader: {
+ '.svg': 'dataurl',
+ '.ttf': 'file',
+ '.woff': 'file',
+ '.woff2': 'file',
+ '.eot': 'file',
+ },
+ target: [
+ 'es6'
+ ],
+ format: 'esm',
+ platform: 'browser',
+ sourcemap: true,
+ jsxFactory: 'h',
+ jsxFragment: 'Fragment',
+ define: {
+ '__VERSION__': `"${_package.version}"`,
+ '__GIT_HASH__': `"${GIT_HASH}"`,
+ },
+ plugins: [
+ preactCompatPlugin,
+ copyFilesPlugin([
+ {
+ src: "./src/index.html",
+ dest: "./dist/index.html",
+ },
+ ]),
+ buildSassPlugin
+ ],
+}
+
+await esbuild.build(buildConfig)
+
+
+
+
diff --git a/packages/anastasis-webui/clean_and_build.sh b/packages/anastasis-webui/clean_and_build.sh
deleted file mode 100755
index 9486848fe..000000000
--- a/packages/anastasis-webui/clean_and_build.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env bash
-
-echo clean
-rm -rf dist
-mkdir -p dist/fonts
-cp \
- src/scss/fonts/XRXV3I6Li01BKofINeaE.ttf \
- src/scss/fonts/materialdesignicons-webfont-4.9.95.ttf \
- src/scss/fonts/materialdesignicons-webfont-4.9.95.woff \
- src/scss/fonts/materialdesignicons-webfont-4.9.95.woff2 \
- dist/fonts
-
-VERSION=$(jq -r .version package.json)
-GIT_HASH=$(git rev-parse --short HEAD)
-
-function build_css() {
- pnpm exec sass -I . ./src/scss/main.scss dist/main.css
-}
-function build_js() {
- pnpm exec esbuild --log-level=error --define:process.env.__VERSION__=\"${VERSION}\" --define:process.env.__GIT_HASH__=\"${GIT_HASH}\" --bundle $1 --outdir=dist --target=es6 --loader:.svg=dataurl --format=iife --sourcemap --jsx-factory=h --jsx-fragment=Fragment --platform=browser --minify
-}
-
-function build_html() {
- cat html/$1.html \
- | sed -e '/ANASTASIS_SCRIPT_CONTENT/ {' -e 'r dist/main.js' -e 'd' -e '}' \
- | sed -e '/ANASTASIS_STYLE_CONTENT/ {' -e 'r dist/main.css' -e 'd' -e '}' \
- >dist/$1.html
-}
-
-function cleanup {
- trap - SIGHUP SIGINT SIGTERM SIGQUIT
- echo -n "Cleaning up... "
- wait
- kill -- -$$
- exit 1
-}
-trap cleanup SIGHUP SIGINT SIGTERM SIGQUIT
-
-set -e
-echo compile
-build_css &
-build_js src/main.ts &
-build_js src/stories.tsx &
-build_js src/main.test.ts &
-for file in $(find src/ -name test.ts); do build_js $file; done &
-wait -n
-wait -n
-wait -n
-wait -n
-wait -n
-pnpm run --silent test -- -R dot
-
-echo html
-build_html ui
-build_html ui-dev
-build_html stories
-
-if [ "WATCH" == "$1" ]; then
-
- echo watch mode
- echo Writing any file in the src directory will trigger a browser reload.
- echo Be sure that the watcher server is running.
- echo ./watch/serve.sh
- inotifywait -e close_write -r src -q -m | while read line; do
- echo $(date) $line
- build_js src/main.ts
- build_html ui-dev
- build_js src/stories.tsx
- build_html stories
- ./watch/send.sh '{"type":"RELOAD"}'
- done;
-fi
diff --git a/packages/anastasis-webui/dev.mjs b/packages/anastasis-webui/dev.mjs
index 3f4915ffc..0446603dc 100755
--- a/packages/anastasis-webui/dev.mjs
+++ b/packages/anastasis-webui/dev.mjs
@@ -14,87 +14,18 @@
You should have received a copy of the GNU Affero General Public License along with
GNU Anastasis; see the file COPYING. If not, see
*/
-/* eslint-disable no-undef */
-import esbuild from 'esbuild'
-import fs from 'fs';
-import WebSocket from "ws";
-import chokidar from "chokidar";
-const devServerBroadcastDelay = 500
-const devServerPort = 8002
-const wss = new WebSocket.Server({ port: devServerPort });
-const toWatch = ["./src"]
-
-function broadcast(file, event) {
- setTimeout(() => {
- wss.clients.forEach((client) => {
- if (client.readyState === WebSocket.OPEN) {
- console.log(new Date(), file)
- client.send(JSON.stringify(event));
- }
- });
- }, devServerBroadcastDelay);
-}
-
-const watcher = chokidar
- .watch(toWatch, {
- persistent: true,
- ignoreInitial: true,
- awaitWriteFinish: {
- stabilityThreshold: 100,
- pollInterval: 100,
- },
- })
- .on("error", (error) => console.error(error))
- .on("change", async (file) => {
- broadcast(file, { type: "RELOAD" });
- })
- .on("add", async (file) => {
- broadcast(file, { type: "RELOAD" });
- })
- .on("unlink", async (file) => {
- broadcast(file, { type: "RELOAD" });
- });
-
-/**
- * Just bundling UI Stories.
- * FIXME: add linaria CSS after implementing Material so CSS will be bundled
- */
-fs.writeFileSync("dist/index.html", fs.readFileSync("html/stories.html"))
-fs.writeFileSync("dist/mocha.css", fs.readFileSync("node_modules/mocha/mocha.css"))
-fs.writeFileSync("dist/mocha.js", fs.readFileSync("node_modules/mocha/mocha.js"))
-fs.writeFileSync("dist/mocha.js.map", fs.readFileSync("node_modules/mocha/mocha.js.map"))
-
-export const buildConfig = {
- entryPoints: ['src/main.ts', 'src/stories.tsx'],
- bundle: true,
- outdir: 'dist',
- minify: false,
- loader: {
- '.svg': 'dataurl',
- },
- target: [
- 'es6'
- ],
- format: 'iife',
- platform: 'browser',
- sourcemap: true,
- jsxFactory: 'h',
- jsxFragment: 'Fragment',
-}
-
-const server = await esbuild
- .serve({ servedir: 'dist' }, {
- ...buildConfig, outdir: 'dist'
- })
- .catch((e) => {
- console.log(e)
- process.exit(1)
- });
-
-console.log(`Dev server is ready at http://localhost:${server.port}/.
-The server is running a using websocket at ${devServerPort} to notify code change and live reload.
-`);
+import { serve } from "@gnu-taler/web-util/lib/index.node";
+import esbuild from 'esbuild';
+import { buildConfig } from "./build.mjs";
+buildConfig.inject = ['./node_modules/@gnu-taler/web-util/lib/live-reload.mjs']
+serve({
+ folder: './dist',
+ port: 8080,
+ source: './src',
+ development: true,
+ onUpdate: async () => esbuild.build(buildConfig)
+})
diff --git a/packages/anastasis-webui/html/stories.html b/packages/anastasis-webui/html/stories.html
deleted file mode 100644
index 9f41fdeaf..000000000
--- a/packages/anastasis-webui/html/stories.html
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
- Stories
-
-
-
-
-
-
-
-
diff --git a/packages/anastasis-webui/html/ui-dev.html b/packages/anastasis-webui/html/ui-dev.html
deleted file mode 100644
index 2790d5678..000000000
--- a/packages/anastasis-webui/html/ui-dev.html
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/anastasis-webui/package.json b/packages/anastasis-webui/package.json
index de70d05fc..c01856243 100644
--- a/packages/anastasis-webui/package.json
+++ b/packages/anastasis-webui/package.json
@@ -15,11 +15,12 @@
"dependencies": {
"@gnu-taler/anastasis-core": "workspace:*",
"@gnu-taler/taler-util": "workspace:*",
+ "@gnu-taler/web-util": "workspace:*",
"@types/chai": "^4.3.0",
"chai": "^4.3.6",
"date-fns": "2.29.2",
"jed": "1.1.1",
- "preact": "^10.5.15",
+ "preact": "10.11.3",
"preact-render-to-string": "^5.1.19",
"preact-router": "^3.2.1",
"qrcode-generator": "^1.4.4"
@@ -41,12 +42,9 @@
"bulma": "^0.9.3",
"bulma-checkbox": "^1.1.1",
"bulma-radio": "^1.1.1",
- "chokidar": "^3.5.3",
- "eslint-plugin-header": "^3.1.1",
"jssha": "^3.2.0",
"mocha": "^9.2.0",
- "sass": "1.32.13",
- "typescript": "^4.8.4",
- "ws": "7.4.5"
+ "sass": "1.56.1",
+ "typescript": "^4.8.4"
}
-}
+}
\ No newline at end of file
diff --git a/packages/anastasis-webui/src/components/menu/SideBar.tsx b/packages/anastasis-webui/src/components/menu/SideBar.tsx
index 51e854944..3dac73e04 100644
--- a/packages/anastasis-webui/src/components/menu/SideBar.tsx
+++ b/packages/anastasis-webui/src/components/menu/SideBar.tsx
@@ -22,7 +22,7 @@
import { BackupStates, RecoveryStates } from "@gnu-taler/anastasis-core";
import { Fragment, h, VNode } from "preact";
import { useAnastasisContext } from "../../context/anastasis.js";
-import { Translate } from "../../i18n/index.js";
+import { useTranslationContext } from "../../context/translation.js";
interface Props {
mobile?: boolean;
@@ -34,6 +34,7 @@ const VERSION_WITH_HASH = GIT_HASH ? `${VERSION}-${GIT_HASH}` : VERSION;
export function Sidebar({ mobile }: Props): VNode {
const reducer = useAnastasisContext()!;
+ const { i18n } = useTranslationContext();
function saveSession(): void {
const state = reducer.exportState();
@@ -64,7 +65,7 @@ export function Sidebar({ mobile }: Props): VNode {
{!reducer.currentReducerState && (
)}