before restructering project
This commit is contained in:
parent
99adc9c445
commit
9605a5b972
22 changed files with 733 additions and 210 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
|||
# Build folder and files #
|
||||
##########################
|
||||
builds/
|
||||
installers/
|
||||
|
||||
# Development folders and files #
|
||||
#################################
|
||||
|
|
|
|||
32
electron-builder.json
Normal file
32
electron-builder.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"appId": "org.nasarek.marvin",
|
||||
"win": {
|
||||
"target": "NSIS",
|
||||
"icon": "marvin256x256.ico"
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"installerIcon": "marvin256x256.ico",
|
||||
"uninstallerIcon": "marvin256x256.ico",
|
||||
"allowToChangeInstallationDirectory": true
|
||||
},
|
||||
"linux": {
|
||||
"target": "deb",
|
||||
"category": "Utility",
|
||||
"icon": "marvin256x256.png"
|
||||
},
|
||||
"files": [
|
||||
"*.js",
|
||||
"**/*",
|
||||
"./dist/bundle.css",
|
||||
"./dist/index.html",
|
||||
"./dist/main.js",
|
||||
"./dist/main.js.LICENSE.txt",
|
||||
"node_modules"
|
||||
],
|
||||
"extraResources": [{
|
||||
"from": "resources/files",
|
||||
"to": "files"
|
||||
}
|
||||
]
|
||||
}
|
||||
12
main.js
12
main.js
|
|
@ -142,6 +142,16 @@ let mainMenu = Menu.buildFromTemplate(
|
|||
]
|
||||
)
|
||||
|
||||
const RESOURCES_PATH = app.isPackaged
|
||||
? path.join(process.resourcesPath, 'assets')
|
||||
: path.join(__dirname, '../../assets');
|
||||
|
||||
console.log(process.resourcesPath);
|
||||
console.log(__dirname);
|
||||
|
||||
const getAssetPath = (paths) => {
|
||||
return path.join(RESOURCES_PATH, paths);
|
||||
};
|
||||
|
||||
function createWindow(dimensions) {
|
||||
if (dev !== true) {
|
||||
|
|
@ -255,5 +265,3 @@ app.on('activate', () => {
|
|||
}
|
||||
|
||||
})
|
||||
|
||||
// IPC-Channel handling
|
||||
|
|
|
|||
BIN
marvin256x256.png
Normal file
BIN
marvin256x256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
23
package.json
23
package.json
|
|
@ -33,25 +33,9 @@
|
|||
"prod": "cross-env NODE_ENV=production webpack --mode production --config webpack.build.config.js && electron --noDevServer .",
|
||||
"start": "cross-env NODE_ENV=development webpack serve --hot --host 0.0.0.0 --config=./webpack.dev.config.js --mode development",
|
||||
"build": "cross-env NODE_ENV=production webpack --config webpack.build.config.js --mode production",
|
||||
"installer": "electron-builder",
|
||||
"pack:installer": "electron-builder build -lw",
|
||||
"package": "npm run build",
|
||||
"postpackage": "electron-packager ./ --ignore 'resources/files' --out=./builds --asar --overwrite --platform win32,linux --icon marvin.ico --extra-resource 'resources/files'"
|
||||
},
|
||||
"build": {
|
||||
"appId": "marvin",
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis"
|
||||
],
|
||||
"icon": "marvin256x256.ico"
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"installerIcon": "marvin.ico",
|
||||
"uninstallerIcon": "marvin.ico",
|
||||
"uninstallDisplayName": "Marvin-Uninstaller",
|
||||
"allowToChangeInstallationDirectory": true
|
||||
}
|
||||
"postpackage": "electron-packager ./ --ignore \"(resources|builds|installer)\" --out=./builds --overwrite --platform win32,linux --icon marvin.ico --extra-resource 'resources/files'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.0",
|
||||
|
|
@ -60,10 +44,12 @@
|
|||
"@mui/material": "^5.10.2",
|
||||
"about-window": "^1.15.2",
|
||||
"docx-templates": "^4.9.2",
|
||||
"image-resize-compress": "^1.0.8",
|
||||
"postcss": "^8.4.16",
|
||||
"react": "^18.2.0",
|
||||
"react-async-devtools": "^10.0.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-image-gallery": "^1.2.9",
|
||||
"react-loader-spinner": "^5.3.3",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"replace-special-characters": "^1.2.6",
|
||||
|
|
@ -91,6 +77,7 @@
|
|||
"postcss-nested": "^5.0.6",
|
||||
"postcss-preset-env": "^7.8.0",
|
||||
"postcss-pxtorem": "^6.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"style-loader": "^3.3.1",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"rootDir": "C:\\Users\\Robert\\Desktop\\marvin"
|
||||
}
|
||||
478
src/DocCreator.js
Normal file
478
src/DocCreator.js
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
// Modules
|
||||
import createReport from 'docx-templates';
|
||||
import fs, {writeFile} from 'fs';
|
||||
import {mkdir} from 'node:fs/promises';
|
||||
import path from 'path';
|
||||
import replaceSpecialCharacters from "replace-special-characters";
|
||||
|
||||
import {parseString, Builder} from 'xml2js';
|
||||
|
||||
|
||||
////////////////////
|
||||
// Main //
|
||||
////////////////////
|
||||
|
||||
class DocCreator {
|
||||
constructor(log, objectData) {
|
||||
|
||||
// Assign Log.
|
||||
this.log = log;
|
||||
|
||||
// Assign general object data.
|
||||
this.objectData = objectData;
|
||||
|
||||
// Get DateTime.
|
||||
this.today = new Date();
|
||||
|
||||
// Get config file and parse to json.
|
||||
this.configFile = fs.readFileSync('/resources/files/config/config.json')
|
||||
this.configJson = JSON.parse(this.configFile.toString())
|
||||
|
||||
// Choose the template for selected document type.
|
||||
switch (objectData.dokumenttyp) {
|
||||
case 'rp':
|
||||
this.documentInfo = {
|
||||
documentType: 'restaurierungsprotokolle', docTypeAbbr: 'rp', templateFile: 'rp-template.docx',
|
||||
}
|
||||
break;
|
||||
case 'lbb':
|
||||
this.documentInfo = {
|
||||
documentType: 'leihgabenbegleitblaetter', docTypeAbbr: 'lbb', templateFile: 'lbb-template.docx',
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
this.documentInfo = {
|
||||
documentType: 'analysen', docTypeAbbr: 'a', templateFile: 'a-template.docx',
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// ObjectId normalisation.
|
||||
const normCharacterObjectId = replaceSpecialCharacters(objectData.inventarnummer);
|
||||
this.normObjectId = normCharacterObjectId.replace("__", "_");
|
||||
|
||||
// Title normalisation
|
||||
const replaceEszettTitle = objectData.titel.replace("ß", "-ss-");
|
||||
let replaceUmlauteTitle = replaceEszettTitle.replace(/[^Ä]+/ig, "Ae");
|
||||
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ä]+/ig, "ae");
|
||||
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^Ö]+/ig, "Oe");
|
||||
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ö]+/ig, "oe");
|
||||
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^Ü]+/ig, "Ue");
|
||||
replaceUmlauteTitle = replaceUmlauteTitle.replace(/[^ü]+/ig, "ue");
|
||||
const normCharacterTitle = replaceSpecialCharacters(replaceUmlauteTitle);
|
||||
const normSingleSpaceTitle = normCharacterTitle.replace("__", "_");
|
||||
const normSpacingTitle = normSingleSpaceTitle.replace(/[^A-Z0-9\-]+/ig, "_");
|
||||
this.normTitle = normSpacingTitle.slice(0, 50);
|
||||
|
||||
const folderName = this.normObjectId + '__' + this.normTitle
|
||||
this.objectPath = path.join(this.configJson.rootDir, folderName);
|
||||
this.documentPath = path.join(this.objectPath, this.documentInfo.documentType, objectData.datum);
|
||||
this.filename = this.normObjectId + '__' + this.normTitle + '__' + this.objectData.datum + '__' + this.objectData.dokumenttyp;
|
||||
this.filenameWithExtension = this.filename + '.docx'
|
||||
this.temporaryWorkDirPath = path.join(this.objectPath, 'werkstatt');
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Fills the docx template.
|
||||
async fillTemplate() {
|
||||
// Variables
|
||||
let buffer;
|
||||
let configJson
|
||||
|
||||
// Create docx document if there was a response.
|
||||
if (this.objectData.httpStatus === 200) {
|
||||
try {
|
||||
// Read template.
|
||||
const template = fs.readFileSync(path.join('/resources/files/templates/', this.documentInfo.templateFile));
|
||||
|
||||
// Create report.
|
||||
buffer = await createReport({
|
||||
template, data: {
|
||||
inventarnummer: this.objectData.inventarnummer ? this.objectData.inventarnummer : 'unbekannt',
|
||||
titel: this.objectData.titel ? this.objectData.titel : 'unbekannt',
|
||||
hersteller: this.objectData.hersteller ? this.objectData.hersteller : 'unbekannt',
|
||||
herstellungsort: this.objectData.herstellungsort ? this.objectData.herstellungsort : 'unbekannt',
|
||||
herstellungsdatum: this.objectData.herstellungsdatum ? this.objectData.herstellungsdatum : 'unbekannt',
|
||||
materialTechnik: this.objectData.materialTechnik ? this.objectData.materialTechnik : 'unbekannt',
|
||||
masse: this.objectData.masse ? this.objectData.masse : 'unbekannt'
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
// Set error log.
|
||||
this.log = {
|
||||
...this.log,
|
||||
status: 'red',
|
||||
message: 'Konnte Template nicht erstellen: ' + err,
|
||||
tip: 'Ist das Template vorhanden?',
|
||||
};
|
||||
return this.log
|
||||
}
|
||||
|
||||
try {
|
||||
const createDocumentPath = await mkdir(this.documentPath, {recursive: true});
|
||||
const createTemporaryWorkDirPath = await mkdir(this.temporaryWorkDirPath, {recursive: true});
|
||||
} catch (err) {
|
||||
// Set error log.
|
||||
this.log = {
|
||||
...this.log,
|
||||
status: 'red',
|
||||
message: 'Konnte den Pfad nicht erstellen' + err,
|
||||
tip: 'Bestehen Schreibrechte auf dem Ordner?'
|
||||
}
|
||||
return this.log
|
||||
}
|
||||
|
||||
// Write document to disk.
|
||||
if (buffer) {
|
||||
fs.writeFileSync(path.join(this.documentPath, this.filenameWithExtension), buffer)
|
||||
this.log = {
|
||||
...this.log, status: 'green', message: 'Dokument erstellt',
|
||||
};
|
||||
}
|
||||
|
||||
} else {
|
||||
this.log = {
|
||||
status: 'red',
|
||||
message: 'Fehler bei der Kommunikation mit dem Objektkatalog',
|
||||
code: this.objectData.httpStatus,
|
||||
tip: 'Ist die Inventarnummer richtig?',
|
||||
};
|
||||
}
|
||||
return this.log;
|
||||
}
|
||||
|
||||
async createMetsMods() {
|
||||
|
||||
const metsModsString = `
|
||||
<mets:mets
|
||||
xmlns:mets="http://www.loc.gov/METS/"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="info:lc/xmlns/premis-v2
|
||||
http://www.loc.gov/standards/premis/v2/premis-v2-0.xsd
|
||||
http://www.loc.gov/mods/v3
|
||||
http://www.loc.gov/standards/mods/v3/mods-3-6.xsd
|
||||
http://www.loc.gov/METS/
|
||||
http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd
|
||||
http://www.loc.gov/mix/v10
|
||||
http://www.loc.gov/standards/mix/mix10/mix10.xsd">
|
||||
<mets:metsHdr createDate="${this.today}">
|
||||
<mets:agent
|
||||
type="other"
|
||||
otherType="software"
|
||||
role="creator">
|
||||
<mets:name>
|
||||
${process.env.REACT_APP_NAME} v${process.env.REACT_APP_VERSION}
|
||||
</mets:name>
|
||||
</mets:agent>
|
||||
</mets:metsHdr>
|
||||
<mets:fileSec>
|
||||
<mets:fileGrp use="${this.documentInfo.documentType}">
|
||||
<mets:file id="file__${this.filename}" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document">
|
||||
<mets:FLocat locType="other" otherLocType="file" xlink:href="${this.filenameWithExtension}"/>
|
||||
</mets:file>
|
||||
</mets:fileGrp>
|
||||
</mets:fileSec>
|
||||
<mets:structMap type="physical">
|
||||
<mets:div type="${this.documentInfo.docTypeAbbr}" id="phys_00" dmdid="dmdphys_00">
|
||||
<mets:fptr fileId="file__${this.filename}"/>
|
||||
</mets:div>
|
||||
</mets:structMap>
|
||||
<mets:structMap type="logical">
|
||||
<mets:div type="${this.documentInfo.docTypeAbbr}" id="phys_00">
|
||||
<mets:fptr fileId="file__${this.filename}"/>
|
||||
</mets:div>
|
||||
</mets:structMap>
|
||||
<mets:dmdSec id="dmdlog_00">
|
||||
<mets:mdWrap mdType="mods">
|
||||
<mets:xmlData>
|
||||
<mods:mods xmlns:mods="http://www.loc.gov/mods/v3">
|
||||
<mods:recordInfo>
|
||||
<mods:recordIdentifier source="https://objektkatalag.gnm.de">${this.objectData.inventarnummer}</mods:recordIdentifier>
|
||||
</mods:recordInfo>
|
||||
<mods:titleInfo>
|
||||
<mods:title>${this.objectData.titel}</mods:title>
|
||||
</mods:titleInfo>
|
||||
<mods:originInfo>
|
||||
<mods_dateIssued encoding="w3cdtf" keyDate="yes">${this.objectData.herstellungsdatum}</mods_dateIssued>
|
||||
<mods:place>
|
||||
<mods:placeTerm type="text">${this.objectData.herstellungsort}</mods:placeTerm>
|
||||
</mods:place>
|
||||
</mods:originInfo>
|
||||
<mods:name type="personal">
|
||||
<mods:role>
|
||||
<mods:roleTerm authority="marcrelator" type="code">cre</mods:roleTerm>
|
||||
</mods:role>
|
||||
<mods:namePart>${this.objectData.herstellungsort}</mods:namePart>
|
||||
<mods:displayForm>${this.objectData.herstellungsort}</mods:displayForm>
|
||||
</mods:name>
|
||||
<mods:physicalDescription>
|
||||
<mods:form type="Material and Technique" lang="de"/>
|
||||
<mods:extent>${this.objectData.masse}</mods:extent>
|
||||
</mods:physicalDescription>
|
||||
</mods:mods>
|
||||
</mets:xmlData>
|
||||
</mets:mdWrap>
|
||||
</mets:dmdSec>
|
||||
</mets:mets>
|
||||
`
|
||||
|
||||
const metModsJson = {
|
||||
'mets:mets': {
|
||||
$: {
|
||||
'xmlns:mets': "http://www.loc.gov/METS/",
|
||||
'xmlns:xlink': "http://www.w3.org/1999/xlink",
|
||||
'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
|
||||
'xsi:schemaLocation': "info:lc/xmlns/premis-v2 http://www.loc.gov/standards/premis/v2/premis-v2-0.xsd " +
|
||||
"http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-6.xsd " +
|
||||
"http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd " +
|
||||
"http://www.loc.gov/mix/v10 http://www.loc.gov/standards/mix/mix10/mix10.xsd"
|
||||
},
|
||||
'mets:metsHdr': {
|
||||
$: {
|
||||
// Creation date of the mets/mods xml.
|
||||
'createDate': this.today // Should be w3ctdf format: YYYY-MM-DDThh:mm:ssTZD
|
||||
},
|
||||
'mets:agent': {
|
||||
// App, which created the xml document
|
||||
$: {
|
||||
'type': 'other',
|
||||
'otherType': 'software',
|
||||
'role': 'creator'
|
||||
},
|
||||
'mets:name': {
|
||||
// App name and version
|
||||
_: `${process.env.REACT_APP_NAME} v${process.env.REACT_APP_VERSION}`
|
||||
}
|
||||
}
|
||||
},
|
||||
'mets:fileSec': {
|
||||
'mets:fielGrp': {
|
||||
$: {
|
||||
// Documenttype
|
||||
'use': `${this.documentInfo.documentType}`
|
||||
},
|
||||
'mets:file': {
|
||||
// Phyical file
|
||||
$: {
|
||||
'id': `file__${this.filename}`,
|
||||
'mimeType': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||||
},
|
||||
'mets:FLocat': {
|
||||
// Physical location - here in same folder
|
||||
$: {
|
||||
'locType': 'other',
|
||||
'otherLocType': 'file',
|
||||
'xlink:href': `${this.filenameWithExtension}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'mets:structMap': [
|
||||
{ // These are solo documents only, this may be inappropriate.
|
||||
$: {
|
||||
// Physical structure.
|
||||
'type': 'physical'
|
||||
},
|
||||
'mets:div': {
|
||||
$: {
|
||||
// Documenttype and id.
|
||||
'type': `${this.documentInfo.docTypeAbbr}`,
|
||||
// since we have only one document, id and dmdid are static.
|
||||
'id': `phys_00`,
|
||||
'dmdid': 'dmdphys_00'
|
||||
},
|
||||
'mets:fptr': {
|
||||
$: {
|
||||
// File id from above
|
||||
'fileId': `file__${this.filename}`
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ // These are solo documents only, this may be inappropriate.
|
||||
$: {
|
||||
// Physical structure.
|
||||
'type': 'logical'
|
||||
},
|
||||
'mets:div': {
|
||||
$: {
|
||||
// Documenttype and id.
|
||||
'type': `${this.documentInfo.docTypeAbbr}`,
|
||||
// since we have only one document, id and dmdid are static.
|
||||
'id': `phys_00`,
|
||||
'dmdid': 'dmdphys_00'
|
||||
},
|
||||
'mets:fptr': {
|
||||
$: {
|
||||
// File id from above
|
||||
'fileId': `file__${this.filename}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}],
|
||||
'mets:dmdSec':
|
||||
{
|
||||
$: {
|
||||
// Since we have only one document, dmdlog is static
|
||||
'id':
|
||||
`dmdlog_00`
|
||||
}
|
||||
,
|
||||
'mets:mdWrap':
|
||||
{
|
||||
$: {
|
||||
'mdType':
|
||||
'mods'
|
||||
}
|
||||
,
|
||||
'mets:xmlData':
|
||||
{
|
||||
'mods:mods':
|
||||
{
|
||||
// Object properties as found at https://objektkatalog.gnm.de.
|
||||
$: {
|
||||
'xmlns:mods':
|
||||
'http://www.loc.gov/mods/v3'
|
||||
}
|
||||
,
|
||||
'mods:recordInfo':
|
||||
{
|
||||
'mods:recordIdentifier':
|
||||
{
|
||||
// ObjectId.
|
||||
$: {
|
||||
'source':
|
||||
'https://objektkatalag.gnm.de'
|
||||
}
|
||||
,
|
||||
_: `${this.objectData.inventarnummer}`
|
||||
}
|
||||
}
|
||||
,
|
||||
'mods:titleInfo':
|
||||
{
|
||||
// Title.
|
||||
'mods:title':
|
||||
{
|
||||
_: `${this.objectData.titel}`
|
||||
}
|
||||
}
|
||||
,
|
||||
'mods:originInfo':
|
||||
{
|
||||
// Creation date.
|
||||
'mods_dateIssued':
|
||||
{
|
||||
$: {
|
||||
'encoding':
|
||||
'w3cdtf', // W3C Date and Time, should be YYYY-MM-DDThh:mm:ssTZD
|
||||
'keyDate':
|
||||
'yes'
|
||||
}
|
||||
,
|
||||
_: `${this.objectData.herstellungsdatum}`
|
||||
}
|
||||
,
|
||||
'mods:place':
|
||||
{
|
||||
// Creation place
|
||||
'mods:placeTerm':
|
||||
{
|
||||
$: {
|
||||
'type':
|
||||
'text'
|
||||
}
|
||||
,
|
||||
_: `${this.objectData.herstellungsort}`
|
||||
}
|
||||
}
|
||||
}
|
||||
,
|
||||
'mods:name':
|
||||
{
|
||||
// Creator.
|
||||
$: {
|
||||
'type':
|
||||
'personal'
|
||||
}
|
||||
,
|
||||
'mods:role':
|
||||
{
|
||||
'mods:roleTerm':
|
||||
{
|
||||
$: {
|
||||
'authority':
|
||||
'marcrelator',
|
||||
'type':
|
||||
'code'
|
||||
}
|
||||
,
|
||||
_: 'cre'
|
||||
}
|
||||
}
|
||||
,
|
||||
'mods:namePart':
|
||||
{
|
||||
_: this.objectData.hersteller
|
||||
}
|
||||
,
|
||||
'mods:displayForm':
|
||||
{
|
||||
_: this.objectData.hersteller
|
||||
}
|
||||
}
|
||||
,
|
||||
'mods:physicalDescription':
|
||||
{
|
||||
'mods:form':
|
||||
{
|
||||
$: {
|
||||
'type':
|
||||
'Material and Technique',
|
||||
'lang':
|
||||
'de'
|
||||
}
|
||||
}
|
||||
,
|
||||
'mods:extent':
|
||||
{
|
||||
_: `${this.objectData.masse}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let metModsXml
|
||||
parseString(metsModsString, {trim: true},
|
||||
function (err, result) {
|
||||
metModsXml = result;
|
||||
}
|
||||
);
|
||||
console.log(metModsXml, 'from string');
|
||||
|
||||
const builder = new Builder()
|
||||
metModsXml = builder.buildObject(metModsJson);
|
||||
console.log(metModsXml, 'from Json')
|
||||
|
||||
const fileName = `.metsMods__${this.normObjectId}__${this.normTitle}.xml`
|
||||
fs.writeFileSync(path.join(this.documentPath,fileName),metModsXml.toString(),
|
||||
function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
console.log("The file was saved!");
|
||||
}
|
||||
}
|
||||
)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export {DocCreator};
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
// Modules
|
||||
import createReport from 'docx-templates';
|
||||
import fs from 'fs';
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import path from 'path';
|
||||
import replaceSpecialCharacters from "replace-special-characters";
|
||||
|
||||
|
||||
////////////////////
|
||||
// Main //
|
||||
////////////////////
|
||||
|
||||
// Fills the docx template.
|
||||
export async function fillTemplate(log, objectData) {
|
||||
// Variables
|
||||
let buffer;
|
||||
let configJson
|
||||
|
||||
// Create docx document if there was a response.
|
||||
if (objectData.httpStatus === 200) {
|
||||
let documentInfo;
|
||||
try {
|
||||
// Load config file.
|
||||
let ConfigFile = fs.readFileSync('resources/files/config/config.json')
|
||||
configJson = JSON.parse(ConfigFile)
|
||||
|
||||
// Choose the template for selected document type.
|
||||
switch (objectData.dokumenttyp) {
|
||||
case 'rp':
|
||||
documentInfo = {
|
||||
documentType: 'restaurierungsprotokolle',
|
||||
templateFile: 'rp-template.docx',
|
||||
}
|
||||
break;
|
||||
case 'lbb':
|
||||
documentInfo = {
|
||||
documentType: 'leihgabenbegleitblaetter',
|
||||
templateFile: 'lbb-template.docx',
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
documentInfo = {
|
||||
documentType: 'analysen',
|
||||
templateFile: 'a-template.docx',
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Read template.
|
||||
const template = fs.readFileSync(path.join('resources/files/templates/', documentInfo.templateFile));
|
||||
|
||||
// Create report.
|
||||
buffer = await createReport({
|
||||
template,
|
||||
data: {
|
||||
inventarnummer: objectData.inventarnummer ? objectData.inventarnummer : 'unbekannt' ,
|
||||
titel: objectData.titel ? objectData.titel : 'unbekannt',
|
||||
hersteller: objectData.hersteller ? objectData.hersteller : 'unbekannt',
|
||||
herstellungsort: objectData.herstellungsort ? objectData.herstellungsort : 'unbekannt',
|
||||
herstellungsdatum: objectData.herstellungsdatum ? objectData.herstellungsdatum : 'unbekannt',
|
||||
materialTechnik: objectData.materialTechnik ? objectData.materialTechnik : 'unbekannt' ,
|
||||
masse: objectData.masse ? objectData.masse : 'unbekannt'
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
// Set error log.
|
||||
log = {
|
||||
...log,
|
||||
status: 'red',
|
||||
message: 'Konnte Template nicht erstellen: ' + err,
|
||||
tip: 'Ist das Template vorhanden?',
|
||||
};
|
||||
return log
|
||||
}
|
||||
|
||||
// Create folder (if necessary).
|
||||
const objectPath = path.join(configJson.rootDir, objectData.inventarnummer);
|
||||
const documentPath = path.join(objectPath, documentInfo.documentType);
|
||||
const temporaryWorkDirPath = path.join(objectPath, 'werkstatt');
|
||||
try {
|
||||
const createDocumentPath = await mkdir(documentPath, {recursive: true});
|
||||
const createTemporaryWorkDirPath = await mkdir(temporaryWorkDirPath, {recursive: true});
|
||||
} catch (err) {
|
||||
// Set error log.
|
||||
log = {
|
||||
...log,
|
||||
status: 'red',
|
||||
message: 'Konnte den Pfad nicht erstellen' + err,
|
||||
tip: 'Bestehen Schreibrechte auf dem Ordner?'
|
||||
}
|
||||
return log
|
||||
}
|
||||
|
||||
// Write document to disk.
|
||||
if (buffer) {
|
||||
const normCharacterObjectId = replaceSpecialCharacters(objectData.inventarnummer)
|
||||
const normCharacterTitle = replaceSpecialCharacters(objectData.titel)
|
||||
const normSpacingTitle = normCharacterTitle.replace(/[^A-Z0-9]+/ig, "_");
|
||||
const filename = objectData.datum + '_' + normCharacterObjectId + '_' + normSpacingTitle + '.docx'
|
||||
fs.writeFileSync(path.join(documentPath, filename), buffer)
|
||||
log = {
|
||||
...log,
|
||||
status: 'green',
|
||||
message: 'Dokument erstellt',
|
||||
};
|
||||
}
|
||||
|
||||
} else {
|
||||
log = {
|
||||
status: 'red',
|
||||
message: 'Fehler bei der Kommunikation mit dem Objektkatalog',
|
||||
code: objectData.httpStatus,
|
||||
tip: 'Ist die Inventarnummer richtig?',
|
||||
};
|
||||
}
|
||||
return log;
|
||||
}
|
||||
30
src/Image.js
Normal file
30
src/Image.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import {blobToURL, fromURL} from "image-resize-compress";
|
||||
|
||||
class Image {
|
||||
constructor(originalUri, originalHeight = '300px', originalWidth = '200px', loading = 'lazy') {
|
||||
this.original = originalUri;
|
||||
this.originalHeight = originalHeight;
|
||||
this.originalWidth = originalWidth;
|
||||
this.loading = loading;
|
||||
|
||||
(async () => {
|
||||
this.thumbnail = await this.convert2Thumbnail(this.original)
|
||||
})();
|
||||
}
|
||||
convert2Thumbnail = async (sourceUrl) => {
|
||||
// quality value for webp and jpeg formats.
|
||||
const quality = 80;
|
||||
// output width. 0 will keep its original width and 'auto' will calculate its scale from height.
|
||||
const width = 100;
|
||||
// output height. 0 will keep its original height and 'auto' will calculate its scale from width.
|
||||
const height = 'auto';
|
||||
// file format: png, jpeg, bmp, gif, webp. If null, original format will be used.
|
||||
const format = 'webp';
|
||||
// note only the sourceUrl argument is required
|
||||
let blob = await fromURL(sourceUrl, quality, width, height, format);
|
||||
return await blobToURL(blob);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export {Image};
|
||||
|
|
@ -18,12 +18,14 @@ class ObjektkatalogApi {
|
|||
masse: '',
|
||||
materialTechnik: '',
|
||||
titel: '',
|
||||
wisskiUri: '',
|
||||
};
|
||||
response;
|
||||
visibility;
|
||||
|
||||
|
||||
// Get data from objektkatalog.gnm.de.
|
||||
|
||||
async getData(objectId) {
|
||||
if (objectId) {
|
||||
// RESTful GET.
|
||||
|
|
@ -50,6 +52,7 @@ class ObjektkatalogApi {
|
|||
eid: responseJson[0]['eid'],
|
||||
allgemeineBezeichnung: responseJson[0]['fc6392714594e73ddb2fa363815a8fdf'],
|
||||
beschreibung: responseJson[0]['f81f557caccf45074edfb65ff077011f'],
|
||||
bilder: responseJson[0]['f41dae62df47283958f605716d141ebf'],
|
||||
darstellung: responseJson[0]['f217e1053b1e29411d4b00f3b1e1d52b'],
|
||||
erwerbsmethode: responseJson[0]['fa4aa035d411275cd36a2fbb5c159a2c'],
|
||||
fruehstes: responseJson[0]['ff4a178095c895a12fce6320c04ba0b0'],
|
||||
|
|
@ -71,6 +74,7 @@ class ObjektkatalogApi {
|
|||
titel: responseJson[0]['f2049b2456b20f8fd80f714e154f1d47'],
|
||||
unterbringung: responseJson[0]['f15265e39237868a568ee63453492b17'],
|
||||
vitrinentext: responseJson[0]['fe5e3ff18aedf1d25c639dc79fb24ad1'],
|
||||
wisskiUri: responseJson[0]['wisski_uri'][0]['value'],
|
||||
zustandsbeschreibung: responseJson[0]['f54b6da6006ea444c33a348b8c4370a8']
|
||||
}
|
||||
break;
|
||||
|
|
@ -118,6 +122,16 @@ class ObjektkatalogApi {
|
|||
return [this.receivedData, this.visibility]
|
||||
}
|
||||
|
||||
// Bilder
|
||||
let bilder =[];
|
||||
if (this.raw.bilder.length !== 0) {
|
||||
for (const bildIndex in this.raw.bilder) {
|
||||
bilder.push(this.raw.bilder[bildIndex].url)
|
||||
}
|
||||
} else {
|
||||
this.bilder = null;
|
||||
}
|
||||
|
||||
// Datum
|
||||
// Default date of today
|
||||
let today = new Date()
|
||||
|
|
@ -187,9 +201,11 @@ class ObjektkatalogApi {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
// Json with important data.
|
||||
this.receivedData = {
|
||||
...this.receivedData,
|
||||
bilder: bilder,
|
||||
datum: todayFormat,
|
||||
titel: titel,
|
||||
hersteller: hersteller,
|
||||
|
|
@ -198,6 +214,7 @@ class ObjektkatalogApi {
|
|||
inventarnummer: inventarnummer,
|
||||
materialTechnik: materialTechnik,
|
||||
masse: masse,
|
||||
wisskiUri: this.raw.wisskiUri,
|
||||
httpStatus: 200,
|
||||
}
|
||||
this.visibility = true
|
||||
|
|
|
|||
3
src/assets/config/config.json
Normal file
3
src/assets/config/config.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"rootDir": "/home/rbrt/Schreibtisch/boehler"
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
/* Imports */
|
||||
@import url('https://fonts.googleapis.com/css?family=Open+Sans');
|
||||
@import "react-image-gallery/styles/css/image-gallery.css";
|
||||
|
||||
a {
|
||||
color: #d5d5d5;
|
||||
|
|
@ -23,6 +26,10 @@ body {
|
|||
.checkup {
|
||||
transition: height 1s;
|
||||
height: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.closed{
|
||||
|
|
@ -43,10 +50,6 @@ body {
|
|||
max-width: max-content;
|
||||
}
|
||||
|
||||
div {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.edit-button {
|
||||
background-color: #e30f27;
|
||||
color: #d5d5d5;
|
||||
|
|
@ -55,6 +58,7 @@ div {
|
|||
border: unset;
|
||||
padding: 0 4px;
|
||||
height: 1.5rem;
|
||||
border-radius: 0 .1875rem .1875rem 0;
|
||||
}
|
||||
|
||||
.edit-input {
|
||||
|
|
@ -87,6 +91,23 @@ div {
|
|||
background-color: darkgreen;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #464646;
|
||||
}
|
||||
|
||||
.image-gallery {
|
||||
flex: .5 .5 50%;
|
||||
}
|
||||
|
||||
.image-gallery-thumbnails-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.image-gallery-slide-wrapper {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.inactive {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -129,6 +150,10 @@ input.edit-input:not(:disabled) {
|
|||
font-family: "Open Sans", sans-serif;
|
||||
}
|
||||
|
||||
.justify-content-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.justify-content-end {
|
||||
|
|
@ -168,13 +193,16 @@ label {
|
|||
}
|
||||
|
||||
.open {
|
||||
height: 610px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pd-05rem {
|
||||
padding: .5rem;
|
||||
}
|
||||
.position-absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
|
@ -223,15 +251,15 @@ select {
|
|||
}
|
||||
|
||||
.settings-div {
|
||||
background-color: #d5d5d5;
|
||||
background-color: #f2f2f2;
|
||||
color: black;
|
||||
width: 300px;
|
||||
width: 388px;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
border-bottom: 0.125rem solid #e30019;
|
||||
border-radius: 0.1875rem;
|
||||
overflow-x: scroll;
|
||||
border-radius: .1875rem 0 0 .1875rem;
|
||||
overflow-x: auto;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
|
|
@ -256,10 +284,13 @@ textarea.select-folder-field, textarea.select-folder-field:focus, input.select-f
|
|||
}
|
||||
|
||||
.v-distance {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.bottom-distance {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
/* width */
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 434 B After Width: | Height: | Size: 434 B |
|
|
@ -1,6 +1,13 @@
|
|||
// Components
|
||||
import {DataForm} from "./DataForm";
|
||||
import {Log} from "./Log"
|
||||
|
||||
|
||||
// CSS
|
||||
import '../assets/css/styles.css'
|
||||
import {LoadingIcon} from "./LoadingIcon";
|
||||
|
||||
// Icons
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
|
||||
// Modules
|
||||
|
|
@ -10,10 +17,6 @@ import ObjektkatalogApi from "../ObjektkatalogApi";
|
|||
import {NavLink} from "react-router-dom";
|
||||
import React, {useState} from 'react'
|
||||
|
||||
// CSS
|
||||
import '../assets/css/styles.css'
|
||||
import {LoadingIcon} from "./LoadingIcon";
|
||||
|
||||
|
||||
////////////////////
|
||||
// Main //
|
||||
|
|
@ -91,8 +94,21 @@ export const App = () => {
|
|||
await setLogState({
|
||||
log: {
|
||||
status: 'red',
|
||||
message: 'Objektkatalog nicht erreichbar!',
|
||||
message: 'Objektkatalog kann sich nicht um die Anfrage kümmern!',
|
||||
code: '503',
|
||||
tip: 'Vielleicht hat der Katalog gerade sehr viele Zugriffe, probieren Sie es später noch einmal.',
|
||||
}, // with message, code, tip
|
||||
logClass: 'active'
|
||||
})
|
||||
// Hide Loading
|
||||
setIsLoading(false)
|
||||
return;
|
||||
case 404:
|
||||
await setLogState({
|
||||
log: {
|
||||
status: 'red',
|
||||
message: 'Objektkatalog nicht erreichbar!',
|
||||
code: '404',
|
||||
tip: 'Sind sie mit dem Internet verbunden und ist der Objektkatalog online?',
|
||||
}, // with message, code, tip
|
||||
logClass: 'active'
|
||||
|
|
@ -170,34 +186,38 @@ export const App = () => {
|
|||
<NavLink className={'nav-icon'} to="/settings"><SettingsIcon/></NavLink>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<div className={"container"}>
|
||||
<form id={"object-id-form"} className={"flex-wrap"}>
|
||||
<div className={"center column flex justify-content-space-between "}>
|
||||
<label htmlFor="document-type" className={"center cut v-distance"}>Dokumenttyp:</label>
|
||||
<select name="documentType" id="document-type" className={"input-field center cut"}>
|
||||
<option value="rp">Restaurierungsprotokoll</option>
|
||||
<option value="lbb">Leihgabenbegleitblatt</option>
|
||||
<option value="a">Analyse</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className={"center column flex full justify-content-space-between"}>
|
||||
<label htmlFor={"object-id"} className={"center cut v-distance"}>Inventarnummer:</label>
|
||||
<input
|
||||
id={"object-id"}
|
||||
name="objectId"
|
||||
type={"text"}
|
||||
className={"center cut input-field"}
|
||||
/>
|
||||
</div>
|
||||
<main className={"bottom-distance"}>
|
||||
<h3 className={"flex-center"}>Marvin</h3>
|
||||
<section>
|
||||
<div className={"container"}>
|
||||
<form id={"object-id-form"} className={"flex-wrap"}>
|
||||
<div className={"center column flex justify-content-space-between "}>
|
||||
<label htmlFor="document-type" className={"center cut v-distance"}>Dokumenttyp:</label>
|
||||
<select name="documentType" id="document-type" className={"input-field center cut"}>
|
||||
<option value="rp">Restaurierungsprotokoll</option>
|
||||
<option value="lbb">Leihgabenbegleitblatt</option>
|
||||
<option value="a">Analyse</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className={"center column flex full justify-content-space-between"}>
|
||||
<label htmlFor={"object-id"} className={"center cut v-distance"}>Inventarnummer:</label>
|
||||
<input
|
||||
id={"object-id"}
|
||||
name="objectId"
|
||||
type={"text"}
|
||||
className={"center cut input-field"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button className={'send-button center top-distance'} onClick={getDataAndAskForCheckUpClickHandler}>
|
||||
Dokument vorbereiten
|
||||
</button>
|
||||
<button className={'send-button center top-distance'} onClick={getDataAndAskForCheckUpClickHandler}>
|
||||
Dokument vorbereiten
|
||||
</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<LoadingIcon isLoading={isLoading}/>
|
||||
</form>
|
||||
</div>
|
||||
<LoadingIcon isLoading={isLoading}/>
|
||||
</section>
|
||||
<section>
|
||||
<DataForm
|
||||
checkUpVisibility={checkUpVisibility}
|
||||
objectData={objectData}
|
||||
|
|
@ -205,6 +225,7 @@ export const App = () => {
|
|||
logState={logState}
|
||||
setLogState={setLogState}
|
||||
/>
|
||||
</section>
|
||||
</main>
|
||||
<footer>
|
||||
{/* We give state and state setter of the parent as params to the child components, so that child events can change parent states */}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
// Components
|
||||
import {Galary} from './Galary'
|
||||
|
||||
// Modules
|
||||
import {fillTemplate} from "../DocxInserter";
|
||||
import {DocCreator} from "../DocCreator";
|
||||
|
||||
// React
|
||||
import React from 'react'
|
||||
|
|
@ -98,7 +101,10 @@ export const DataForm = ({checkUpVisibility, objectData, setObjectData, logState
|
|||
// Fill the template and save it.
|
||||
const fillTemplateClickHandler = async (e) => {
|
||||
e.preventDefault();
|
||||
log = await fillTemplate(logState, objectData);
|
||||
const docCreator = new DocCreator(logState, objectData)
|
||||
log = await docCreator.fillTemplate();
|
||||
const metsMods = await docCreator.createMetsMods();
|
||||
|
||||
// Set new state of log div with message and visibility class
|
||||
setLogState({
|
||||
log: log,
|
||||
|
|
@ -107,8 +113,11 @@ export const DataForm = ({checkUpVisibility, objectData, setObjectData, logState
|
|||
}
|
||||
|
||||
// Renders data form
|
||||
return (<div className={'checkup ' + (checkUpVisibility ? 'open' : 'closed')}>
|
||||
<form className={'flex column '}>
|
||||
return (
|
||||
<div className={'checkup ' + (checkUpVisibility ? 'open' : 'closed')}>
|
||||
<form className={'flex column pd-05rem'}>
|
||||
<Galary objectData={objectData}/>
|
||||
<div>
|
||||
<div >
|
||||
<label htmlFor={'template-datum'} >Datum</label>
|
||||
<input
|
||||
|
|
@ -198,6 +207,7 @@ export const DataForm = ({checkUpVisibility, objectData, setObjectData, logState
|
|||
onChange={masseChangeHandler}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type={"submit"}
|
||||
className={'send-button center top-distance'}
|
||||
|
|
|
|||
22
src/components/Galary.js
Normal file
22
src/components/Galary.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
import {Image} from "../Image";
|
||||
import ImageGallery from 'react-image-gallery';
|
||||
|
||||
|
||||
////////////////////
|
||||
// Main //
|
||||
////////////////////
|
||||
|
||||
export const Galary = ({objectData}) => {
|
||||
let images =[];
|
||||
if (objectData.bilder) {
|
||||
for (const imageIndex in objectData.bilder) {
|
||||
images.push(new Image(objectData.bilder[imageIndex]));
|
||||
}
|
||||
}
|
||||
return (
|
||||
<ImageGallery items={images} showFullscreenButton={false} showPlayButton={false} showThumbnails={false} disableKeyDown={true}/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Galary;
|
||||
|
|
@ -15,7 +15,7 @@ export const Log = ({logState, setLogState}) => {
|
|||
logClass: 'inactive'});
|
||||
}
|
||||
|
||||
const classes = 'round-box flex ' + logState.log.status + ' ' + logState.logClass
|
||||
const classes = 'round-box flex pd-05rem ' + logState.log.status + ' ' + logState.logClass
|
||||
if (logState.log.code) {
|
||||
code = ' Code: ' + logState.log.code
|
||||
} else {
|
||||
|
|
@ -29,10 +29,10 @@ export const Log = ({logState, setLogState}) => {
|
|||
return (
|
||||
<div className={'log '}>
|
||||
<div id={'log-content'} className={classes}>
|
||||
<div>
|
||||
<div className={"log-close-button"}>
|
||||
<button onClick={closeLog}>x</button>
|
||||
</div>
|
||||
<div className={'scroll-y flex-full'} style={{maxHeight: 4 + 'em'}}>
|
||||
<div className={'scroll-y flex-full pd-05rem'} style={{maxHeight: 4 + 'em'}}>
|
||||
<p>{logState.log.message}</p>
|
||||
<p>{code}</p>
|
||||
<p>{tip}</p>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// Config
|
||||
import configImport from '/resources/files/config/config.json'
|
||||
// Modules
|
||||
import path from "path";
|
||||
|
||||
// Components
|
||||
import {Log} from "../components/Log";
|
||||
// Config
|
||||
import configImport from '/src/assets/config/config.json'
|
||||
|
||||
// Icons
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
|
|
@ -48,8 +48,9 @@ export default function Settings() {
|
|||
rootDir: rootDirFromWindow
|
||||
}
|
||||
if (rootDirFromWindow) {
|
||||
console.log(__dirname);
|
||||
let message;
|
||||
await writeFile('resources/files/config/config.json', JSON.stringify(config2Safe, null, 2), (err) => {
|
||||
await writeFile('/resources/files/config/config.json', JSON.stringify(config2Safe, null, 2), (err) => {
|
||||
if (err) {
|
||||
message = err;
|
||||
} else {
|
||||
|
|
@ -68,19 +69,22 @@ export default function Settings() {
|
|||
<NavLink className={'nav-icon'} to="/"><ArrowBackIosIcon/></NavLink>
|
||||
</header>
|
||||
<main>
|
||||
<form onSubmit={selectFolderHandler}>
|
||||
<label htmlFor={"output-root"}>
|
||||
Hauptverzeichnis
|
||||
</label>
|
||||
<div className="col-sm-10 d-flex align-items-center flex sticky-edit">
|
||||
<Input config={config} setConfig={setConfig}/>
|
||||
<button type="submit" className="edit-button text-end">
|
||||
<i className="fas fa-edit d-block">
|
||||
<EditIcon sx={{fontSize: 16}} color={'#d5d5d5'}/>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<section className={"flex-center column"}>
|
||||
<h3>Einstellungen</h3>
|
||||
<form onSubmit={selectFolderHandler} className={"pd-05rem"}>
|
||||
<label className={"center cut v-distance"} htmlFor={"output-root"}>
|
||||
Hauptverzeichnis
|
||||
</label>
|
||||
<div className="align-items-center flex">
|
||||
<Input config={config} setConfig={setConfig}/>
|
||||
<button type="submit" className="edit-button text-end">
|
||||
<i className="fas fa-edit d-block">
|
||||
<EditIcon sx={{fontSize: 16}} color={'#d5d5d5'}/>
|
||||
</i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<footer>
|
||||
</footer>
|
||||
|
|
|
|||
|
|
@ -12,25 +12,23 @@ module.exports = {
|
|||
{
|
||||
test: /\.css$/,
|
||||
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }, { loader: 'postcss-loader' }],
|
||||
include: defaultInclude
|
||||
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
use: [{ loader: 'babel-loader' }],
|
||||
include: defaultInclude
|
||||
},
|
||||
{
|
||||
test: /\.(jpe?g|png|gif)$/,
|
||||
use: [{ loader: 'file-loader?name=img/[name]__[hash:base64:5].[ext]' }],
|
||||
include: defaultInclude
|
||||
},
|
||||
{
|
||||
test: /\.(eot|svg|ttf|woff|woff2)$/,
|
||||
use: [{ loader: 'file-loader?name=font/[name]__[hash:base64:5].[ext]' }],
|
||||
include: defaultInclude
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
target: 'electron-renderer',
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue