feat: Implement ErrorBoundary class for global error handling

feat: Refactor Session class to use LocalStorageService for session management

feat: Enhance BasicButton component with configuration options and event handling

style: Update SASS variables to CSS custom properties for better theming support

style: Modify app.sass to include Bootstrap with legacy import

chore: Update settings.ts to handle session initialization and error notifications

fix: Improve buttonType definition for better readability

chore: Refactor parse.ts for cleaner file handling and keyword replacement

chore: Enhance syncConfig.ts with TypeScript interfaces and async file operations

chore: Update v2.ts to modify manifest.json for compatibility with manifest version 2

chore: Revise tsconfig.json for stricter type checking and improved module resolution

chore: Refactor vite.config.ts for better build configuration and asset management
This commit is contained in:
JonasPfalzgraf 2025-07-11 16:53:48 +02:00
parent 8f99895c88
commit 482151f980
24 changed files with 1321 additions and 418 deletions

View file

@ -1,72 +1,72 @@
import * as fs from "fs";
import * as path from "path";
const appConfig = JSON.parse(fs.readFileSync("./app.config.json", "utf8"));
const DEPLOY_TARGET = "./dist/";
import * as fs from 'fs';
import * as path from 'path';
const appConfig = JSON.parse(fs.readFileSync('./app.config.json', 'utf8'));
const DEPLOY_TARGET = './dist/';
function findCssFileNames(source: string): string[] {
let files: string[] = [];
const dir = fs.readdirSync(source);
dir.forEach(function (file: string) {
const sourceFile = path.join(source, file);
const stat = fs.lstatSync(sourceFile);
if (stat.isDirectory()) {
files = files.concat(findCssFileNames(sourceFile));
} else {
if (path.extname(sourceFile) == ".css") {
files.push(file);
}
}
});
return files;
let files: string[] = [];
const dir = fs.readdirSync(source);
dir.forEach(function (file: string) {
const sourceFile = path.join(source, file);
const stat = fs.lstatSync(sourceFile);
if (stat.isDirectory()) {
files = files.concat(findCssFileNames(sourceFile));
} else {
if (path.extname(sourceFile) == '.css') {
files.push(file);
}
}
});
return files;
}
function findHtmlFilesRecursive(source: string): string[] {
let files: string[] = [];
const dir = fs.readdirSync(source);
dir.forEach(function (file: string) {
const sourceFile = path.join(source, file);
const stat = fs.lstatSync(sourceFile);
if (stat.isDirectory()) {
files = files.concat(findHtmlFilesRecursive(sourceFile));
} else {
if (path.extname(sourceFile) == ".html") {
files.push(sourceFile);
}
}
});
return files;
let files: string[] = [];
const dir = fs.readdirSync(source);
dir.forEach(function (file: string) {
const sourceFile = path.join(source, file);
const stat = fs.lstatSync(sourceFile);
if (stat.isDirectory()) {
files = files.concat(findHtmlFilesRecursive(sourceFile));
} else {
if (path.extname(sourceFile) == '.html') {
files.push(sourceFile);
}
}
});
return files;
}
function replaceKeywordsInHtmlFile(file: string) {
let content = fs.readFileSync(file, "utf8");
const pairs: { key: string; value: string }[] = appConfig.htmlTemplatePairs;
pairs.forEach(function (pair: { key: string; value: string }) {
//@ts-ignore
content = content.replaceAll(pair.key, pair.value);
});
file = file.replace("public\\", DEPLOY_TARGET);
fs.writeFileSync(file, content);
let content = fs.readFileSync(file, 'utf8');
const pairs: { key: string; value: string }[] = appConfig.htmlTemplatePairs;
pairs.forEach(function (pair: { key: string; value: string }) {
//@ts-ignore
content = content.replaceAll(pair.key, pair.value);
});
file = file.replace('public\\', DEPLOY_TARGET);
fs.writeFileSync(file, content);
}
function buildHtmlFiles(source: string) {
const files = findHtmlFilesRecursive(source);
files.forEach(function (file: string) {
replaceKeywordsInHtmlFile(file);
});
const files = findHtmlFilesRecursive(source);
files.forEach(function (file: string) {
replaceKeywordsInHtmlFile(file);
});
}
findCssFileNames(DEPLOY_TARGET).forEach((file: string) => {
const files = findHtmlFilesRecursive(DEPLOY_TARGET);
files.forEach(function (htmlFile: string) {
let content = fs.readFileSync(htmlFile, "utf8");
content = content.replace(
"</head>",
`<link rel="stylesheet" href="./assets/${file}">\n</head>`
);
fs.writeFileSync(htmlFile, content);
});
const files = findHtmlFilesRecursive(DEPLOY_TARGET);
files.forEach(function (htmlFile: string) {
let content = fs.readFileSync(htmlFile, 'utf8');
content = content.replace(
'</head>',
`<link rel="stylesheet" href="./assets/${file}">\n</head>`
);
fs.writeFileSync(htmlFile, content);
});
});
buildHtmlFiles(DEPLOY_TARGET);
console.log("Parsed Files: ", findHtmlFilesRecursive(DEPLOY_TARGET));
console.log('Parsed Files: ', findHtmlFilesRecursive(DEPLOY_TARGET));

