diff --git a/BewerbungWebseite/Models/SiteContent/AboutSection.cs b/BewerbungWebseite/Models/SiteContent/AboutSection.cs new file mode 100644 index 0000000..7f0f6e0 --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/AboutSection.cs @@ -0,0 +1,41 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// Bereich "Ueber mich" (section id="about"). +public class AboutSection +{ + [StringLength(ContentLimits.Url, ErrorMessage = ContentLimits.TooLongMessage)] + public string Image { get; set; } = string.Empty; + + [StringLength(ContentLimits.AltText, ErrorMessage = ContentLimits.TooLongMessage)] + public string ImageAlt { get; set; } = string.Empty; + + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleLine1 { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleLine2 { get; set; } = string.Empty; + + /// Hervorgehobener Teil der zweiten Titelzeile. + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleLine2Highlight { get; set; } = string.Empty; + + [StringLength(ContentLimits.ParagraphText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Text { get; set; } = string.Empty; + + public List Facts { get; set; } = new(); +} + +/// Eine Zeile der Kurzuebersicht rechts unter dem Text. +public class FactItem +{ + [StringLength(ContentLimits.FactLabel, ErrorMessage = ContentLimits.TooLongMessage)] + public string Label { get; set; } = string.Empty; + + [StringLength(ContentLimits.FactValue, ErrorMessage = ContentLimits.TooLongMessage)] + public string Value { get; set; } = string.Empty; +} diff --git a/BewerbungWebseite/Models/SiteContent/ContactSection.cs b/BewerbungWebseite/Models/SiteContent/ContactSection.cs new file mode 100644 index 0000000..02cdfbb --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/ContactSection.cs @@ -0,0 +1,43 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// +/// Bereich "Kontakt" (section id="contact"). Enthaelt nur die Texte; +/// das Formular selbst bleibt Bestandteil der Seite und ist nicht editierbar. +/// +public class ContactSection +{ + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleHighlight { get; set; } = string.Empty; + + public List InfoBoxes { get; set; } = new(); + + /// Einleitungstext oberhalb der Formularfelder. + [StringLength(ContentLimits.FormIntro, ErrorMessage = ContentLimits.TooLongMessage)] + public string FormHeading { get; set; } = string.Empty; +} + +/// Eine Kontaktangabe (Standort, Telefon, E-Mail, ...). +public class ContactInfoItem +{ + /// CSS-Klasse des Icons, z. B. "flaticon-call". + [StringLength(ContentLimits.IconClass, ErrorMessage = ContentLimits.TooLongMessage)] + public string Icon { get; set; } = string.Empty; + + [StringLength(ContentLimits.FactLabel, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.FactValue, ErrorMessage = ContentLimits.TooLongMessage)] + public string Text { get; set; } = string.Empty; + + /// Optional: macht den Text zum Link, z. B. "tel:0797367355". + [StringLength(ContentLimits.Url, ErrorMessage = ContentLimits.TooLongMessage)] + public string LinkUrl { get; set; } = string.Empty; +} diff --git a/BewerbungWebseite/Models/SiteContent/DocumentsSection.cs b/BewerbungWebseite/Models/SiteContent/DocumentsSection.cs new file mode 100644 index 0000000..ff22adb --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/DocumentsSection.cs @@ -0,0 +1,34 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// Bereich "Dokumente und Zertifikate" (section id="documents"). +public class DocumentsSection +{ + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleHighlight { get; set; } = string.Empty; + + public List Items { get; set; } = new(); +} + +/// Ein Dokument bzw. Zertifikat mit Link auf die PDF-Datei. +public class DocumentItem +{ + [StringLength(ContentLimits.CardTitle, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.ParagraphText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Description { get; set; } = string.Empty; + + [StringLength(ContentLimits.Url, ErrorMessage = ContentLimits.TooLongMessage)] + public string FileUrl { get; set; } = string.Empty; + + [StringLength(ContentLimits.ButtonLabel, ErrorMessage = ContentLimits.TooLongMessage)] + public string LinkText { get; set; } = string.Empty; +} diff --git a/BewerbungWebseite/Models/SiteContent/ExperienceSection.cs b/BewerbungWebseite/Models/SiteContent/ExperienceSection.cs new file mode 100644 index 0000000..c048db0 --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/ExperienceSection.cs @@ -0,0 +1,43 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// Bereich "Berufliche Erfahrung" (section id="experience"). +public class ExperienceSection +{ + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleHighlight { get; set; } = string.Empty; + + public List Items { get; set; } = new(); + + [StringLength(ContentLimits.ButtonLabel, ErrorMessage = ContentLimits.TooLongMessage)] + public string ToggleMoreText { get; set; } = string.Empty; + + [StringLength(ContentLimits.ButtonLabel, ErrorMessage = ContentLimits.TooLongMessage)] + public string ToggleLessText { get; set; } = string.Empty; +} + +/// Ein Eintrag der Erfahrungs-Timeline. +public class ExperienceItem +{ + [StringLength(ContentLimits.CardTitle, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.Meta, ErrorMessage = ContentLimits.TooLongMessage)] + public string Meta { get; set; } = string.Empty; + + [StringLength(ContentLimits.DetailHeading, ErrorMessage = ContentLimits.TooLongMessage)] + public string DetailHeading { get; set; } = string.Empty; + + [StringLength(ContentLimits.ParagraphText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Text { get; set; } = string.Empty; + + /// true = erst nach Klick auf "Mehr erfahren" sichtbar. + public bool Collapsed { get; set; } +} diff --git a/BewerbungWebseite/Models/SiteContent/GoalsSection.cs b/BewerbungWebseite/Models/SiteContent/GoalsSection.cs new file mode 100644 index 0000000..54f0963 --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/GoalsSection.cs @@ -0,0 +1,35 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// Bereich "Meine Ziele" (section id="goals"). +public class GoalsSection +{ + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleHighlight { get; set; } = string.Empty; + + public List Items { get; set; } = new(); +} + +/// Eine Ziel-Kachel. +public class GoalItem +{ + /// CSS-Klasse des Icons, z. B. "flaticon-growth". + [StringLength(ContentLimits.IconClass, ErrorMessage = ContentLimits.TooLongMessage)] + public string Icon { get; set; } = string.Empty; + + [StringLength(ContentLimits.TileTitle, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.TileText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Text { get; set; } = string.Empty; + + /// true = hervorgehobene Kachel (CSS-Klasse "active"). + public bool Highlighted { get; set; } +} diff --git a/BewerbungWebseite/Models/SiteContent/HeroSection.cs b/BewerbungWebseite/Models/SiteContent/HeroSection.cs new file mode 100644 index 0000000..2cb22e8 --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/HeroSection.cs @@ -0,0 +1,45 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// Startbereich der Seite (section id="hero"). +public class HeroSection : IValidatableObject +{ + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + /// Grosse Titelzeilen. Die letzte Zeile wird farblich hervorgehoben. + public List TitleLines { get; set; } = new(); + + [StringLength(ContentLimits.ParagraphText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Intro { get; set; } = string.Empty; + + public LinkItem PrimaryButton { get; set; } = new(); + public LinkItem SecondaryButton { get; set; } = new(); + + /// Kleine Links unter den Buttons (LinkedIn, E-Mail, ...). + public List SocialLinks { get; set; } = new(); + + [StringLength(ContentLimits.Url, ErrorMessage = ContentLimits.TooLongMessage)] + public string PortraitImage { get; set; } = string.Empty; + + [StringLength(ContentLimits.AltText, ErrorMessage = ContentLimits.TooLongMessage)] + public string PortraitAlt { get; set; } = string.Empty; + + /// + /// Prueft die Titelzeilen einzeln: [StringLength] laesst sich nicht direkt + /// auf eine List<string> anwenden, deshalb hier von Hand. + /// + public IEnumerable Validate(ValidationContext validationContext) + { + for (var i = 0; i < TitleLines.Count; i++) + { + if (TitleLines[i]?.Length > ContentLimits.Heading) + { + yield return new ValidationResult( + $"Titelzeile {i + 1} darf höchstens {ContentLimits.Heading} Zeichen lang sein.", + [nameof(TitleLines)]); + } + } + } +} diff --git a/BewerbungWebseite/Models/SiteContent/ProjectsSection.cs b/BewerbungWebseite/Models/SiteContent/ProjectsSection.cs new file mode 100644 index 0000000..2cb0b51 --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/ProjectsSection.cs @@ -0,0 +1,46 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// Bereich "Projekte" (section id="projects"). +public class ProjectsSection +{ + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleHighlight { get; set; } = string.Empty; + + public List Items { get; set; } = new(); +} + +/// Eine Projektkarte. +public class ProjectItem +{ + [StringLength(ContentLimits.Url, ErrorMessage = ContentLimits.TooLongMessage)] + public string Image { get; set; } = string.Empty; + + [StringLength(ContentLimits.AltText, ErrorMessage = ContentLimits.TooLongMessage)] + public string ImageAlt { get; set; } = string.Empty; + + [StringLength(ContentLimits.CardTitle, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + /// Optionaler fett gesetzter Auftakt vor der Beschreibung, z. B. "Ziel:". + [StringLength(ContentLimits.DetailHeading, ErrorMessage = ContentLimits.TooLongMessage)] + public string DescriptionLead { get; set; } = string.Empty; + + [StringLength(ContentLimits.ParagraphText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Description { get; set; } = string.Empty; + + /// Zwischentitel mit Text ("TECH:", "Meine Arbeit:", ...). + public List Details { get; set; } = new(); + + public List Links { get; set; } = new(); + + /// true = breite Karte ueber die volle Breite mit Bild links. + public bool Wide { get; set; } +} diff --git a/BewerbungWebseite/Models/SiteContent/SkillsSection.cs b/BewerbungWebseite/Models/SiteContent/SkillsSection.cs new file mode 100644 index 0000000..d2ae924 --- /dev/null +++ b/BewerbungWebseite/Models/SiteContent/SkillsSection.cs @@ -0,0 +1,39 @@ +using System.ComponentModel.DataAnnotations; + +namespace BewerbungsSeite.Models.SiteContent; + +/// Bereich "Kompetenzen" (section id="skills"). +public class SkillsSection +{ + [StringLength(ContentLimits.Kicker, ErrorMessage = ContentLimits.TooLongMessage)] + public string Kicker { get; set; } = string.Empty; + + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + /// Hervorgehobener Teil des Titels. + [StringLength(ContentLimits.Heading, ErrorMessage = ContentLimits.TooLongMessage)] + public string TitleHighlight { get; set; } = string.Empty; + + [StringLength(ContentLimits.ParagraphText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Intro { get; set; } = string.Empty; + + public List Items { get; set; } = new(); +} + +/// Eine Kompetenz-Kachel. +public class SkillItem +{ + /// CSS-Klasse des Icons, z. B. "flaticon-pen". + [StringLength(ContentLimits.IconClass, ErrorMessage = ContentLimits.TooLongMessage)] + public string Icon { get; set; } = string.Empty; + + [StringLength(ContentLimits.TileTitle, ErrorMessage = ContentLimits.TooLongMessage)] + public string Title { get; set; } = string.Empty; + + [StringLength(ContentLimits.TileText, ErrorMessage = ContentLimits.TooLongMessage)] + public string Text { get; set; } = string.Empty; + + /// true = hervorgehobene Kachel (CSS-Klasse "active"). + public bool Highlighted { get; set; } +}