Compare commits

..
8 changed files with 148 additions and 291 deletions

View file

@ -1,34 +0,0 @@
Loin vers l'infini s'étendent
Les grands prés marécageux .
Pas un seul oiseau ne chante
Sur les arbres secs et creux !
*(Refrain)*
Ô terre de détresse,
Où nous devons sans cesse,
Piocher, piocher .
Dans ce camp morne et sauvage
Entouré de murs de fer,
Il nous semble vivre en cage
Au milieu d'un grand désert .
Bruit des pas et bruit des armes,
Sentinelles jours et nuits,
Et du sang, et des cris, des larmes,
La mort pour celui qui fuit .
Mais un jour dans notre vie,
Le printemps refleurira .
Liberté, liberté chérie
Je dirai : « Tu es à moi ! »
*(Dernier refrain)*
Ô terre d'allégresse,
Où nous pourrons sans cesse,
Aimer, aimer !
[audio : Mario Hacquard - Youtube](https://www.youtube.com/watch?v=ogw_mgk1pFs)

View file

@ -1,61 +0,0 @@
<UserControl
x:Class="PostIt.Controls.MarkdownEditorControl"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:AvaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
xmlns:md="using:MarkdownViewer.Core.Controls"
x:Name="Root"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="260">
<Border
BorderBrush="LightGray"
BorderThickness="1"
CornerRadius="5"
IsVisible="{Binding !IsPreviewVisible, ElementName=Root}"
Padding="0"
MinHeight="260">
<ScrollViewer
BringIntoViewOnFocusChange="False"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<AvaloniaEdit:TextEditor
x:Name="SourceEditor"
Document="{Binding Document, ElementName=Root, Mode=TwoWay}"
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
ShowLineNumbers="True"
WordWrap="True"
BorderThickness="0"
Padding="5,5,5,15"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
TextInputOptions.Multiline="True"
TextInputOptions.ReturnKeyType="Default" />
</ScrollViewer>
</Border>
<Border
BorderBrush="LightGray"
BorderThickness="1"
CornerRadius="5"
IsVisible="{Binding IsPreviewVisible, ElementName=Root}"
Padding="8"
MinHeight="260">
<ScrollViewer
BringIntoViewOnFocusChange="False"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<md:MarkdownViewer
x:Name="PreviewViewer"
MarkdownText="{Binding MarkdownText, ElementName=Root}"
ClipToBounds="False" />
</ScrollViewer>
</Border>
</Grid>
</UserControl>

View file

@ -1,88 +0,0 @@
using System;
using Avalonia;
using Avalonia.Controls;
using AvaloniaEdit.Document;
namespace PostIt.Controls;
public partial class MarkdownEditorControl : UserControl
{
public static readonly StyledProperty<string?> MarkdownTextProperty =
AvaloniaProperty.Register<MarkdownEditorControl, string?>(nameof(MarkdownText));
public static readonly StyledProperty<TextDocument?> DocumentProperty =
AvaloniaProperty.Register<MarkdownEditorControl, TextDocument?>(nameof(Document));
public static readonly StyledProperty<bool> IsPreviewVisibleProperty =
AvaloniaProperty.Register<MarkdownEditorControl, bool>(nameof(IsPreviewVisible), false);
public string? MarkdownText
{
get => GetValue(MarkdownTextProperty);
set => SetValue(MarkdownTextProperty, value);
}
public TextDocument? Document
{
get => GetValue(DocumentProperty);
set => SetValue(DocumentProperty, value);
}
public bool IsPreviewVisible
{
get => GetValue(IsPreviewVisibleProperty);
set => SetValue(IsPreviewVisibleProperty, value);
}
public MarkdownEditorControl()
{
InitializeComponent();
PropertyChanged += OnPropertyChanged;
SizeChanged += OnSizeChanged;
UpdateEditorLimits();
}
private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == MarkdownTextProperty)
{
var text = e.NewValue as string ?? string.Empty;
if (Document is null || !string.Equals(Document.Text, text, StringComparison.Ordinal))
{
Document = new TextDocument(text);
}
}
else if (e.Property == DocumentProperty)
{
var newDocument = e.NewValue as TextDocument;
var text = newDocument?.Text ?? string.Empty;
if (!string.Equals(MarkdownText, text, StringComparison.Ordinal))
{
MarkdownText = text;
}
}
}
private void OnSizeChanged(object? sender, SizeChangedEventArgs e)
{
UpdateEditorLimits();
}
private void UpdateEditorLimits()
{
var visibleHeight = Bounds.Height > 0 ? Bounds.Height - 24 : 260;
visibleHeight = Math.Max(visibleHeight, 80);
if (SourceEditor is not null)
{
SourceEditor.MaxHeight = visibleHeight;
SourceEditor.Height = double.NaN;
}
if (PreviewViewer is not null)
{
PreviewViewer.MaxHeight = visibleHeight;
PreviewViewer.Height = double.NaN;
}
}
}