View file

@ -1,23 +1,151 @@
// @ts-ignore
const fs = require('fs');
import * as fs from 'fs';
const appConfig = JSON.parse(fs.readFileSync('./app.config.json', 'utf8'));
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
const manifestJson = JSON.parse(fs.readFileSync('./public/manifest.json', 'utf8'));
interface AppConfig {
AppData: {
id: string;
name: string;
version: string;
description: string;
repository: {
type: string;
url: string;
};
license: string;
homepage: string;
bugs: {
url: string;
};
authors: Array<{
name: string;
email: string;
}>;
};
htmlTemplatePairs: Array<{
key: string;
value: string;
}>;
}
pkg.version = appConfig.AppData.version;
pkg.name = appConfig.AppData.id;
pkg.authors = appConfig.AppData.authors;
pkg.description = appConfig.AppData.description;
pkg.homepage = appConfig.AppData.homepage;
pkg.license = appConfig.AppData.license;
pkg.repository = appConfig.AppData.repository;
pkg.bugs = appConfig.AppData.bugs;
interface PackageJson {
version: string;
name: string;
authors: Array<{
name: string;
email: string;
}>;
description: string;
homepage: string;
license: string;
repository: {
type: string;
url: string;
};
bugs: {
url: string;
};
[key: string]: unknown;
}
manifestJson.version = appConfig.AppData.version;
manifestJson.name = appConfig.AppData.name;
manifestJson.description = appConfig.AppData.description;
manifestJson.homepage_url = appConfig.AppData.homepage;
interface ManifestJson {
version: string;
name: string;
description: string;
homepage_url: string;
[key: string]: unknown;
}
fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
fs.writeFileSync('./public/manifest.json', JSON.stringify(manifestJson, null, 2));
class ConfigSyncer {
private readonly appConfigPath = './app.config.json';
private readonly packageJsonPath = './package.json';
private readonly manifestJsonPath = './public/manifest.json';
public async sync(): Promise<void> {
try {
console.log('Starting configuration synchronization...');
const appConfig = await this.loadAppConfig();
const packageJson = await this.loadPackageJson();
const manifestJson = await this.loadManifestJson();
this.updatePackageJson(packageJson, appConfig.AppData);
this.updateManifestJson(manifestJson, appConfig.AppData);
await this.savePackageJson(packageJson);
await this.saveManifestJson(manifestJson);
console.log('Configuration synchronization completed successfully!');
} catch (error) {
console.error('Failed to sync configuration:', error);
process.exit(1);
}
}
private async loadAppConfig(): Promise<AppConfig> {
try {
const content = await fs.promises.readFile(this.appConfigPath, 'utf8');
return JSON.parse(content) as AppConfig;
} catch (error) {
throw new Error(`Failed to load app config: ${error}`);
}
}
private async loadPackageJson(): Promise<PackageJson> {
try {
const content = await fs.promises.readFile(this.packageJsonPath, 'utf8');
return JSON.parse(content) as PackageJson;
} catch (error) {
throw new Error(`Failed to load package.json: ${error}`);
}
}
private async loadManifestJson(): Promise<ManifestJson> {
try {
const content = await fs.promises.readFile(this.manifestJsonPath, 'utf8');
return JSON.parse(content) as ManifestJson;
} catch (error) {
throw new Error(`Failed to load manifest.json: ${error}`);
}
}
private updatePackageJson(packageJson: PackageJson, appData: AppConfig['AppData']): void {
packageJson.version = appData.version;
packageJson.name = appData.id;
packageJson.authors = appData.authors;
packageJson.description = appData.description;
packageJson.homepage = appData.homepage;
packageJson.license = appData.license;
packageJson.repository = appData.repository;
packageJson.bugs = appData.bugs;
}
private updateManifestJson(manifestJson: ManifestJson, appData: AppConfig['AppData']): void {
manifestJson.version = appData.version;
manifestJson.name = appData.name;
manifestJson.description = appData.description;
manifestJson.homepage_url = appData.homepage;
}
private async savePackageJson(packageJson: PackageJson): Promise<void> {
try {
const content = JSON.stringify(packageJson, null, 2);
await fs.promises.writeFile(this.packageJsonPath, content, 'utf8');
console.log('✓ package.json updated');
} catch (error) {
throw new Error(`Failed to save package.json: ${error}`);
}
}
private async saveManifestJson(manifestJson: ManifestJson): Promise<void> {
try {
const content = JSON.stringify(manifestJson, null, 2);
await fs.promises.writeFile(this.manifestJsonPath, content, 'utf8');
console.log('✓ manifest.json updated');
} catch (error) {
throw new Error(`Failed to save manifest.json: ${error}`);
}
}
}
// Run the sync process
const syncer = new ConfigSyncer();
syncer.sync().catch(console.error);

