add notes app

This commit is contained in:
Java-Fish 2025-06-10 14:49:08 +02:00
parent acb398be1c
commit a29376b3c5
38 changed files with 1720 additions and 45 deletions

View file

@ -0,0 +1,75 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}{{ title }} - Notizen{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-lg-8 mx-auto">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>
<i class="fas fa-paperclip text-primary"></i>
{{ title }}
</h1>
<a href="javascript:history.back()" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> Zurück
</a>
</div>
<div class="alert alert-info mb-4">
<h5 class="alert-heading">
<i class="fas fa-info-circle"></i> Notiz anhängen
</h5>
<p class="mb-0">
Sie erstellen eine neue Notiz, die an <strong>{{ content_object }}</strong> angehängt wird.
Die Notiz wird auf der Detailseite dieses Objekts angezeigt.
</p>
</div>
<div class="card">
<div class="card-body">
<form method="post" novalidate>
{% csrf_token %}
<div class="mb-3">
{{ form.name|as_crispy_field }}
</div>
<div class="mb-4">
{{ form.inhalt|as_crispy_field }}
</div>
<div class="d-flex justify-content-between">
<div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-paperclip"></i> Notiz anhängen
</button>
<a href="javascript:history.back()" class="btn btn-outline-secondary ms-2">
<i class="fas fa-times"></i> Abbrechen
</a>
</div>
</div>
</form>
</div>
</div>
<div class="card mt-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-lightbulb"></i> Tipps für Notizen
</h5>
</div>
<div class="card-body">
<ul class="mb-0">
<li>Verwenden Sie Markdown-Syntax für Formatierung (z.B. **fett**, *kursiv*)</li>
<li>Notizen werden automatisch als HTML gerendert angezeigt</li>
<li>Sie können die Notiz später jederzeit bearbeiten</li>
<li>Angehängte Notizen sind nur für angemeldete Benutzer sichtbar</li>
</ul>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,57 @@
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-lg-8">
<h3>Notiz zu "{{ page.name }}" hinzufügen</h3>
<p class="text-muted">
Fügen Sie eine Notiz zu dieser Übersichtsseite hinzu. Die Notiz wird am Ende der Seite angezeigt.
</p>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="mt-3">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Notiz speichern
</button>
<a href="javascript:history.back()" class="btn btn-secondary">
<i class="fas fa-times"></i> Abbrechen
</a>
</div>
</form>
</div>
<div class="col-lg-4">
<div class="card">
<div class="card-header">
<h5><i class="fas fa-info-circle"></i> Hinweise</h5>
</div>
<div class="card-body">
<h6>Markdown-Unterstützung</h6>
<p class="small">
Sie können Markdown-Syntax verwenden, um Ihre Notiz zu formatieren:
</p>
<ul class="small">
<li><strong>**Fett**</strong> für fetten Text</li>
<li><em>*Kursiv*</em> für kursiven Text</li>
<li><code># Überschrift</code> für Überschriften</li>
<li><code>- Punkt</code> für Listen</li>
<li><code>[Link](URL)</code> für Links</li>
</ul>
<h6 class="mt-3">Sichtbarkeit</h6>
<p class="small">
Diese Notiz wird am Ende der Übersichtsseite "{{ page.name }}" angezeigt
und ist für alle Benutzer sichtbar, die Zugriff auf diese Seite haben.
</p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,86 @@
{% extends "base.html" %}
{% block title %}Notiz löschen - {{ notiz.name }}{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 mx-auto">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>
<i class="fas fa-trash text-danger"></i>
Notiz löschen
</h1>
<a href="{% url 'notizen:detail' notiz.pk %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> Zurück
</a>
</div>
<div class="alert alert-danger">
<h4 class="alert-heading">
<i class="fas fa-exclamation-triangle"></i> Achtung!
</h4>
<p>Sie sind dabei, die folgende Notiz unwiderruflich zu löschen:</p>
<hr>
<h5>{{ notiz.name }}</h5>
{% if notiz.attached_to_object_str %}
<p class="mb-0">
<small class="text-muted">
Angehängt an: {{ notiz.attached_to_model_name }} - {{ notiz.attached_to_object_str }}
</small>
</p>
{% endif %}
</div>
<div class="card">
<div class="card-header">
<h5 class="mb-0">Bestätigung erforderlich</h5>
</div>
<div class="card-body">
<p>Diese Aktion kann nicht rückgängig gemacht werden. Sind Sie sicher, dass Sie diese Notiz löschen möchten?</p>
<form method="post">
{% csrf_token %}
<div class="d-flex justify-content-between">
<div>
<button type="submit" class="btn btn-danger">
<i class="fas fa-trash"></i> Ja, endgültig löschen
</button>
</div>
<div>
<a href="{% url 'notizen:detail' notiz.pk %}" class="btn btn-outline-secondary">
<i class="fas fa-times"></i> Abbrechen
</a>
</div>
</div>
</form>
</div>
</div>
<div class="card mt-4">
<div class="card-header">
<h5 class="mb-0">Notiz-Details</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-sm-4"><strong>Name:</strong></div>
<div class="col-sm-8">{{ notiz.name }}</div>
</div>
<div class="row">
<div class="col-sm-4"><strong>Erstellt von:</strong></div>
<div class="col-sm-8">{{ notiz.erstellt_von.get_full_name|default:notiz.erstellt_von.username }}</div>
</div>
<div class="row">
<div class="col-sm-4"><strong>Erstellt am:</strong></div>
<div class="col-sm-8">{{ notiz.erstellt_am|date:"d.m.Y H:i" }}</div>
</div>
<div class="row">
<div class="col-sm-4"><strong>Zuletzt geändert:</strong></div>
<div class="col-sm-8">{{ notiz.geaendert_am|date:"d.m.Y H:i" }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,138 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}{{ notiz.name }} - Notizen{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>
<i class="fas fa-sticky-note text-primary"></i>
{{ notiz.name }}
</h1>
<div class="btn-group" role="group">
<a href="{% url 'notizen:list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> Zurück zur Liste
</a>
<a href="{% url 'notizen:edit' notiz.pk %}" class="btn btn-primary">
<i class="fas fa-edit"></i> Bearbeiten
</a>
</div>
</div>
{% if notiz.attached_to_object_str %}
<div class="alert alert-info mb-4">
<i class="fas fa-paperclip"></i>
Diese Notiz ist angehängt an: <strong>{{ notiz.attached_to_model_name }} - {{ notiz.attached_to_object_str }}</strong>
</div>
{% endif %}
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<small class="text-muted">
Erstellt von: {{ notiz.erstellt_von.get_full_name|default:notiz.erstellt_von.username }}
am {{ notiz.erstellt_am|date:"d.m.Y H:i" }}
</small>
</div>
<div class="col-auto">
<small class="text-muted">
Zuletzt geändert: {{ notiz.geaendert_am|date:"d.m.Y H:i" }}
</small>
</div>
</div>
</div>
<div class="card-body">
<div class="notiz-content">
{{ html_content|safe }}
</div>
</div>
<div class="card-footer bg-transparent">
<div class="btn-group" role="group">
<a href="{% url 'notizen:edit' notiz.pk %}" class="btn btn-primary">
<i class="fas fa-edit"></i> Bearbeiten
</a>
<a href="{% url 'notizen:delete' notiz.pk %}" class="btn btn-outline-danger">
<i class="fas fa-trash"></i> Löschen
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.notiz-content {
line-height: 1.6;
}
.notiz-content h1, .notiz-content h2, .notiz-content h3,
.notiz-content h4, .notiz-content h5, .notiz-content h6 {
margin-top: 1.5rem;
margin-bottom: 1rem;
}
.notiz-content h1:first-child, .notiz-content h2:first-child,
.notiz-content h3:first-child, .notiz-content h4:first-child,
.notiz-content h5:first-child, .notiz-content h6:first-child {
margin-top: 0;
}
.notiz-content p {
margin-bottom: 1rem;
}
.notiz-content pre {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 0.375rem;
padding: 1rem;
overflow-x: auto;
}
.notiz-content code {
background-color: #f8f9fa;
padding: 0.125rem 0.25rem;
border-radius: 0.25rem;
font-size: 0.875em;
}
.notiz-content pre code {
background-color: transparent;
padding: 0;
}
.notiz-content blockquote {
border-left: 4px solid #dee2e6;
padding-left: 1rem;
margin: 1rem 0;
color: #6c757d;
}
.notiz-content ul, .notiz-content ol {
margin-bottom: 1rem;
padding-left: 2rem;
}
.notiz-content table {
width: 100%;
margin-bottom: 1rem;
border-collapse: collapse;
}
.notiz-content table th,
.notiz-content table td {
padding: 0.5rem;
border: 1px solid #dee2e6;
}
.notiz-content table th {
background-color: #f8f9fa;
font-weight: 600;
}
</style>
{% endblock %}

View file

@ -0,0 +1,100 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}{{ title }} - Notizen{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-lg-8 mx-auto">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>
<i class="fas fa-sticky-note text-primary"></i>
{{ title }}
</h1>
<a href="{% url 'notizen:list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> Zurück zur Liste
</a>
</div>
<div class="card">
<div class="card-body">
<form method="post" novalidate>
{% csrf_token %}
<div class="mb-3">
{{ form.name|as_crispy_field }}
</div>
<div class="mb-4">
{{ form.inhalt|as_crispy_field }}
</div>
<div class="d-flex justify-content-between">
<div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Speichern
</button>
<a href="{% url 'notizen:list' %}" class="btn btn-outline-secondary ms-2">
<i class="fas fa-times"></i> Abbrechen
</a>
</div>
{% if notiz %}
<div>
<a href="{% url 'notizen:detail' notiz.pk %}" class="btn btn-outline-info">
<i class="fas fa-eye"></i> Vorschau
</a>
<a href="{% url 'notizen:delete' notiz.pk %}" class="btn btn-outline-danger ms-2">
<i class="fas fa-trash"></i> Löschen
</a>
</div>
{% endif %}
</div>
</form>
</div>
</div>
{% if notiz %}
<div class="card mt-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-info-circle"></i> Notiz-Informationen
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<p><strong>Erstellt von:</strong> {{ notiz.erstellt_von.get_full_name|default:notiz.erstellt_von.username }}</p>
<p><strong>Erstellt am:</strong> {{ notiz.erstellt_am|date:"d.m.Y H:i" }}</p>
</div>
<div class="col-md-6">
<p><strong>Zuletzt geändert:</strong> {{ notiz.geaendert_am|date:"d.m.Y H:i" }}</p>
{% if notiz.attached_to_object_str %}
<p><strong>Angehängt an:</strong> {{ notiz.attached_to_model_name }} - {{ notiz.attached_to_object_str }}</p>
{% endif %}
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
{{ block.super }}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Auto-save draft functionality could be added here
const form = document.querySelector('form');
const nameField = document.querySelector('#id_name');
// Auto-focus on name field for new notes
if (nameField && !nameField.value) {
nameField.focus();
}
});
</script>
{% endblock %}

View file

@ -0,0 +1,108 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block title %}Notizen{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col">
<h1 class="mb-4">
<i class="fas fa-sticky-note text-primary"></i>
Meine Notizen
</h1>
<div class="mb-3">
<a href="{% url 'notizen:create' %}" class="btn btn-primary">
<i class="fas fa-plus"></i> Neue Notiz erstellen
</a>
</div>
{% if notizen %}
<div class="row">
{% for notiz in notizen %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title">
<a href="{% url 'notizen:detail' notiz.pk %}" class="text-decoration-none">
{{ notiz.name }}
</a>
</h5>
{% if notiz.attached_to_object_str %}
<p class="card-text">
<small class="text-muted">
<i class="fas fa-paperclip"></i>
Angehängt an: {{ notiz.attached_to_model_name }} - {{ notiz.attached_to_object_str }}
</small>
</p>
{% endif %}
<p class="card-text">
<small class="text-muted">
Zuletzt bearbeitet: {{ notiz.geaendert_am|date:"d.m.Y H:i" }}
</small>
</p>
</div>
<div class="card-footer bg-transparent">
<div class="btn-group btn-group-sm" role="group">
<a href="{% url 'notizen:detail' notiz.pk %}" class="btn btn-outline-primary">
<i class="fas fa-eye"></i> Anzeigen
</a>
<a href="{% url 'notizen:edit' notiz.pk %}" class="btn btn-outline-secondary">
<i class="fas fa-edit"></i> Bearbeiten
</a>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<!-- Pagination -->
{% if page_obj.has_other_pages %}
<nav aria-label="Notizen Navigation">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1">Erste</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Zurück</a>
</li>
{% endif %}
<li class="page-item active">
<span class="page-link">
Seite {{ page_obj.number }} von {{ page_obj.paginator.num_pages }}
</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">Weiter</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}">Letzte</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<div class="alert alert-info">
<h4 class="alert-heading">Keine Notizen vorhanden</h4>
<p>Sie haben noch keine Notizen erstellt.</p>
<hr>
<p class="mb-0">
<a href="{% url 'notizen:create' %}" class="btn btn-primary">
<i class="fas fa-plus"></i> Erste Notiz erstellen
</a>
</p>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,125 @@
{% load static %}
{% load notizen_tags %}
<!-- Notizen für dieses Objekt -->
{% if notizen_with_html %}
<div class="mt-4">
<h4>
<i class="fas fa-sticky-note text-primary"></i>
Notizen ({{ notizen_with_html|length }})
</h4>
{% for item in notizen_with_html %}
<div class="card mb-3">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">{{ item.notiz.name }}</h5>
<div class="btn-group btn-group-sm">
<a href="{% url 'notizen:edit' item.notiz.pk %}" class="btn btn-outline-primary">
<i class="fas fa-edit"></i> Bearbeiten
</a>
<a href="{% url 'notizen:detail' item.notiz.pk %}" class="btn btn-outline-secondary">
<i class="fas fa-external-link-alt"></i> Vollansicht
</a>
</div>
</div>
<small class="text-muted">
Von {{ item.notiz.erstellt_von.get_full_name|default:item.notiz.erstellt_von.username }}
am {{ item.notiz.erstellt_am|date:"d.m.Y H:i" }}
{% if item.notiz.geaendert_am != item.notiz.erstellt_am %}
(bearbeitet am {{ item.notiz.geaendert_am|date:"d.m.Y H:i" }})
{% endif %}
</small>
</div>
<div class="card-body">
<div class="notiz-content">
{{ item.html_content|safe }}
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
<!-- Button zum Hinzufügen einer neuen Notiz -->
<div class="mt-3">
{% if user.is_authenticated %}
<a href="{% url 'notizen:attach' content_type.id content_object.pk %}" class="btn btn-outline-primary">
<i class="fas fa-plus"></i> Notiz hinzufügen
</a>
{% endif %}
</div>
<style>
.notiz-content {
line-height: 1.6;
}
.notiz-content h1, .notiz-content h2, .notiz-content h3,
.notiz-content h4, .notiz-content h5, .notiz-content h6 {
margin-top: 1rem;
margin-bottom: 0.5rem;
}
.notiz-content h1:first-child, .notiz-content h2:first-child,
.notiz-content h3:first-child, .notiz-content h4:first-child,
.notiz-content h5:first-child, .notiz-content h6:first-child {
margin-top: 0;
}
.notiz-content p {
margin-bottom: 0.75rem;
}
.notiz-content pre {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 0.375rem;
padding: 0.75rem;
overflow-x: auto;
font-size: 0.875em;
}
.notiz-content code {
background-color: #f8f9fa;
padding: 0.125rem 0.25rem;
border-radius: 0.25rem;
font-size: 0.875em;
}
.notiz-content pre code {
background-color: transparent;
padding: 0;
}
.notiz-content blockquote {
border-left: 4px solid #dee2e6;
padding-left: 1rem;
margin: 1rem 0;
color: #6c757d;
font-style: italic;
}
.notiz-content ul, .notiz-content ol {
margin-bottom: 0.75rem;
padding-left: 1.5rem;
}
.notiz-content table {
width: 100%;
margin-bottom: 1rem;
border-collapse: collapse;
}
.notiz-content table th,
.notiz-content table td {
padding: 0.5rem;
border: 1px solid #dee2e6;
text-align: left;
}
.notiz-content table th {
background-color: #f8f9fa;
font-weight: 600;
}
</style>

View file

@ -0,0 +1,98 @@
{% load static %}
{% load notizen_tags %}
<!-- Notizen für diese Seite -->
{% if notizen_with_html %}
<div class="mt-4 mb-4" style="border-top: 2px solid #dc3545; padding-top: 20px;">
<h4>
<i class="fas fa-sticky-note text-primary"></i>
Notizen zu dieser Übersicht ({{ notizen_with_html|length }})
</h4>
{% for item in notizen_with_html %}
<div class="card mb-3">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">{{ item.notiz.name }}</h5>
<div class="btn-group btn-group-sm">
<a href="{% url 'notizen:edit' item.notiz.pk %}" class="btn btn-outline-primary">
<i class="fas fa-edit"></i> Bearbeiten
</a>
<a href="{% url 'notizen:detail' item.notiz.pk %}" class="btn btn-outline-secondary">
<i class="fas fa-eye"></i> Details
</a>
</div>
</div>
<small class="text-muted">
<i class="fas fa-calendar"></i> {{ item.notiz.geaendert_am|date:"d.m.Y H:i" }} Uhr
{% if item.notiz.autor %}
| <i class="fas fa-user"></i> {{ item.notiz.autor }}
{% endif %}
</small>
</div>
<div class="card-body">
<div class="notiz-content">
{{ item.html_content|safe }}
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
<!-- Button zum Hinzufügen einer neuen Notiz -->
<div class="mt-3 mb-4" style="border-top: 1px solid #dee2e6; padding-top: 15px;">
{% if user.is_authenticated %}
<a href="{% url 'notizen:attach_page' page_identifier %}" class="btn btn-outline-primary">
<i class="fas fa-plus"></i> Notiz zu dieser Übersicht hinzufügen
</a>
{% endif %}
</div>
<style>
.notiz-content {
line-height: 1.6;
}
.notiz-content h1,
.notiz-content h2,
.notiz-content h3,
.notiz-content h4,
.notiz-content h5,
.notiz-content h6 {
margin-top: 1rem;
margin-bottom: 0.5rem;
}
.notiz-content p {
margin-bottom: 1rem;
}
.notiz-content ul,
.notiz-content ol {
margin-bottom: 1rem;
padding-left: 2rem;
}
.notiz-content blockquote {
border-left: 4px solid #007bff;
padding-left: 1rem;
margin-left: 0;
font-style: italic;
color: #6c757d;
}
.notiz-content code {
background-color: #f8f9fa;
padding: 0.2rem 0.4rem;
border-radius: 0.25rem;
font-size: 0.875em;
}
.notiz-content pre {
background-color: #f8f9fa;
padding: 1rem;
border-radius: 0.25rem;
overflow-x: auto;
}
</style>