UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4
Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag. Oberflaeche - Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml (eigene ControlThemes statt Fluent umzufaerben). - Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite statt eigenem Fenster, Texteditor-Fenster. - ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt. Rocket.Chat - Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird nur, wenn wirklich etwas anliegt. - send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist. - Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei Annahmen waren falsch und sind korrigiert. Deploymentcenter - DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json) erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke. - AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Der Rahmen mit den vier Eckmarken — das wiederkehrende Motiv des Entwurfs.
|
||||
///
|
||||
/// <para>Eigenes Steuerelement statt vier von Hand gesetzter Striche je Stelle: Die Marken
|
||||
/// liegen bewusst <em>halb außerhalb</em> des Rahmens, und das ist genau die Sorte Detail,
|
||||
/// die beim Nachbauen an der fünften Stelle nicht mehr stimmt.</para>
|
||||
///
|
||||
/// <para>Weil die Marken über den Rand hinausragen, darf kein Elternteil zuschneiden.
|
||||
/// In der Praxis heißt das: nicht direkt an den Fensterrand setzen, sondern mit etwas
|
||||
/// Abstand — die Vorlage im Entwurf tut dasselbe.</para>
|
||||
///
|
||||
/// <para>Sparsam verwenden. Im Entwurf tragen nur die Info-Karte und die beiden Dialoge
|
||||
/// die Marken; alle übrigen Karten sind schlichte Haarlinien-Kästen (Klasse
|
||||
/// <c>card</c> in <c>Styles/Shell.axaml</c>).</para>
|
||||
/// </summary>
|
||||
public sealed class BlueprintFrame : ContentControl
|
||||
{
|
||||
protected override Type StyleKeyOverride => typeof(BlueprintFrame);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Documents;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// Ein Strichsymbol aus dem Entwurf — 24×24-Geometrie, gezeichnet mit der geerbten
|
||||
/// Vordergrundfarbe.
|
||||
///
|
||||
/// <para>Warum nicht <c>PathIcon</c>: Das füllt seine Geometrie. Die Symbole des Entwurfs
|
||||
/// sind Umrisse (Lucide, Strichstärke 1.5); gefüllt werden daraus schwarze Klumpen.</para>
|
||||
///
|
||||
/// <para>Warum nicht <c>Path</c> mit <c>Stroke</c>: Dann müsste an jeder einzelnen Stelle
|
||||
/// die Farbe mitgegeben werden — und zwar die <em>richtige</em>, je nachdem ob das Symbol
|
||||
/// in einer Schaltfläche, einer ausgewählten Navigationszeile oder der Statusleiste sitzt.
|
||||
/// <see cref="Foreground"/> ist hier von <see cref="TextElement"/> übernommen und erbt
|
||||
/// daher wie eine Textfarbe: Wer den Text einfärbt, färbt das Symbol mit.</para>
|
||||
///
|
||||
/// <para>Die Strichstärke wird beim Skalieren mitskaliert. Das ist keine Nachlässigkeit,
|
||||
/// sondern das Verhalten von SVG: <c>stroke-width</c> zählt in Einheiten des viewBox.
|
||||
/// Ein Symbol mit 1.5 in 24×24, dargestellt auf 16 px, hat genau 1 px starke Linien.</para>
|
||||
/// </summary>
|
||||
public sealed class StrokeIcon : Control
|
||||
{
|
||||
/// <summary>Kantenlänge des Koordinatenraums aller Symbole (SVG-viewBox 0 0 24 24).</summary>
|
||||
private const double ViewBox = 24d;
|
||||
|
||||
public static readonly StyledProperty<Geometry?> DataProperty =
|
||||
AvaloniaProperty.Register<StrokeIcon, Geometry?>(nameof(Data));
|
||||
|
||||
/// <summary>Geerbt wie eine Textfarbe — siehe Klassenbeschreibung.</summary>
|
||||
public static readonly StyledProperty<IBrush?> ForegroundProperty =
|
||||
TextElement.ForegroundProperty.AddOwner<StrokeIcon>();
|
||||
|
||||
public static readonly StyledProperty<double> StrokeThicknessProperty =
|
||||
AvaloniaProperty.Register<StrokeIcon, double>(nameof(StrokeThickness), 1.5d);
|
||||
|
||||
/// <summary>Für die wenigen massiven Symbole des Entwurfs (Wiedergabe, Halt).</summary>
|
||||
public static readonly StyledProperty<bool> IsFilledProperty =
|
||||
AvaloniaProperty.Register<StrokeIcon, bool>(nameof(IsFilled));
|
||||
|
||||
static StrokeIcon()
|
||||
{
|
||||
AffectsRender<StrokeIcon>(
|
||||
DataProperty, ForegroundProperty, StrokeThicknessProperty, IsFilledProperty);
|
||||
AffectsMeasure<StrokeIcon>(DataProperty);
|
||||
}
|
||||
|
||||
public Geometry? Data
|
||||
{
|
||||
get => GetValue(DataProperty);
|
||||
set => SetValue(DataProperty, value);
|
||||
}
|
||||
|
||||
public IBrush? Foreground
|
||||
{
|
||||
get => GetValue(ForegroundProperty);
|
||||
set => SetValue(ForegroundProperty, value);
|
||||
}
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get => GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
|
||||
public bool IsFilled
|
||||
{
|
||||
get => GetValue(IsFilledProperty);
|
||||
set => SetValue(IsFilledProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ohne gesetzte Größe 16×16 — die Größe, in der die meisten Symbole im Entwurf stehen.
|
||||
/// Ein unbegrenzter Vorschlag würde das Symbol den ganzen Platz nehmen lassen.
|
||||
/// </summary>
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var width = double.IsInfinity(availableSize.Width) ? 16d : Math.Min(16d, availableSize.Width);
|
||||
var height = double.IsInfinity(availableSize.Height) ? 16d : Math.Min(16d, availableSize.Height);
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
if (Data is not { } geometry || Foreground is not { } brush) return;
|
||||
|
||||
var scale = Math.Min(Bounds.Width / ViewBox, Bounds.Height / ViewBox);
|
||||
if (scale <= 0) return;
|
||||
|
||||
// Mittig setzen, falls das Steuerelement nicht quadratisch ist.
|
||||
var offsetX = (Bounds.Width - ViewBox * scale) / 2;
|
||||
var offsetY = (Bounds.Height - ViewBox * scale) / 2;
|
||||
|
||||
using var _ = context.PushTransform(
|
||||
Matrix.CreateScale(scale, scale) * Matrix.CreateTranslation(offsetX, offsetY));
|
||||
|
||||
if (IsFilled)
|
||||
{
|
||||
context.DrawGeometry(brush, null, geometry);
|
||||
return;
|
||||
}
|
||||
|
||||
// Runde Enden und Verbindungen: Ohne sie verschwinden die Punkt-Symbole
|
||||
// (Pfadstücke der Länge 0.01, etwa in „Agenten-Chats") vollständig.
|
||||
var pen = new Pen(brush, StrokeThickness,
|
||||
lineCap: PenLineCap.Round, lineJoin: PenLineJoin.Round);
|
||||
|
||||
context.DrawGeometry(null, pen, geometry);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user