View file

@ -39,56 +39,18 @@ public partial class BlogsViewModel : ViewModelBase, IActionStatusViewModel
/// <summary>Editor buffer for the post body. Same pattern as
/// <see cref="DraftTitle"/>.</summary>
public string? DraftArticle
public string DraftArticle
{
get => DraftArticleDocument?.Text ?? null;
set
{
var currentText = DraftArticleDocument?.Text;
if (string.Equals(currentText, value, StringComparison.Ordinal))
{
OnPropertyChanged(nameof(DraftArticle));
return;
}
get => DraftArticleDocument.Text;
set {
OnPropertyChanging(nameof(DraftArticle));
DraftArticleDocument = value is not null ? new TextDocument(value) : null;
OnPropertyChanged(nameof(DraftArticle));
DraftArticleDocument = new TextDocument(value);
this.OnPropertyChanged(nameof(DraftArticle));
}
}
private TextDocument? _draftArticleDocument;
public TextDocument? DraftArticleDocument
{
get => _draftArticleDocument;
set
{
if (ReferenceEquals(_draftArticleDocument, value))
{
return;
}
if (_draftArticleDocument is not null)
{
_draftArticleDocument.TextChanged -= DraftArticleDocument_TextChanged;
}
_draftArticleDocument = value;
if (_draftArticleDocument is not null)
{
_draftArticleDocument.TextChanged += DraftArticleDocument_TextChanged;
}
OnPropertyChanged(nameof(DraftArticleDocument));
}
}
private void DraftArticleDocument_TextChanged(object? sender, EventArgs e)
{
OnPropertyChanged(nameof(DraftArticle));
}
[ObservableProperty]
public partial TextDocument DraftArticleDocument {get; set;}
/// <summary>Editor buffer for the post's publication state.
/// Reflects the server-side <c>IsPublished</c> flag (the

View file

@ -17,14 +17,10 @@
<Design.DataContext>
<vm:BlogsViewModel />
</Design.DataContext>
<ScrollViewer
Margin="5,5,10,5"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
BringIntoViewOnFocusChange="False">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
Margin="5,5,10,5" HorizontalAlignment="Stretch" BringIntoViewOnFocusChange="False"
VerticalAlignment="Stretch">
<StackPanel>
<WrapPanel x:Name="BlogsHeaderPanel"
Margin="5"
@ -91,7 +87,7 @@
<PathIcon Data="{StaticResource PublishedIcon}" />
</CommandBarToggleButton.Icon>
</CommandBarToggleButton>
<CommandBarToggleButton IsChecked="{Binding IsMarkdownViewerVisible, Mode=TwoWay}" Label="Aperçu">
<CommandBarToggleButton IsChecked="{Binding IsMarkdownViewerVisible, Mode=TwoWay}" Label="Markdown Viewer">
<CommandBarToggleButton.Icon>
<PathIcon Data="{StaticResource MarkdownIcon}" />
</CommandBarToggleButton.Icon>
@ -107,7 +103,7 @@
</CommandBar.PrimaryCommands>
</CommandBar>
<Grid Margin="12" RowSpacing="12" x:Name="MainGrid" MinHeight="500">
<Grid Margin="12" RowSpacing="12" x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@ -141,61 +137,90 @@
</ListBox>
</Border>
<Grid
<Border
Grid.Row="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
FontWeight="SemiBold"
Text="Post detail" />
<TextBox
x:Name="DraftTitleTextBox"
Grid.Row="1"
PlaceholderText="Title"
Text="{Binding DraftTitle, Mode=TwoWay}" />
<postitControls:MarkdownEditorControl
Grid.Row="2"
Padding="8"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsPreviewVisible="{Binding IsMarkdownViewerVisible, Mode=TwoWay}"
MarkdownText="{Binding DraftArticle, Mode=TwoWay}"
Document="{Binding DraftArticleDocument, Mode=TwoWay}" />
BorderBrush="Gray"
BorderThickness="1"
IsVisible="{Binding IsMarkdownViewerVisible}">
<md:MarkdownViewer Name="MarkdownViewer" MarkdownText="{Binding DraftArticle}" />
</Border>
<Border x:Name="AttachmentsBorder"
Grid.Row="3"
Padding="8"
BorderBrush="LightGray"
BorderThickness="1"
<Border
Grid.Row="2"
Padding="8"
BorderBrush="Gray"
BorderThickness="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<StackPanel Spacing="4">
<TextBlock FontWeight="SemiBold" Text="Pièces jointes" />
<ItemsControl ItemsSource="{Binding DraftAttachments}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FileName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
VerticalAlignment="Stretch"
IsVisible="{Binding !IsMarkdownViewerVisible}">
<Grid
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<postitControls:StatusBar Grid.Row="4" DataContext="{Binding ActionStatus}" x:Name="StatusBar" />
<TextBlock
Grid.Row="0"
FontWeight="SemiBold"
Text="Post detail" />
<TextBox
x:Name="DraftTitleTextBox"
Grid.Row="1"
PlaceholderText="Title"
Text="{Binding DraftTitle, Mode=TwoWay}" />
</Grid>
<AvaloniaEdit:TextEditor
x:Name="DraftArticleTextEditor"
Grid.Row="2"
VerticalAlignment="Stretch"
Document="{Binding DraftArticleDocument, Mode=TwoWay}"
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
ShowLineNumbers="True"
WordWrap="True"
BorderThickness="1"
BorderBrush="LightGray"
CornerRadius="5"
Padding="5,5,5,15"
HorizontalScrollBarVisibility="Disabled"
TextInputOptions.Multiline="True"
TextInputOptions.ReturnKeyType="Default"
/>
<Border x:Name="AttachmentsBorder"
Grid.Row="3"
Padding="8"
BorderBrush="LightGray"
BorderThickness="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<StackPanel Spacing="4">
<TextBlock FontWeight="SemiBold" Text="Pièces jointes" />
<ItemsControl ItemsSource="{Binding DraftAttachments}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FileName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<postitControls:StatusBar Grid.Row="4" DataContext="{Binding ActionStatus}" x:Name="StatusBar" />
</Grid>
</Border>
</Grid>
</StackPanel>
</ScrollViewer>

View file

@ -4,16 +4,69 @@ using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Controls.Platform;
namespace PostIt.Views.Blogs;
public partial class BlogsPage : ContentPage
{
private IInputPane? _inputPane;
public BlogsPage()
{
InitializeComponent();
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
// Récupère l'accès au TopLevel de la fenêtre/application
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel != null)
{
_inputPane = topLevel!.InputPane;
if (_inputPane != null)
{
// S'abonne aux changements d'état du clavier virtuel
_inputPane.StateChanged += OnInputPaneStateChanged;
// Applique la configuration initiale si le clavier est déjà présent
UpdateLayoutForKeyboard(_inputPane.OccludedRect.Height);
}
}
}
protected override void OnUnloaded(RoutedEventArgs e)
{
if (_inputPane != null)
{
_inputPane.StateChanged -= OnInputPaneStateChanged;
}
base.OnUnloaded(e);
}
private void UpdateLayoutForKeyboard(double keyboardHeight)
{
double visibleHeight = this.Bounds.Height - keyboardHeight;
if (keyboardHeight > 0)
{
DraftArticleTextEditor.MaxHeight = visibleHeight;
}
else
{
DraftArticleTextEditor.MaxHeight = double.PositiveInfinity;
}
}
private void OnInputPaneStateChanged(object? sender, InputPaneStateEventArgs e)
{
// e.EndRect contient le rectangle final du clavier virtuel
// e.EndRect.Height vous donne sa hauteur exacte en pixels indépendants du périphérique (pixels logiques)
UpdateLayoutForKeyboard(e.EndRect.Height);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);

View file

@ -1 +1,4 @@
.user-icon{max-width:1.5em;max-height:1.5em}.card{padding:.5em}
.user-icon {
max-width: 1.5em;
max-height: 1.5em;
}

View file

@ -1,7 +1,4 @@
.user-icon {
user-icon {
max-width: 1.5em;
max-height: 1.5em;
}
.card {
padding: .5em;
}