Design suggestion from AI. Not very useable

This commit is contained in:
2025-11-05 10:16:56 +01:00
parent 0cd09d0878
commit 32917113f2
14 changed files with 3257 additions and 269 deletions

View File

@@ -1,110 +1,403 @@
{% extends "base.html" %}
{% block title %}{{ standard }}{% endblock %}
{% block title %}{{ standard.nummer }} {{ standard.name }}{% endblock %}
{% block breadcrumb_items %}
<li class="breadcrumb-item"><a href="{% url 'standard_list' %}">Standards</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ standard.nummer }}</li>
{% endblock %}
{% block content %}
<h1>{{ standard.nummer }} {{ standard.name }}</h1>
{% if standard.history == True %}
<h2>Version vom {{ standard.check_date }}</h2>
{% endif %}
<!-- Autoren, Prüfende etc. -->
<p><strong>Autoren:</strong> {{ standard.autoren.all|join:", " }}</p>
<p><strong>Prüfende:</strong> {{ standard.pruefende.all|join:", " }}</p>
<p><strong>Gültigkeit:</strong> {{ standard.gueltigkeit_von }} bis {{ standard.gueltigkeit_bis|default_if_none:"auf weiteres" }}</p>
<p><a href="{% url 'standard_json' standard.nummer %}" class="button" download="{{ standard.nummer }}.json">JSON herunterladen</a></p>
<!-- Start Einleitung -->
{% if standard.einleitung_html %}
<h2>Einleitung</h2>
{% for typ, html in standard.einleitung_html %}
<div>{{ html|safe }}</div>
{% endfor %}
{% endif %}
<!-- End Einleitung -->
<!-- Start Geltungsbereich -->
{% if standard.geltungsbereich_html %}
<h2>Geltungsbereich</h2>
{% for typ, html in standard.geltungsbereich_html %}
<div>{{ html|safe }}</div>
{% endfor %}
{% endif %}
<!-- End Geltungsbereich -->
<h2>Vorgaben</h2>
{% for vorgabe in vorgaben %}
<!-- Start Vorgabe -->
{% if standard.history == True or vorgabe.long_status == "active" %}
<a id="{{ vorgabe.Vorgabennummer }}"></a><div class="card mb-4">
{% if vorgabe.long_status == "active"%}
<div class="card-header d-flex justify-content-between align-items-center bg-secondary text-light">
{% elif standard.history == True %}
<div class="card-header d-flex justify-content-between align-items-center bg-danger-subtle">
{% endif %}
<h3 class="h5 m-0">{{ vorgabe.Vorgabennummer }} {{ vorgabe.titel }}
{% if vorgabe.long_status != "active" and standard.history == True %}<span class="text-danger"> ({{ vorgabe.long_status}})</span>{% endif %}
</h3>
{% if vorgabe.relevanzset %}
<span class="badge bg-light text-black"> Relevanz:
{{ vorgabe.relevanzset|join:", " }}
</span>
{% endif %}
<span class="badge bg-light text-black">{{ vorgabe.thema }}</span>
<div class="row">
<!-- Main Content -->
<div class="col-lg-8">
<!-- Standard Header -->
<div class="card mb-4">
<div class="card-header bg-primary text-white">
<div class="d-flex justify-content-between align-items-start">
<div>
<h1 class="h2 mb-2">{{ standard.nummer }} {{ standard.name }}</h1>
{% if standard.history == True %}
<p class="mb-0 opacity-75">Version vom {{ standard.check_date|date:"d.m.Y" }}</p>
{% endif %}
</div>
<div class="d-flex gap-2">
{% if not standard.aktiv %}
<span class="badge bg-danger">Inaktiv</span>
{% else %}
<span class="badge bg-success">Aktiv</span>
{% endif %}
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6 class="text-muted mb-2">📅 Gültigkeit</h6>
<p class="mb-3">
<strong>Von:</strong> {{ standard.gueltigkeit_von|default_if_none:"-" }}<br>
<strong>Bis:</strong> {{ standard.gueltigkeit_bis|default_if_none:"Auf weiteres" }}
</p>
</div>
<div class="col-md-6">
<h6 class="text-muted mb-2">👥 Verantwortlich</h6>
{% if standard.autoren.all %}
<p class="mb-1"><strong>Autoren:</strong><br>
{% for autor in standard.autoren.all %}
<span class="badge bg-light text-dark me-1">{{ autor }}</span>
{% endfor %}
</p>
{% endif %}
{% if standard.pruefende.all %}
<p class="mb-3"><strong>Prüfende:</strong><br>
{% for pruefender in standard.pruefende.all %}
<span class="badge bg-light text-dark me-1">{{ pruefender }}</span>
{% endfor %}
</p>
{% endif %}
</div>
</div>
<div class="d-flex gap-2">
<a href="{% url 'standard_json' standard.nummer %}" class="btn btn-outline btn-sm" download="{{ standard.nummer }}.json">
📄 JSON herunterladen
</a>
<button class="btn btn-outline btn-sm" onclick="window.print()">
🖨️ Drucken
</button>
</div>
</div>
</div>
<div class="card-body p-0">
<!-- Start Kurztext -->
{% comment %} KURZTEXT BLOCK {% endcomment %}
{% if vorgabe.kurztext_html.0.1 %}
<div class="p-3 mb-3 bg-light border-3" style="width: 100%;">
{% for typ, html in vorgabe.kurztext_html %}
{% if html %}
<div class="mb-2">{{ html|safe }}</div>
<!-- Table of Contents -->
<div class="toc mb-4" id="table-of-contents">
<h3>📋 Inhaltsverzeichnis</h3>
<ul class="list-unstyled">
{% if standard.einleitung_html %}
<li><a href="#einleitung">Einleitung</a></li>
{% endif %}
{% if standard.geltungsbereich_html %}
<li><a href="#geltungsbereich">Geltungsbereich</a></li>
{% endif %}
<li><a href="#vorgaben">Vorgaben ({{ vorgaben|length }})</a>
<ul class="ms-3 mt-1">
{% for vorgabe in vorgaben %}
{% if standard.history == True or vorgabe.long_status == "active" %}
<li><a href="#{{ vorgabe.Vorgabennummer }}">{{ vorgabe.Vorgabennummer }} {{ vorgabe.titel|truncatechars:50 }}</a></li>
{% endif %}
{% endfor %}
</ul>
</li>
</ul>
</div>
<!-- Einleitung -->
{% if standard.einleitung_html %}
<section id="einleitung" class="mb-5">
<div class="card">
<div class="card-header">
<h2 class="h4 mb-0">📖 Einleitung</h2>
</div>
<div class="card-body">
{% for typ, html in standard.einleitung_html %}
<div class="content-section">{{ html|safe }}</div>
{% endfor %}
</div>
</div>
</section>
{% endif %}
<!-- Geltungsbereich -->
{% if standard.geltungsbereich_html %}
<section id="geltungsbereich" class="mb-5">
<div class="card">
<div class="card-header">
<h2 class="h4 mb-0">🎯 Geltungsbereich</h2>
</div>
<div class="card-body">
{% for typ, html in standard.geltungsbereich_html %}
<div class="content-section">{{ html|safe }}</div>
{% endfor %}
</div>
</div>
</section>
{% endif %}
<!-- Vorgaben -->
<section id="vorgaben" class="mb-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="h4 mb-0">📝 Vorgaben</h2>
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline btn-sm" onclick="toggleAllVorgaben(true)">Alle ausklappen</button>
<button type="button" class="btn btn-outline btn-sm" onclick="toggleAllVorgaben(false)">Alle einklappen</button>
</div>
</div>
{% for vorgabe in vorgaben %}
{% if standard.history == True or vorgabe.long_status == "active" %}
<div class="card mb-4 vorgabe-card" id="{{ vorgabe.Vorgabennummer }}">
<div class="card-header {% if vorgabe.long_status == "active" %}bg-success text-white{% else %}bg-secondary text-white{% endif %}"
style="cursor: pointer;"
onclick="toggleVorgabe('{{ vorgabe.Vorgabennummer }}')">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center">
<span class="toggle-icon me-2"></span>
<h3 class="h5 m-0">
{{ vorgabe.Vorgabennummer }} {{ vorgabe.titel }}
{% if vorgabe.long_status != "active" and standard.history == True %}
<span class="badge bg-warning text-dark ms-2">{{ vorgabe.long_status }}</span>
{% endif %}
</h3>
</div>
<div class="d-flex gap-2">
{% if vorgabe.relevanzset %}
<span class="badge bg-light text-dark">
🔥 {{ vorgabe.relevanzset|join:", " }}
</span>
{% endif %}
{% if vorgabe.thema %}
<span class="badge bg-info">{{ vorgabe.thema }}</span>
{% endif %}
</div>
</div>
</div>
<div class="card-body vorgabe-content" id="content-{{ vorgabe.Vorgabennummer }}">
<!-- Kurztext -->
{% if vorgabe.kurztext_html.0.1 %}
<div class="alert alert-info mb-3">
<h6 class="alert-heading">📌 Kurztext</h6>
{% for typ, html in vorgabe.kurztext_html %}
{% if html %}
<div class="mb-2">{{ html|safe }}</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% endfor %}
<!-- Langtext -->
<div class="mb-4">
{% for typ, html in vorgabe.langtext_html %}
{% if html %}
<div class="content-section mb-3">{{ html|safe }}</div>
{% endif %}
{% endfor %}
</div>
<!-- Checklistenfragen -->
<div class="mb-4">
<h6 class="mb-3">✅ Checklistenfragen</h6>
{% if vorgabe.checklistenfragen.all %}
<div class="list-group">
{% for frage in vorgabe.checklistenfragen.all %}
<div class="list-group-item">
<div class="d-flex align-items-start">
<input type="checkbox" class="form-check-input me-2 mt-1" id="check-{{ forloop.counter }}">
<label class="form-check-label" for="check-{{ forloop.counter }}">
{{ frage.frage }}
</label>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="text-muted"><em>Keine Checklistenfragen vorhanden</em></p>
{% endif %}
</div>
<!-- Metadaten -->
<div class="border-top pt-3">
<div class="row">
<div class="col-md-6">
<h6 class="text-muted mb-2">🏷️ Stichworte</h6>
{% if vorgabe.stichworte.all %}
<div>
{% for s in vorgabe.stichworte.all %}
<a href="{% url 'stichwort_detail' stichwort=s %}" class="badge bg-light text-dark text-decoration-none me-1 mb-1">
{{ s }}
</a>
{% endfor %}
</div>
{% else %}
<p class="text-muted small mb-0">Keine Stichworte</p>
{% endif %}
</div>
<div class="col-md-6">
<h6 class="text-muted mb-2">🔗 Referenzen</h6>
{% if vorgabe.referenzpfade %}
<div class="small">
{% for ref in vorgabe.referenzpfade %}
<div class="mb-1">{{ ref|safe }}</div>
{% endfor %}
</div>
{% else %}
<p class="text-muted small mb-0">Keine Referenzen</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endif %}
<!-- Langtext -->
<div class="p-3 mb-3">
{% comment %} LANGTEXT BLOCK {% endcomment %}
{# <h5>Langtext</h5> #}
{% for typ, html in vorgabe.langtext_html %}
{% if html %}<div class="mb-3">{{ html|safe }}</div>{% endif %}
{% endfor %}
<!-- Checklistenfragen -->
{% comment %} CHECKLISTENFRAGEN BLOCK {% endcomment %}
<h5>Checklistenfragen</h5>
{% if vorgabe.checklistenfragen.all %}
<ul class="list-group">
{% for frage in vorgabe.checklistenfragen.all %}
<li class="list-group-item">{{ frage.frage }}</li>
{% endfor %}
</ul>
{% else %}
<p><em>Keine Checklistenfragen</em></p>
{% endif %}
{% comment %} STICHWORTE + REFERENZEN AT BOTTOM {% endcomment %}
<div class="mt-4 small text-muted">
<strong>Stichworte:</strong>
{% if vorgabe.stichworte.all %}
{% for s in vorgabe.stichworte.all %}
<a href="{% url 'stichwort_detail' stichwort=s %}">{{ s }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
{% else %}
<em>Keine</em>
{% endif %}
<br>
<strong>Referenzen:</strong>
{% if vorgabe.referenzpfade %}
{% for ref in vorgabe.referenzpfade %}
{{ ref|safe }}{% if not forloop.last %}, {% endif %}
{% endfor %}
{% else %}
<em>Keine</em>
{% endif %}
</section>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Quick Actions -->
<div class="card mb-4 sticky-top" style="top: 1rem;">
<div class="card-header">
<h5 class="mb-0">⚡ Schnellaktionen</h5>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<button class="btn btn-outline btn-sm" onclick="scrollToSection('einleitung')">
📖 Zur Einleitung
</button>
<button class="btn btn-outline btn-sm" onclick="scrollToSection('geltungsbereich')">
🎯 Zum Geltungsbereich
</button>
<button class="btn btn-outline btn-sm" onclick="scrollToSection('vorgaben')">
📝 Zu den Vorgaben
</button>
<hr>
<a href="{% url 'standard_list' %}" class="btn btn-outline btn-sm">
← Zurück zur Liste
</a>
</div>
</div>
</div>
<!-- Statistics -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">📊 Statistiken</h5>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-6">
<div class="border-end">
<h4 class="text-primary mb-1">{{ vorgaben|length }}</h4>
<small class="text-muted">Vorgaben</small>
</div>
</div>
<div class="col-6">
<h4 class="text-success mb-1">
{% for vorgabe in vorgaben %}
{% if vorgabe.long_status == "active" %}
{% if forloop.first %}1{% else %}{{ forloop.counter }}{% endif %}
{% endif %}
{% endfor %}
</h4>
<small class="text-muted">Aktiv</small>
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
<!-- JavaScript -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Update active TOC item on scroll
const sections = document.querySelectorAll('section[id]');
const tocLinks = document.querySelectorAll('.toc a');
function updateActiveTOC() {
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
const sectionHeight = section.clientHeight;
if (pageYOffset >= sectionTop - 100) {
current = section.getAttribute('id');
}
});
tocLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href') === '#' + current) {
link.classList.add('active');
}
});
}
window.addEventListener('scroll', updateActiveTOC);
updateActiveTOC();
});
function toggleVorgabe(vorgabeId) {
const content = document.getElementById('content-' + vorgabeId);
const icon = document.querySelector('#' + vorgabeId + ' .toggle-icon');
if (content.style.display === 'none') {
content.style.display = 'block';
icon.textContent = '▼';
} else {
content.style.display = 'none';
icon.textContent = '▶';
}
}
function toggleAllVorgaben(expand) {
const contents = document.querySelectorAll('.vorgabe-content');
const icons = document.querySelectorAll('.toggle-icon');
contents.forEach(content => {
content.style.display = expand ? 'block' : 'none';
});
icons.forEach(icon => {
icon.textContent = expand ? '▼' : '▶';
});
}
function scrollToSection(sectionId) {
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
</script>
<style>
.content-section {
line-height: 1.6;
}
.content-section h1, .content-section h2, .content-section h3 {
margin-top: 1.5rem;
margin-bottom: 1rem;
}
.content-section ul, .content-section ol {
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.content-section li {
margin-bottom: 0.5rem;
}
.vorgabe-card {
transition: all 0.2s ease;
}
.vorgabe-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.toc a.active {
background-color: var(--primary-color);
color: white;
}
@media print {
.vorgabe-content {
display: block !important;
}
.toggle-icon {
display: none !important;
}
}
</style>
{% endblock %}

View File

@@ -1,13 +1,201 @@
{% extends "base.html" %}
{% block title %}Standards Informatiksicherheit{% endblock %}
{% block breadcrumb_items %}
<li class="breadcrumb-item active" aria-current="page">Standards</li>
{% endblock %}
{% block content %}
<h1>Standards Informatiksicherheit</h1>
<ul>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>Standards Informatiksicherheit</h1>
<div class="d-flex gap-2">
<span class="badge bg-primary">{{ dokumente|length }} Standards</span>
</div>
</div>
<!-- Filter and Search Section -->
<div class="card mb-4">
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label for="filter-search" class="form-label">Suchen</label>
<input type="text" class="form-control" id="filter-search" placeholder="Standard durchsuchen...">
</div>
<div class="col-md-3">
<label for="filter-status" class="form-label">Status</label>
<select class="form-select" id="filter-status">
<option value="">Alle</option>
<option value="active">Aktiv</option>
<option value="inactive">Inaktiv</option>
</select>
</div>
<div class="col-md-3">
<label for="filter-sort" class="form-label">Sortieren</label>
<select class="form-select" id="filter-sort">
<option value="nummer">Nummer</option>
<option value="name">Name</option>
<option value="gueltigkeit">Gültigkeit</option>
</select>
</div>
</div>
</div>
</div>
<!-- Standards Grid -->
<div class="row" id="standards-container">
{% for dokument in dokumente %}
<li>
<a href="{% url 'standard_detail' nummer=dokument.nummer %}">
{{ dokument.nummer }} {{ dokument.name }}
</a>
</li>
<div class="col-lg-6 col-xl-4 mb-4 standard-item"
data-nummer="{{ dokument.nummer|lower }}"
data-name="{{ dokument.name|lower }}"
data-status="{% if dokument.aktiv %}active{% else %}inactive{% endif %}">
<div class="card standard-card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<div>
<span class="standard-number">{{ dokument.nummer }}</span>
{% if not dokument.aktiv %}
<span class="badge badge-status-inactive ms-2">Inaktiv</span>
{% else %}
<span class="badge badge-status-active ms-2">Aktiv</span>
{% endif %}
</div>
<div class="dropdown">
<button class="btn btn-sm btn-outline" type="button" data-bs-toggle="dropdown">
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'standard_detail' nummer=dokument.nummer %}">Details anzeigen</a></li>
<li><a class="dropdown-item" href="{% url 'standard_json' dokument.nummer %}" download="{{ dokument.nummer }}.json">JSON herunterladen</a></li>
</ul>
</div>
</div>
<div class="card-body">
<h5 class="card-title">
<a href="{% url 'standard_detail' nummer=dokument.nummer %}" class="text-decoration-none">
{{ dokument.name }}
</a>
</h5>
<div class="standard-meta mb-3">
<div class="row g-2">
<div class="col-6">
<small class="text-muted">
<strong>Gültig von:</strong><br>
{{ dokument.gueltigkeit_von|default_if_none:"-" }}
</small>
</div>
<div class="col-6">
<small class="text-muted">
<strong>Gültig bis:</strong><br>
{{ dokument.gueltigkeit_bis|default_if_none:"Auf weiteres" }}
</small>
</div>
</div>
</div>
{% if dokument.autoren.all %}
<div class="mb-2">
<small class="text-muted">
<strong>Autoren:</strong>
{% for autor in dokument.autoren.all %}
{{ autor }}{% if not forloop.last %}, {% endif %}
{% endfor %}
</small>
</div>
{% endif %}
{% if dokument.pruefende.all %}
<div class="mb-3">
<small class="text-muted">
<strong>Prüfende:</strong>
{% for pruefender in dokument.pruefende.all %}
{{ pruefender }}{% if not forloop.last %}, {% endif %}
{% endfor %}
</small>
</div>
{% endif %}
<div class="d-flex justify-content-between align-items-center">
<a href="{% url 'standard_detail' nummer=dokument.nummer %}" class="btn btn-primary btn-sm">
Details anzeigen
</a>
<div class="text-muted">
<small>
{% if dokument.history %}
Version vom {{ dokument.check_date|date:"d.m.Y" }}
{% endif %}
</small>
</div>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12">
<div class="text-center py-5">
<h3 class="text-muted">Keine Standards gefunden</h3>
<p class="text-muted">Es wurden keine Standards gefunden, die Ihren Kriterien entsprechen.</p>
</div>
</div>
{% endfor %}
</ul>
</div>
<!-- JavaScript for filtering and sorting -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('filter-search');
const statusSelect = document.getElementById('filter-status');
const sortSelect = document.getElementById('filter-sort');
const container = document.getElementById('standards-container');
function filterAndSort() {
const searchTerm = searchInput.value.toLowerCase();
const statusFilter = statusSelect.value;
const sortBy = sortSelect.value;
let items = Array.from(container.querySelectorAll('.standard-item'));
// Filter
items = items.filter(item => {
const nummer = item.dataset.nummer;
const name = item.dataset.name;
const status = item.dataset.status;
const matchesSearch = !searchTerm ||
nummer.includes(searchTerm) ||
name.includes(searchTerm);
const matchesStatus = !statusFilter || status === statusFilter;
return matchesSearch && matchesStatus;
});
// Sort
items.sort((a, b) => {
switch(sortBy) {
case 'nummer':
return a.dataset.nummer.localeCompare(b.dataset.nummer);
case 'name':
return a.dataset.name.localeCompare(b.dataset.name);
case 'gueltigkeit':
// This would need additional data attributes for proper sorting
return a.dataset.nummer.localeCompare(b.dataset.nummer);
default:
return 0;
}
});
// Reorder DOM
items.forEach(item => container.appendChild(item));
// Show/hide no results message
const noResults = container.querySelector('.col-12 .text-center');
if (noResults) {
noResults.parentElement.style.display = items.length === 0 ? 'block' : 'none';
}
}
searchInput.addEventListener('input', filterAndSort);
statusSelect.addEventListener('change', filterAndSort);
sortSelect.addEventListener('change', filterAndSort);
});
</script>
{% endblock %}