Author SHA1 Message Date
tsindt 8a0be322d2 Merge branch 'main' into HTMLMockup 2026-09-25 07:10:13 +02:00
tsindt 3116696a79 Tabelle 2026-09-25 06:26:53 +02:00
tsindt f01587a4f7 Treeview und Formfeld als Dummy aufgebaut 2026-09-22 15:47:59 +02:00
tsindt 56064d672f Update README.md
Externe Libs dokumentiert
2026-09-22 09:47:49 +02:00
tsindt 77ed6e0869 CSS glatt gezogen 2026-09-22 09:45:13 +02:00
tsindt 2c22601cd6 CSS Fixes 2026-09-21 23:07:55 +02:00
tsindt 1a06080a82 Erster Wurf des Mockups 2026-09-21 18:28:23 +02:00
tsindt a631b31341 Update README.md 2026-09-21 09:18:08 +02:00
tsindt c533d8a39e Merge pull request 'sourcen übernommen und wieder compilierbar gemacht.' (#5) from 3_Wiederverwendung into main
Reviewed-on: #5
2026-09-21 08:06:47 +02:00
8 changed files with 390 additions and 25 deletions
+77
View File
@@ -49,3 +49,80 @@ Als Quelltext-Editor / IDE kommt VSCode zum Einsatz.
### DBeaver ### DBeaver
Ist der Datenbank-Editor Ist der Datenbank-Editor
## Technische Dokumentation
### 20.09.2026 Grundsätzliche technische Entscheidungen
#### Systeme:
- Programmiersprache : - GO
- Javascript
- SQL
- Datenbank: Postgresql
- Webtechnologie: HTMX
#### Grundlegende technische Entscheidungen
- Jedes relevante Objekt (z.B. Produkte) hat eine Darstellung als:
- Node (Raumdarstellung)
- Form (Darstellung des Objektes und Editiermöglichkeit) - List (Listen /Tabellensicht
- Alle Objekte werden in der API über ihre eindeutige ID angesprochen. Über die ID kann ich den Typ des Objektes herausfinden
- Objekte werden nur bei Bedarf aus der Datenbank geladen.
- Objekte werden nach dem Laden oder Anlegen gechached!
- Weboberflächen zur Pflege der Daten aber auch die Seiten zur Nutzung des CPQ müssen responsive sein!
- Nutzung des 12- Spalten loyouts!
- Alle Images haben einen Alternativen Text
- Struktur der Oberfläche und die Darstellung werden strikt getrennt (HTML + CSS)
- Die Entwicklung erfolgt über die Definition von Tickets
- Jedes Ticket verursacht ein Brauch und einen Merge!
### Open Source - Pakete
#### Go:
##### Viper
Viper dient zum Laden uns Auswerten von Config-Dateien. In diesem Case werden die HTTP-Servereinstellungen und die Datenbankverbindung ausgewertet.
````
go get github.com/spf13/viper
````
##### PostgreSQL
Die Datenbank des Systems ist in dem Datenbankmanagementsystem PostgreSQL abgelegt. Zum einen braucht es eine Installation des Systems, auf dem die Software Zugriff hat und zum anderen benötigt das System die entsprechenden PostgreSQL Treiber für Go.
````
go get github.com/lib/pq
````
##### Gin Gonic
Webserver Library zum Routing der API.
````
go get -u github.com/gin-gonic/gin
go get github.com/gin-contrib/cors
go get github.com/gin-contrib/sessions
````
##### Go Air
Go Air ist ein Live-Reload-Tool für Go-Anwendungen, das die Entwicklungsproduktivität erhöht.
````
go install github.com/air-verse/air@latest
export PATH="$PATH:$(go env GOPATH)/bin"
````
Den Export ggf. in der .bashrc oder .zshrc hinzufügen.
#### HTML Erweiterungen
ggf. später lokal runter laden ...
##### HTMX
HTMX ist eine JavaScript-Bibliothek, die es ermöglicht, HTML direkt über AJAX-Anfragen zu aktualisieren.
````
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
````
+1 -1
View File
@@ -49,7 +49,7 @@ func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
router := gin.Default() router := gin.Default()
// initialize templates // initialize templates
//router.LoadHTMLGlob("../templates/**/*.html") router.LoadHTMLGlob("../templates/**/*.html")
router.Use(cors.Default()) router.Use(cors.Default())
@@ -18,4 +18,5 @@ func NewMainHandler(p *services.PropertyTypeService) *MainHandler {
func (h *MainHandler) Home(ctx *gin.Context) { func (h *MainHandler) Home(ctx *gin.Context) {
// Implement the logic for the main handler's home endpoint here // Implement the logic for the main handler's home endpoint here
ctx.HTML(200, "index.html", nil)
} }
+69 -4
View File
@@ -3,7 +3,7 @@
main { main {
padding: var(--main-content-padding); padding: var(--main-content-padding);
margin: 16px; margin: 16px;
height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding) - 64px); height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding));
/* 32px für die Margen */ /* 32px für die Margen */
overflow-y: auto; overflow-y: auto;
/* Scrollbar, wenn der Inhalt zu groß ist */ /* Scrollbar, wenn der Inhalt zu groß ist */
@@ -11,8 +11,49 @@ main {
border-radius: var(--box-border-radius); border-radius: var(--box-border-radius);
} }
nav {
height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding));
overflow-y: auto;
/* Scrollbar, wenn der Inhalt zu groß ist */
display: flex; /* Macht die Liste horizontal */
justify-content: flex-start; /* Elemente am Anfang ausrichten */
flex-direction: column; /* Elemente vertikal anordnen */
border: 1px solid var(--secondary-color);
border-radius: var(--box-border-radius);
margin-left: 16px;
@media (max-width: 768px) {
height: 100%;
}
padding: 5px;
background-color: var(--primary-color);
color: var(--secondary-font-color);
}
nav ul {
list-style-type: none; /* Entfernt die Standard-Aufzählungszeichen */
flex-wrap: wrap; /* Elemente umbrechen, wenn der Platz nicht ausreicht */
gap: 20px; /* Abstand zwischen den Listenelementen */
}
nav ul li a {
text-decoration: none; /* Entfernt die Unterstreichung */
color: var(--secondary-font-color); /* Setzt die Schriftfarbe */
}
nav ul li a:hover {
text-decoration: underline; /* Unterstreichung beim Überfahren mit der Maus */
font-weight: bold; /* Macht den Text fett */
}
.rootNode {
padding-top: 28px;
/* Einrückung für die Wurzelknoten */
color: var(--primary-color);
font-weight: bold;
}
.editor-container { .editor-container {
height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding) - 132px); height: calc(100vh - var(--header-height) - var(--footer-height) - 4 * var(--main-content-padding) - 96px);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
/* Elemente horizontal anordnen */ /* Elemente horizontal anordnen */
@@ -48,13 +89,12 @@ main {
} }
.leaf { .leaf {
padding-left: 20px; padding-left: 28px;
/* Einrückung für Blätter */ /* Einrückung für Blätter */
color: var(--primary-color); color: var(--primary-color);
font-weight: lighter; font-weight: lighter;
} }
/* form styles */ /* form styles */
.cform { .cform {
display: flex; display: flex;
@@ -101,3 +141,28 @@ main {
.mt-16 { .mt-16 {
margin-top: 16px; margin-top: 16px;
} }
/* Table styles */
table {
margin: 16px;
width: 80%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid var(--primary-color);
}
th, td {
padding: 8px;
text-align: left;
}
td {
background-color: var(--data-background-color);
}
th {
color: var(--primary-color);
font-weight: 500;
}
+14 -1
View File
@@ -7,5 +7,18 @@ footer {
border-radius: var(--box-border-radius); border-radius: var(--box-border-radius);
color: var(--secondary-font-color); color: var(--secondary-font-color);
margin: 16px; margin: 16px;
padding: 10px; @media (max-width: 768px) {
padding: 0px; /* Adjust the padding for smaller screens */
margin: 8px; /* Adjust the margin for smaller screens */
}
} }
footer a {
text-decoration: none; /* Entfernt die Unterstreichung */
color: var(--secondary-font-color); /* Setzt die Schriftfarbe */
}
footer a:hover {
text-decoration: underline; /* Unterstreichung beim Überfahren mit der Maus */
font-weight: bold; /* Macht den Text fett */
}
+53 -1
View File
@@ -14,7 +14,7 @@
--data-background-color: #ffffff; --data-background-color: #ffffff;
/* Dimensions */ /* Dimensions */
--header-height: 32px; --header-height: 64px;
--footer-height: 32px; --footer-height: 32px;
--main-content-padding: 20px; --main-content-padding: 20px;
--box-border-radius: 10px; --box-border-radius: 10px;
@@ -32,8 +32,60 @@
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box;
} }
// 12 Spalten Grid System
.row::after {
content: "";
clear: both;
display: table;
}
[class*="col-"] {
float: left;
padding: 15px;
}
/* Responsive Anpassungen Handy */
[class*="col-"] {
width: 100%;
}
/* Responsive Anpassungen Tablet */
@media screen and (min-width: 600px) {
.col-s-1 {width: 8.33%;}
.col-s-2 {width: 16.66%;}
.col-s-3 {width: 25%;}
.col-s-4 {width: 33.33%;}
.col-s-5 {width: 41.66%;}
.col-s-6 {width: 50%;}
.col-s-7 {width: 58.33%;}
.col-s-8 {width: 66.66%;}
.col-s-9 {width: 75%;}
.col-s-10 {width: 83.33%;}
.col-s-11 {width: 91.66%;}
.col-s-12 {width: 100%;}
}
/* Spaltenbreiten für 12 Spalten Grid */
@media screen and (min-width: 768px) {
.col-1 {width: 8.33%;}
.col-2 {width: 16.66%;}
.col-3 {width: 25%;}
.col-4 {width: 33.33%;}
.col-5 {width: 41.66%;}
.col-6 {width: 50%;}
.col-7 {width: 58.33%;}
.col-8 {width: 66.66%;}
.col-9 {width: 75%;}
.col-10 {width: 83.33%;}
.col-11 {width: 91.66%;}
.col-12 {width: 100%;}
}
/* 2. Schriftart anwenden und Ränder entfernen*/ /* 2. Schriftart anwenden und Ränder entfernen*/
body { body {
font-family: 'Inter', Arial, sans-serif; font-family: 'Inter', Arial, sans-serif;
+17 -17
View File
@@ -4,6 +4,12 @@
header { header {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
flex-direction: row;
@media (max-width: 768px) {
flex-direction: column;
justify-content: center;
align-items: center;
}
align-items: center; align-items: center;
height: var(--header-height); height: var(--header-height);
@@ -21,28 +27,22 @@ header img {
padding-right: 16px; /* Space between the image and the header text */ padding-right: 16px; /* Space between the image and the header text */
} }
header h1 {
font-weight: 600;
font-size: 2em; /* Adjust the font size as needed */
margin-left: 5px;
padding: 16px;
@media (max-width: 768px) {
font-size: 1em; /* Adjust the font size for smaller screens */
padding: 0px; /* Adjust the padding for smaller screens */
}
}
header p { header p {
font-weight: 100; font-weight: 100;
margin-left: 16px; margin-left: 16px;
padding-right: 16px; padding-right: 16px;
} }
nav {
margin: 16px;
padding: 10px;
}
nav ul {
list-style-type: none; /* Entfernt die Standard-Aufzählungszeichen */
display: flex; /* Macht die Liste horizontal */
gap: 20px; /* Abstand zwischen den Listenelementen */
}
nav ul li a {
text-decoration: none; /* Entfernt die Unterstreichung */
color: var(--secondary-font-color); /* Setzt die Schriftfarbe */
}
nav ul li a:hover {
text-decoration: underline; /* Unterstreichung beim Überfahren mit der Maus */
font-weight: bold; /* Macht den Text fett */
}
+157
View File
@@ -0,0 +1,157 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/css/scpq_global.css">
<link rel="stylesheet" href="/static/css/scpq_header.css">
<link rel="stylesheet" href="/static/css/scpq_footer.css">
<link rel="stylesheet" href="/static/css/scpq_content.css">
<title>Simply CPQ Material Editor V2</title>
</head>
<body>
<header class="row">
<div class="col-8 col-s-12">
<h1>Simply CPQ Material Editor V2</h1>
</div>
</header>
<div class="row">
<nav class="col-2 col-s-12">
<ul>
<li>
<ul>
<details closed>
<summary>
Eigenschaften
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Produkte
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Regeln
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Preiskalkulation
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
<li>
<ul>
<details closed>
<summary>
Übersetzungen
</summary>
<ul class="node">
<li class="leaf"><a href="#">Unterpunkt 1</a></li>
<li class="leaf"><a href="#">Unterpunkt 2</a></li>
</ul>
</details>
</ul>
</li>
</ul>
</nav>
<main>
<div class="col-6 col-s-6">
<h3>Property-Type Group </h3>
<section class="editor-view">
<section id="PropertyTypeGroupData">
<form class="cform" method="post" action="/updatePropertyTypeGroup">
<label for="propertyTypeGroupID">ID:</label>
<input type="text" id="propertyTypeGroupID" name="propertyTypeGroupID" value="{PropertyTypeGroupID}" disabled>
<label for="propertyTypeGroupName">Name:</label>
<input type="text" id="propertyTypeGroupName" name="propertyTypeGroupName" value="{PropertyTypeGroupName}">
<label for="propertyTypeGroupDescription">Beschreibung:</label>
<textarea id="propertyTypeGroupDescription" name="propertyTypeGroupDescription">{PropertyTypeGroupDescription}</textarea>
<div class="button_row">
<button type="submit">Speichern</button>
<button type="submit">Neu</button>
<button type="submit">Löschen</button>
</div>
</form>
</section>
</section>
</div>
<div class="col-6 col-s-12">
<div class="aside">
<h3>Values für {PropertyTypeName}</h3>
<section class="editor-view">
<section id="ValueData">
<table>
<tr>
<th>ID</th>
<th>Value</th>
<th>Description</th>
<th>Actions</th>
</tr>
<tr>
<td>1</td>
<td>Value 1</td>
<td>Description 1</td>
<td>
<div class="button_row">
<button type="button">Edit</button>
<button type="button">Delete</button>
</div>
</td>
</tr>
<tr>
<td>2</td>
<td>Value 2</td>
<td>Description 2</td>
<td>
<div class="button_row">
<button type="button">Edit</button>
<button type="button">Delete</button>
</div>
</td>
</tr>
</table>
</section>
</section>
</div>
</div>
</main>
</div> <!-- Closing the initial row div -->
<footer class="row">
<div class="col-12 col-s-12">
<h6>&copy; 2026 Simply CPQ - All rights reserved - contact: <a href="mailto:Thomas.Sindt@gmx.de">Thomas.Sindt@gmx.de</a></h6>
</div>
</footer> <!-- Closing the footer row div -->
</body>
</html>