feat: add flowing templates and PDF import pipeline
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-08-31 19:56:25 +02:00
parent 95e3f677e4
commit 3e5f197bdb
19 changed files with 920 additions and 44 deletions
@@ -39,17 +39,17 @@ public sealed class StarterTemplateLibrary
}
public StarterTemplateItem Save(TemplateManifest manifest, string layoutSource,
IReadOnlyDictionary<string, byte[]> assets)
IReadOnlyDictionary<string, byte[]> assets, string? continuationLayoutSource = null)
{
var path = Path.Combine(_directory, SafeId(manifest.Id) + TemplatePackage.Extension);
TemplatePackage.Create(path, manifest, layoutSource, assets);
TemplatePackage.Create(path, manifest, layoutSource, assets, continuationLayoutSource);
return ToItem(manifest, path);
}
public StarterTemplateItem Import(string sourcePath)
{
var (template, layout) = LoadPackage(sourcePath);
return Save(template.Manifest, layout, template.Assets);
var (template, layout, continuationLayout) = LoadPackage(sourcePath);
return Save(template.Manifest, layout, template.Assets, continuationLayout);
}
public void Export(StarterTemplateItem item, string destinationPath)
@@ -64,13 +64,19 @@ public sealed class StarterTemplateLibrary
public StarterTemplateItem Duplicate(StarterTemplateItem item)
{
var (template, layout) = Load(item);
var (template, layout, continuationLayout) = LoadWithContinuation(item);
var id = CreateUniqueId(template.Manifest.Id + "-kopie");
var manifest = CopyManifest(template.Manifest, id, template.Manifest.Name + " - Kopie");
return Save(manifest, layout, template.Assets);
return Save(manifest, layout, template.Assets, continuationLayout);
}
public (LoadedTemplate Template, string LayoutSource) Load(StarterTemplateItem item) =>
public (LoadedTemplate Template, string LayoutSource) Load(StarterTemplateItem item)
{
var (template, layout, _) = LoadPackage(item.PackagePath);
return (template, layout);
}
public (LoadedTemplate Template, string LayoutSource, string? ContinuationLayoutSource) LoadWithContinuation(StarterTemplateItem item) =>
LoadPackage(item.PackagePath);
public void Delete(StarterTemplateItem item)
@@ -78,15 +84,24 @@ public sealed class StarterTemplateLibrary
if (File.Exists(item.PackagePath)) File.Delete(item.PackagePath);
}
private (LoadedTemplate Template, string LayoutSource) LoadPackage(string path)
private (LoadedTemplate Template, string LayoutSource, string? ContinuationLayoutSource) LoadPackage(string path)
{
var template = _loader.LoadFromPackage(path);
using var archive = ZipFile.OpenRead(path);
var layoutEntry = archive.Entries.FirstOrDefault(x => x.FullName.Equals(
template.Manifest.LayoutFile.Replace('\\', '/'), StringComparison.OrdinalIgnoreCase))
?? throw new InvalidDataException($"Layoutdatei „{template.Manifest.LayoutFile}“ fehlt.");
using var reader = new StreamReader(layoutEntry.Open());
return (template, reader.ReadToEnd());
string layoutSource;
using (var reader = new StreamReader(layoutEntry.Open())) layoutSource = reader.ReadToEnd();
string? continuationLayoutSource = null;
if (template.Manifest.ContinuationLayoutFile is { } continuationPath)
{
var continuationEntry = archive.Entries.First(x => x.FullName.Equals(
continuationPath.Replace('\\', '/'), StringComparison.OrdinalIgnoreCase));
using var reader = new StreamReader(continuationEntry.Open());
continuationLayoutSource = reader.ReadToEnd();
}
return (template, layoutSource, continuationLayoutSource);
}
public string CreateUniqueId(string baseId)
@@ -108,6 +123,7 @@ public sealed class StarterTemplateLibrary
Description = source.Description,
PageSize = new(source.PageSize.Width, source.PageSize.Height, source.PageSize.Unit),
LayoutFile = source.LayoutFile,
ContinuationLayoutFile = source.ContinuationLayoutFile,
MetadataFile = source.MetadataFile,
Metadata = new(source.Metadata, StringComparer.OrdinalIgnoreCase),
Placeholders = source.Placeholders.Select(x => new PlaceholderDefinition(x.Name, x.Type, x.Required,