View file

@ -3,44 +3,44 @@ const fs = require('fs');
const manifest = JSON.parse(fs.readFileSync('./dist/manifest.json', 'utf8'));
manifest.manifest_version = 2
manifest.manifest_version = 2;
manifest.background.scripts = []
manifest.background.scripts = [];
manifest.background.scripts.push(manifest.background.service_worker)
delete manifest.background.type
delete manifest.background.service_worker
manifest.background.persistent = true
manifest.background.scripts.push(manifest.background.service_worker);
delete manifest.background.type;
delete manifest.background.service_worker;
manifest.background.persistent = true;
if (manifest.host_permissions) {
manifest.permissions.push(manifest.host_permissions)
manifest.permissions.push(manifest.host_permissions);
}
if (manifest.optional_host_permissions) {
manifest.permissions.push(manifest.optional_host_permissions)
manifest.permissions.push(manifest.optional_host_permissions);
}
delete manifest.host_permissions
delete manifest.optional_host_permissions
delete manifest.host_permissions;
delete manifest.optional_host_permissions;
let newContentSecurityPolicy = ""
let newContentSecurityPolicy = '';
try {
for (const policy of manifest.content_security_policy) {
newContentSecurityPolicy += policy.key + "'" + policy.value + "'" + " "
}
for (const policy of manifest.content_security_policy) {
newContentSecurityPolicy += policy.key + "'" + policy.value + "'" + ' ';
}
} catch (e) {
newContentSecurityPolicy = "default-src 'self'"
newContentSecurityPolicy = "default-src 'self'";
}
manifest.content_security_policy = newContentSecurityPolicy
manifest.content_security_policy = newContentSecurityPolicy;
try {
manifest.web_accessible_resources = manifest.web_accessible_resources.resources
manifest.web_accessible_resources = manifest.web_accessible_resources.resources;
} catch (e) {
manifest.web_accessible_resources = []
manifest.web_accessible_resources = [];
}
if (manifest.action) {
manifest.browser_action = manifest.action
manifest.browser_action = manifest.action;
}
delete manifest.action
delete manifest.action;
fs.writeFileSync('./dist/manifest.json', JSON.stringify(manifest, null, 2));