Loading zip file OK, Still need to clenup and refactor loading and compilation
This commit is contained in:
parent
77da5b21ed
commit
1f8e27111a
21 changed files with 703 additions and 65 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
|||
# Dist electron
|
||||
dist-electron
|
||||
release
|
||||
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
|
|
@ -25,3 +26,9 @@ logs
|
|||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# public assets
|
||||
public/assets
|
||||
|
||||
# zip files
|
||||
static/data/*.zip
|
||||
|
|
|
|||
2
.npmrc
2
.npmrc
|
|
@ -1,2 +1,4 @@
|
|||
# For electron-builder
|
||||
# https://github.com/electron-userland/electron-builder/issues/6289#issuecomment-1042620422
|
||||
shamefully-hoist=true
|
||||
strict-peer-dependencies=false
|
||||
|
|
|
|||
4
app.vue
4
app.vue
|
|
@ -20,10 +20,12 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import Modal from "bootstrap/js/dist/modal";
|
||||
import KonamiCode from "konami-code-js";
|
||||
import Swal from "sweetalert2";
|
||||
import { defineComponent } from "vue";
|
||||
import dataJson from "public/assets/data.json";
|
||||
import data from "data/test.json";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
@ -34,6 +36,7 @@ export default defineComponent({
|
|||
modal: Modal;
|
||||
adminModal: Modal;
|
||||
data: typeof data;
|
||||
dataJson: TypeApp;
|
||||
selectedItem: Item | null;
|
||||
konami: KonamiCode;
|
||||
contacts: Array<Contact>;
|
||||
|
|
@ -42,6 +45,7 @@ export default defineComponent({
|
|||
modalId: "productModal",
|
||||
adminModalId: "adminModal",
|
||||
data,
|
||||
dataJson,
|
||||
selectedItem: null,
|
||||
modal: {} as Modal,
|
||||
adminModal: {} as Modal,
|
||||
|
|
|
|||
44
composable/useElectron.ts
Normal file
44
composable/useElectron.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import log from "electron-log";
|
||||
|
||||
export default function useElectron() {
|
||||
const isServer = process.server || typeof window === "undefined" || typeof window.require === "undefined";
|
||||
const isElectron = !isServer && navigator.userAgent.toLowerCase().includes("nuxt-app");
|
||||
log.info(`isServer ${isServer}`);
|
||||
log.info(`isElectron ${isElectron}`);
|
||||
log.info(`userAgent ${navigator.userAgent.toLowerCase()}`);
|
||||
if (!isElectron || isServer) return { isElectron };
|
||||
|
||||
// Initialize electron
|
||||
const electron = window.require("electron");
|
||||
|
||||
// Window title bar actions
|
||||
// ========================
|
||||
const titleBarActions = {
|
||||
minimize: () => electron.ipcRenderer.invoke("titlebar:action", "minimize"),
|
||||
toggleMaximize: () => electron.ipcRenderer.invoke("titlebar:action", "toggleMaximize"),
|
||||
isMaximized: () => electron.ipcRenderer.invoke("isMaximized:app", null),
|
||||
close: () => electron.ipcRenderer.invoke("close:app", null)
|
||||
};
|
||||
|
||||
// Window title bar stats
|
||||
// ======================
|
||||
const windowStats = ref({
|
||||
isMaximized: false,
|
||||
isFullscreen: false
|
||||
});
|
||||
|
||||
electron.ipcRenderer.on("window:maximizeChanged", (_event, value) => {
|
||||
windowStats.value.isMaximized = value;
|
||||
});
|
||||
electron.ipcRenderer.on("window:fullscreenChanged", (_event, value) => {
|
||||
windowStats.value.isFullscreen = value;
|
||||
});
|
||||
|
||||
// Get Json Data
|
||||
const sendSync = (): TypeApp => {
|
||||
return electron.ipcRenderer.sendSync("get-config", "");
|
||||
};
|
||||
|
||||
// Initialize ipcRenderer
|
||||
return { isElectron, titleBarActions, windowStats, sendSync };
|
||||
}
|
||||
30
electron-builder.json5
Normal file
30
electron-builder.json5
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* @see https://www.electron.build/configuration/configuration
|
||||
*/
|
||||
{
|
||||
appId: "your.app.id",
|
||||
asar: false,
|
||||
directories: {
|
||||
output: "release/${version}",
|
||||
},
|
||||
files: [".output/**/*", "dist-electron"],
|
||||
mac: {
|
||||
artifactName: "${productName}_${version}.${ext}",
|
||||
target: ["dmg"],
|
||||
},
|
||||
win: {
|
||||
target: [
|
||||
{
|
||||
target: "nsis",
|
||||
arch: ["x64"],
|
||||
},
|
||||
],
|
||||
artifactName: "${productName}_${version}.${ext}",
|
||||
},
|
||||
nsis: {
|
||||
oneClick: false,
|
||||
perMachine: false,
|
||||
allowToChangeInstallationDirectory: true,
|
||||
deleteAppDataOnUninstall: false,
|
||||
},
|
||||
}
|
||||
94
electron/UnzipData.ts
Normal file
94
electron/UnzipData.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import fs from "node:fs";
|
||||
import AdmZip from "adm-zip";
|
||||
import Ajv from "ajv";
|
||||
import addFormats from "ajv-formats";
|
||||
import { app } from "electron";
|
||||
import log from "electron-log/main";
|
||||
|
||||
/**
|
||||
* In charge to unzip data from showroom Bo,
|
||||
* validate data config and check version
|
||||
*/
|
||||
export default class UnzipData {
|
||||
static zipFileToUse: string|null;
|
||||
|
||||
/**
|
||||
* Init zipFileToUse if not already inited
|
||||
*/
|
||||
private static init() {
|
||||
if (!UnzipData.zipFileToUse) {
|
||||
// * Try to locate last zip file and load it.
|
||||
const zipFile = fs.readdirSync("static/data")
|
||||
.map(path => { return {path: `static/data/${path}`, "stat": fs.lstatSync(`static/data/${path}`)}; })
|
||||
.filter(obj => obj.stat.isFile() && obj.path.endsWith(".zip"))
|
||||
.sort((objA, objB) => objB.stat.mtime.getTime() - objA.stat.mtime.getTime())
|
||||
.at(0) ?? null;
|
||||
|
||||
if (zipFile) {
|
||||
UnzipData.zipFileToUse = zipFile.path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress zip file content
|
||||
* And fetch data.json content
|
||||
*/
|
||||
public static loadZipFileContent(): TypeApp|null {
|
||||
UnzipData.init();
|
||||
if (!UnzipData.zipFileToUse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const zip = new AdmZip(fs.readFileSync(UnzipData.zipFileToUse));
|
||||
// * Clear export dir
|
||||
fs.rmSync("public/assets", { recursive: true, force: true });
|
||||
zip.extractAllTo("public/assets");
|
||||
const jsonData = fs.readFileSync("public/assets/data.json", { encoding: "utf8", flag: "r" });
|
||||
const jsonSchemaPath = "schemas";
|
||||
|
||||
if (!UnzipData.validateAgainstJsonSchema(jsonSchemaPath, jsonData)) {
|
||||
log.warn(`Data for file ${UnzipData.zipFileToUse} is not valid JSON`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const appJsonConfig: TypeApp = JSON.parse(jsonData);
|
||||
const appVersion: string = app.getVersion();
|
||||
|
||||
if (appJsonConfig.version !== appVersion) {
|
||||
throw new Error(`App version ${appVersion} is not compatible with config version ${appJsonConfig.version}`);
|
||||
}
|
||||
|
||||
return appJsonConfig;
|
||||
}
|
||||
|
||||
private static validateAgainstJsonSchema(jsonSchemaPath:string, jsonData: string): boolean {
|
||||
try {
|
||||
const schemaList = fs.readdirSync(jsonSchemaPath)
|
||||
.filter(schemaPath => schemaPath.endsWith(".schema.json"))
|
||||
.map(schemaPath => JSON.parse(fs.readFileSync(`schemas/${schemaPath}`, { encoding: "utf8", flag: "r" })) as Record<string,string|any>);
|
||||
const appSchemaIndex = schemaList.findIndex((schema) => String(schema.$id).endsWith("app.schema.json"));
|
||||
if (appSchemaIndex === -1) {
|
||||
throw new Error("app.schema.json not found");
|
||||
}
|
||||
|
||||
const appSchema = schemaList.splice(appSchemaIndex, 1).at(0);
|
||||
if (!appSchema) {
|
||||
throw new Error("app.schema.json not found");
|
||||
}
|
||||
|
||||
const ajv = new Ajv();
|
||||
addFormats(ajv);
|
||||
ajv.addMetaSchema(appSchema);
|
||||
ajv.addSchema(schemaList);
|
||||
|
||||
return ajv.validate(appSchema, JSON.parse(jsonData));
|
||||
} catch (err:unknown) {
|
||||
if (err instanceof Error) {
|
||||
log.error(err);
|
||||
return false;
|
||||
}
|
||||
throw new Error("validateAgainstJsonSchema unkown error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
/* eslint-disable */
|
||||
import { BrowserWindow, app } from 'electron'
|
||||
import { BrowserWindow, app, type BrowserWindowConstructorOptions } from 'electron'
|
||||
import { EventEmitter } from 'events'
|
||||
const DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL
|
||||
const isProduction = process.env.NODE_ENV === 'production'
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
const fs = import("node:fs");
|
||||
|
||||
export default class BrowserWinHandler {
|
||||
|
||||
private _eventEmitter: EventEmitter;
|
||||
|
|
@ -13,10 +15,11 @@ export default class BrowserWinHandler {
|
|||
private browserWindow: BrowserWindow|null;
|
||||
|
||||
/**
|
||||
* @param [options] {object} - browser window options
|
||||
* @param [allowRecreate] {boolean}
|
||||
*/
|
||||
constructor (options: object, allowRecreate: boolean = true) {
|
||||
*
|
||||
* @param options browser window options
|
||||
* @param allowRecreate
|
||||
*/
|
||||
constructor (options: BrowserWindowConstructorOptions, allowRecreate: boolean = true) {
|
||||
this._eventEmitter = new EventEmitter()
|
||||
this.allowRecreate = allowRecreate
|
||||
this.options = options
|
||||
|
|
@ -42,22 +45,27 @@ export default class BrowserWinHandler {
|
|||
}
|
||||
|
||||
_create () {
|
||||
this.browserWindow = new BrowserWindow(
|
||||
{
|
||||
this.browserWindow = new BrowserWindow({
|
||||
...this.options,
|
||||
webPreferences: {
|
||||
...this.options.webPreferences,
|
||||
webSecurity: isProduction, // disable on dev to allow loading local resources
|
||||
nodeIntegration: true, // allow loading modules via the require () function
|
||||
contextIsolation: false, // https://github.com/electron/electron/issues/18037#issuecomment-806320028
|
||||
...this.options.webPreferences,
|
||||
webSecurity: isProduction, // disable on dev to allow loading local resources
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true
|
||||
}
|
||||
}
|
||||
)
|
||||
this.browserWindow.on('closed', () => {
|
||||
// Dereference the window object
|
||||
this.browserWindow = null
|
||||
})
|
||||
this._eventEmitter.emit('created')
|
||||
this.browserWindow.on('closed', () => {
|
||||
// Dereference the window object
|
||||
this.browserWindow = null
|
||||
})
|
||||
this._eventEmitter.emit('created');
|
||||
this.browserWindow.webContents.on('before-input-event', (_, input) => {
|
||||
if (input.type === 'keyDown' && input.key === 'F12' && this.browserWindow) {
|
||||
this.browserWindow.webContents.openDevTools({ mode: 'detach' });
|
||||
}
|
||||
});
|
||||
this.browserWindow.removeMenu();
|
||||
this.browserWindow.setMenu(null);
|
||||
}
|
||||
|
||||
_recreate () {
|
||||
|
|
@ -87,4 +95,26 @@ export default class BrowserWinHandler {
|
|||
this.onCreated(() => resolve(this.browserWindow))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Open dev tools if ti can be
|
||||
*/
|
||||
openDevTool() {
|
||||
const browserWindow = this.browserWindow;
|
||||
if (!browserWindow) {
|
||||
throw new Error("No window is loaded");
|
||||
}
|
||||
browserWindow.webContents.openDevTools();
|
||||
}
|
||||
|
||||
quit() {
|
||||
const browserWindow = this.browserWindow;
|
||||
if (!browserWindow) {
|
||||
throw new Error("No window is loaded");
|
||||
}
|
||||
browserWindow.on('closed', () => {
|
||||
this.browserWindow = null
|
||||
});
|
||||
browserWindow.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
import { app } from "electron";
|
||||
import path from "node:path";
|
||||
import { app, ipcMain } from "electron";
|
||||
import log from "electron-log/main";
|
||||
import UnzipData from "./UnzipData";
|
||||
import BrowserWinHandler from "./browserWinHandler";
|
||||
|
||||
// TODO: take inspiration form https://github.com/michalzaq12/electron-nuxt/tree/master/template/src/main.
|
||||
// Or https://github.com/EternalC0der/electron-nuxt3
|
||||
|
||||
log.initialize();
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on("window-all-closed", function () {
|
||||
|
|
@ -14,15 +20,36 @@ app.whenReady().then(() => {
|
|||
// * Run an Electron window ?
|
||||
if (process.env.npm_lifecycle_event === "electron") {
|
||||
const winHandler = new BrowserWinHandler({
|
||||
kiosk: true,
|
||||
closable: false,
|
||||
alwaysOnTop: true,
|
||||
fullScreen: true,
|
||||
autoHideMenuBar: true
|
||||
kiosk: false,
|
||||
closable: true,
|
||||
alwaysOnTop: false,
|
||||
fullscreen: false,
|
||||
autoHideMenuBar: false,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "versions.js")
|
||||
}
|
||||
});
|
||||
|
||||
winHandler.onCreated(_browserWindow => {
|
||||
winHandler.loadPage("ranges");
|
||||
try {
|
||||
const appData = UnzipData.loadZipFileContent();
|
||||
if (!appData) {
|
||||
throw new Error("No zip file to load");
|
||||
}
|
||||
// this is the event listener that will respond when we will request it in the web page
|
||||
ipcMain.on("get-config", (event) => {
|
||||
log.info("read json app config");
|
||||
event.returnValue = appData;
|
||||
});
|
||||
|
||||
winHandler.loadPage("ranges");
|
||||
winHandler.openDevTool();
|
||||
} catch (err) {
|
||||
log.error(err);
|
||||
winHandler.quit();
|
||||
}
|
||||
});
|
||||
|
||||
// fs.readFile();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
9
electron/preload/versions.ts
Normal file
9
electron/preload/versions.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { contextBridge } from "electron";
|
||||
|
||||
// This runs in sandboxed mode.
|
||||
contextBridge.exposeInMainWorld("versions", {
|
||||
node: () => process.versions.node,
|
||||
chrome: () => process.versions.chrome,
|
||||
electron: () => process.versions.electron
|
||||
// Nous pouvons exposer des variables en plus des fonctions
|
||||
});
|
||||
4
electron/renderer.ts
Normal file
4
electron/renderer.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
|
||||
// console.log("versions.chrome()");
|
||||
// console.log(app.chrome());
|
||||
12
index.d.ts
vendored
12
index.d.ts
vendored
|
|
@ -22,6 +22,8 @@ type SettingsModel = {
|
|||
color: string;
|
||||
/** Éléments par ligne, entre 3 et 6 inclus */
|
||||
items_by_line: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
/** A brand from Showroom Bo */
|
||||
|
|
@ -71,7 +73,7 @@ type ProductModel = {
|
|||
/** Logo du produit, chemin tel que présent dans le zip */
|
||||
picture: string;
|
||||
/** Clé étrangère de la gamme */
|
||||
range_id: string;
|
||||
range_id: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
|
@ -116,6 +118,14 @@ declare global {
|
|||
type Settings = ModalSettings;
|
||||
type Contact = ContactModel;
|
||||
|
||||
// * App Models
|
||||
type TypeApp = AppModel;
|
||||
type TypeSettings = SettingsModel;
|
||||
type TypeBrand = BrandModel;
|
||||
type TypeRange = RangeModel;
|
||||
type TypeProduct = ProductModel;
|
||||
|
||||
|
||||
// Nuxt
|
||||
type RouteLocation = NRouteLocation;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,18 @@ export default defineNuxtConfig({
|
|||
build: [
|
||||
{
|
||||
// Main-Process entry file of the Electron App.
|
||||
entry: "electron/main.ts",
|
||||
entry: "electron/main.ts"
|
||||
},
|
||||
{
|
||||
entry: "electron/preload/versions.ts",
|
||||
onstart(args) {
|
||||
// Notify the Renderer-Process to reload the page when the Preload-Scripts build is complete,
|
||||
// instead of restarting the entire Electron App.
|
||||
args.reload();
|
||||
},
|
||||
},
|
||||
],
|
||||
renderer: {},
|
||||
},
|
||||
devtools: { enabled: false },
|
||||
app: {
|
||||
|
|
|
|||
189
package-lock.json
generated
189
package-lock.json
generated
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"name": "nuxt-app",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "nuxt-app",
|
||||
"version": "1.0.0",
|
||||
"hasInstallScript": true,
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
|
|
@ -14,14 +16,19 @@
|
|||
"@nuxt/devtools": "^1.0.0-beta.1",
|
||||
"@nuxtjs/eslint-config-typescript": "latest",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@types/adm-zip": "^0.5.5",
|
||||
"@types/bootstrap": "^5.2.10",
|
||||
"@types/dompurify": "^3.0.3",
|
||||
"@types/konami-code-js": "^0.8.1",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"adm-zip": "^0.5.10",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"bootstrap": "^5.3.2",
|
||||
"dompurify": "^3.0.6",
|
||||
"electron": "^28.1.1",
|
||||
"electron-builder": "^24.9.1",
|
||||
"electron-log": "^5.0.3",
|
||||
"eslint": "latest",
|
||||
"eslint-config-prettier": "latest",
|
||||
"eslint-plugin-nuxt": "latest",
|
||||
|
|
@ -1040,6 +1047,37 @@
|
|||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/@develar/schema-utils/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/@develar/schema-utils/node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"ajv": "^6.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@develar/schema-utils/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@electron/asar": {
|
||||
"version": "3.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.8.tgz",
|
||||
|
|
@ -1666,6 +1704,22 @@
|
|||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
|
|
@ -1676,6 +1730,12 @@
|
|||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
|
@ -4371,6 +4431,15 @@
|
|||
"node": "^16.14.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/adm-zip": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.5.tgz",
|
||||
"integrity": "sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
|
|
@ -5249,6 +5318,15 @@
|
|||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz",
|
||||
"integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
|
|
@ -5275,14 +5353,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
|
|
@ -5290,13 +5368,21 @@
|
|||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"node_modules/ajv-formats": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ajv": "^6.9.1"
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"ajv": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-colors": {
|
||||
|
|
@ -7707,6 +7793,30 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dmg-license/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/dmg-license/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
|
|
@ -7916,6 +8026,15 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-log": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-5.0.3.tgz",
|
||||
"integrity": "sha512-jUgAuRjfpCD9tmH1F6fb195YsFfM/DkqkZLhFeo0VAAstantn11bxmgx63uE6KG/JljHG7sIkgM2QEjDimJI0g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-publish": {
|
||||
"version": "24.8.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.8.1.tgz",
|
||||
|
|
@ -8802,6 +8921,22 @@
|
|||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
|
|
@ -8824,6 +8959,12 @@
|
|||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/eslint/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
|
@ -11647,9 +11788,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/json-stable-stringify-without-jsonify": {
|
||||
|
|
@ -17124,28 +17265,6 @@
|
|||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/table/node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/table/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
|
|
|
|||
12
package.json
12
package.json
|
|
@ -1,10 +1,13 @@
|
|||
{
|
||||
"name": "nuxt-app",
|
||||
"author": "LDC Service Web",
|
||||
"description": "Application Kiosk",
|
||||
"version": "1.0.0",
|
||||
"name": "app-kiosk",
|
||||
"private": true,
|
||||
"type": "commonjs",
|
||||
"main": "dist-electron/main.js",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"build": "nuxi build --prerender && electron-builder",
|
||||
"dev": "nuxt dev",
|
||||
"electron": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
|
|
@ -28,14 +31,19 @@
|
|||
"@nuxt/devtools": "^1.0.0-beta.1",
|
||||
"@nuxtjs/eslint-config-typescript": "latest",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@types/adm-zip": "^0.5.5",
|
||||
"@types/bootstrap": "^5.2.10",
|
||||
"@types/dompurify": "^3.0.3",
|
||||
"@types/konami-code-js": "^0.8.1",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"adm-zip": "^0.5.10",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"bootstrap": "^5.3.2",
|
||||
"dompurify": "^3.0.6",
|
||||
"electron": "^28.1.1",
|
||||
"electron-builder": "^24.9.1",
|
||||
"electron-log": "^5.0.3",
|
||||
"eslint": "latest",
|
||||
"eslint-config-prettier": "latest",
|
||||
"eslint-plugin-nuxt": "latest",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import log from "electron-log";
|
||||
import { defineComponent } from "vue";
|
||||
import { useRoute, type RouteLocationNormalizedLoaded } from "vue-router";
|
||||
|
||||
|
|
@ -21,7 +23,7 @@ export default defineComponent({
|
|||
},
|
||||
mounted() {
|
||||
const route = useRoute();
|
||||
console.log(route);
|
||||
log.info(route);
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import log from "electron-log";
|
||||
import { defineComponent } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ export default defineComponent({
|
|||
},
|
||||
mounted() {
|
||||
const route = useRoute();
|
||||
console.log(route);
|
||||
log.info(route);
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
|
|
|
|||
33
schemas/app.schema.json
Normal file
33
schemas/app.schema.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"$id": "schemas/app.schema.json",
|
||||
"title": "Showroom Bo",
|
||||
"description": "Showroom Bo json data format",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"description": "Version de l'application",
|
||||
"$ref": "#/$defs/version"
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "settings.schema.json"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "brand.schema.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"version": {
|
||||
"description": "Version",
|
||||
"pattern": "^[0-9]+?\\.[0-9]+?\\.[0-9]+?$",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"version",
|
||||
"settings",
|
||||
"items"
|
||||
]
|
||||
}
|
||||
60
schemas/brand.schema.json
Normal file
60
schemas/brand.schema.json
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"$id": "schemas/brand.schema.json",
|
||||
"title": "Brand",
|
||||
"description": "A brand from Showroom Bo",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The unique identifier for a product",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"name": {
|
||||
"description": "Nom de la marque",
|
||||
"type": "string"
|
||||
},
|
||||
"slug": {
|
||||
"description": "Slug de la marque",
|
||||
"type": "string"
|
||||
},
|
||||
"color": {
|
||||
"description": "Couleur de la marque",
|
||||
"$ref": "#/$defs/hexcolor"
|
||||
},
|
||||
"picture": {
|
||||
"description": "Logo de la marque, chemin tel que présent dans le zip",
|
||||
"type": "string"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"ranges": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "range.schema.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"hexcolor": {
|
||||
"description": "HEX color",
|
||||
"pattern": "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"slug",
|
||||
"color",
|
||||
"picture",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"ranges"
|
||||
]
|
||||
}
|
||||
52
schemas/product.schema.json
Normal file
52
schemas/product.schema.json
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"$id": "schemas/product.schema.json",
|
||||
"title": "Product",
|
||||
"description": "A product from Showroom Bo",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The unique identifier for a product",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"name": {
|
||||
"description": "Nom du produit",
|
||||
"type": "string"
|
||||
},
|
||||
"slug": {
|
||||
"description": "Slug du produit",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Description du produit, texte WYSYWYG",
|
||||
"type": "string"
|
||||
},
|
||||
"picture": {
|
||||
"description": "Logo du produit, chemin tel que présent dans le zip",
|
||||
"type": "string"
|
||||
},
|
||||
"range_id": {
|
||||
"description": "Clé étrangère de la gamme",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"slug",
|
||||
"description",
|
||||
"picture",
|
||||
"range_id",
|
||||
"created_at",
|
||||
"updated_at"
|
||||
]
|
||||
}
|
||||
54
schemas/range.schema.json
Normal file
54
schemas/range.schema.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"$id": "schemas/range.schema.json",
|
||||
"title": "Range",
|
||||
"description": "A range from Showroom Bo",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The unique identifier for a range",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"name": {
|
||||
"description": "Nom de la gamme",
|
||||
"type": "string"
|
||||
},
|
||||
"slug": {
|
||||
"description": "Slug de la gamme",
|
||||
"type": "string"
|
||||
},
|
||||
"picture": {
|
||||
"description": "Logo de la gamme, chemin tel que présent dans le zip",
|
||||
"type": "string"
|
||||
},
|
||||
"brand_id": {
|
||||
"description": "Clé étrangère de la marque",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"products": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "product.schema.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"slug",
|
||||
"picture",
|
||||
"brand_id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
"products"
|
||||
]
|
||||
}
|
||||
39
schemas/settings.schema.json
Normal file
39
schemas/settings.schema.json
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"$id": "schemas/settings.schema.json",
|
||||
"title": "Settings",
|
||||
"description": "Settings from Showroom Bo",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"description": "Titre de l'application",
|
||||
"type": "string"
|
||||
},
|
||||
"logo": {
|
||||
"description": "Logo de l'application, chemin tel que présent dans le zip",
|
||||
"type": "string"
|
||||
},
|
||||
"color": {
|
||||
"description": "Couleur de l'application",
|
||||
"$ref": "#/$defs/hexcolor"
|
||||
},
|
||||
"items_by_line": {
|
||||
"description": "Éléments par ligne",
|
||||
"type": "integer",
|
||||
"minimum": 3,
|
||||
"maximum": 6
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"hexcolor": {
|
||||
"description": "HEX color",
|
||||
"pattern": "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"logo",
|
||||
"color",
|
||||
"items_by_line"
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue