UI Tuneup!

This commit is contained in:
Max 2023-05-26 21:54:12 +02:00
parent 8af1497695
commit 863aa4777e
11 changed files with 216 additions and 184 deletions

View File

@ -5,7 +5,6 @@ using System.Threading.Tasks;
using CodeHollow.FeedReader; using CodeHollow.FeedReader;
using Serilog; using Serilog;
using SharpRss.Models; using SharpRss.Models;
using ToolQit.Extensions;
namespace SharpRss.Services namespace SharpRss.Services
{ {

View File

@ -3,13 +3,27 @@
<MudThemeProvider IsDarkMode="true"/> <MudThemeProvider IsDarkMode="true"/>
<MudDialogProvider/> <MudDialogProvider/>
<MudSnackbarProvider/> <MudSnackbarProvider/>
<style>
.blur_transparency {
backdrop-filter: blur(16px) saturate(180%);
background: rgba(0,0,0,0.3);
}
.layout_image{
background-image: url('http://s1.picswalls.com/wallpapers/2016/06/10/best-4k-wallpaper_065236736_309.jpg');
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
background-attachment: fixed;
}
</style>
<MudLayout>
<MudLayout style="background-image: url('http://s1.picswalls.com/wallpapers/2016/06/10/best-4k-wallpaper_065236736_309.jpg'); height: 100%; background-position: center; background-repeat: no-repeat; background-size: cover; background-attachment: fixed;"> <MudAppBar Class="blur_transparency">
<!-- Glassmorphism(backdrop-filter: blur(16px) saturate(180%);) added -->
<MudAppBar Color="Color.Transparent" Style="backdrop-filter: blur(16px) saturate(180%);">
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())"/> <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())"/>
<MudText Typo="Typo.h6">SharpRSS</MudText> <MudText Typo="Typo.h6">SharpRSS</MudText>
<MudSpacer/>
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Href="https://github.com/hmaxnl/SharpRSS" Target="_blank"></MudIconButton>
</MudAppBar> </MudAppBar>
<MudDrawer @bind-Open="@_drawerOpen" ClipMode="DrawerClipMode.Always"> <MudDrawer @bind-Open="@_drawerOpen" ClipMode="DrawerClipMode.Always">
<SideGuide/> <SideGuide/>

View File

@ -8,18 +8,17 @@ namespace WebSharpRSS.Models
{ {
public FeedItemData() public FeedItemData()
{ {
if (Link == null) return;
//FaviconUrl = new Uri(Link).AbsoluteUri;
//FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), Link.Remove(Link.IndexOf("http", StringComparison.Ordinal), Link.IndexOf("://", StringComparison.Ordinal) + 3));
} }
public static FeedItemData? FromModel(FeedItemModel model) => Utilities.ConvertFrom<FeedItemData, FeedItemModel>(model); public static FeedItemData? FromModel(FeedItemModel model) => Utilities.ConvertFrom<FeedItemData, FeedItemModel>(model);
private string? _faviconUrl;
public string? FaviconUrl public string? FaviconUrl
{ {
get get
{ {
if (Link == null) return null; if (Link == null || _faviconUrl != null) return _faviconUrl;
Uri uri = new Uri(Link); _faviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), new Uri(Link).Host);
return string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), uri.Host); return _faviconUrl;
} }
} }

View File

@ -19,14 +19,15 @@ namespace WebSharpRSS.Models
public TreeItemData(FeedModel feedModel) public TreeItemData(FeedModel feedModel)
{ {
FeedModel = feedModel; FeedModel = feedModel;
Title = feedModel.Title; Title = feedModel.Title ?? string.Empty;
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), feedModel.Url.Remove(feedModel.Url.IndexOf("http", StringComparison.Ordinal), feedModel.Url.IndexOf("://", StringComparison.Ordinal) + 3)); if (FeedModel.Url == null) return;
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), new Uri(FeedModel.Url).Host);
} }
public readonly GroupModel? GroupModel; public readonly GroupModel? GroupModel;
public readonly FeedModel? FeedModel; public readonly FeedModel? FeedModel;
public HashSet<TreeItemData>? Children { get; set; } public HashSet<TreeItemData>? Children { get; set; }
public string Title { get; set; } = string.Empty; public string Title { get; set; }
public bool IsSelected { get; set; } public bool IsSelected { get; set; }
public string? Icon { get; set; } public string? Icon { get; set; }
public string? FaviconUrl { get; set; } public string? FaviconUrl { get; set; }

View File

@ -1,68 +1,14 @@
@page "/" @page "/"
@using CodeHollow.FeedReader; @page "/dashboard"
@using SharpRss.Models;
@using WebSharpRSS.Models; @using WebSharpRSS.Models;
@using SharpRss.Services
@inject FeedStateContainer _stateContainer; @inject FeedStateContainer _stateContainer;
<MudStack Spacing="2" Class="ml-2 mr-2"> <MudText>Dashboard!</MudText>
@*@foreach (var feedItemData in _itemDatas) <MudGrid Spacing="2" Class="ml-2 mr-2">
{
<MudItem> </MudGrid>
<MudCard>
<MudCardContent>
<div style="justify-self: start;" class="d-flex align-center">
@if (feedItemData.Icon != null)
{
<MudIcon Icon="@feedItemData.Icon" Style="@($"color:{feedItemData.CategoryColorHex}")" />
}
@if (feedItemData.FaviconUrl != null)
{
<MudImage Src="@feedItemData.FaviconUrl" ObjectFit="ObjectFit.Contain" />
}
<MudText Class="d-inline pa-2 align-center">@feedItemData.FeedItem.Title</MudText>
</div>
<MudText Typo="Typo.body2">@feedItemData.FeedItem.Description</MudText>
<MudText Typo="Typo.overline">@feedItemData.FeedItem.PublishingDate.ToString()</MudText>
</MudCardContent>
</MudCard>
</MudItem>
}*@
</MudStack>
@code { @code {
protected override void OnInitialized()
{
UpdateFeeds();
//_stateContainer.StateChanged += FeedsChanged;
}
private void FeedsChanged()
{
UpdateFeeds();
InvokeAsync(StateHasChanged);
}
//private HashSet<FeedItemData> _itemDatas = new HashSet<FeedItemData>();
//private TreeItemData? _treeItemData;
private void UpdateFeeds()
{
/*if (_stateContainer.TreeItem == null) return;
_treeItemData = _stateContainer.TreeItem;
if (_treeItemData.Feed != null)
{
Feed feed = _treeItemData.Feed;
_itemDatas = feed.Items.Select(x => new FeedItemData(x) { Icon = _treeItemData.Icon, FaviconUrl = _treeItemData.FaviconUrl, CategoryColorHex = _treeItemData.CategoryModel?.HexColor }).ToHashSet();
}
else if (_treeItemData.Feeds != null)
{
HashSet<FeedItemData> items = new HashSet<FeedItemData>();
foreach (var treeItem in _treeItemData.Feeds)
{
if (treeItem.Feed == null) continue;
items.UnionWith(treeItem.Feed.Items.Select(x => new FeedItemData(x) { Icon = treeItem.Icon, FaviconUrl = treeItem.FaviconUrl, CategoryColorHex = _treeItemData.CategoryModel?.HexColor }));
_itemDatas = items.OrderBy(x => x.FeedItem.PublishingDate).Reverse().ToHashSet();
}
}*/
}
} }

View File

@ -0,0 +1,72 @@
@page "/list"
@using WebSharpRSS.Models
@using SharpRss.Services
@inject IDialogService _dialogService;
@inject RssService _rssService;
<div>
@if (_isLoading)
{
<div class="justify-self: center">
<MudProgressCircular Color="Color.Primary" Indeterminate="true" />
<MudText>Loading...</MudText>
</div>
}
else
{
<FeedItemList Items="items"/>
}
</div>
@code {
[Parameter]
[SupplyParameterFromQuery(Name = "fid")]
public string? Fid
{
get => _fid;
set
{
_fid = value;
LoadItems();
}
}
private string? _fid;
[Parameter]
[SupplyParameterFromQuery(Name = "gid")]
public string? Gid
{
get => _gid;
set
{
_gid = value;
LoadItems();
}
}
private string? _gid;
HashSet<FeedItemData> items = new HashSet<FeedItemData>();
bool _isLoading = true;
private async void LoadItems()
{
_isLoading = true;
if (Fid != null)
{
var fItems = await _rssService.GetFeedItemsAsync(Fid);
items = fItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
_isLoading = false;
}
else if (Gid != null)
{
var feeds = await _rssService.GetFeedsAsync(Gid);
var feedids = feeds.Select(x => x.Id);
var feedItems = await _rssService.GetFeedItemsFromFeedsAsync(feedids.ToArray());
items = feedItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
}
_isLoading = false;
StateHasChanged();
}
protected override void OnInitialized()
{
LoadItems();
}
}

View File

@ -1,107 +1,9 @@
@page "/read" @page "/read"
@using WebSharpRSS.Models;
@using ToolQit.Extensions
@using Serilog
@using SharpRss.Models
@using SharpRss.Services @using SharpRss.Services
@inject RssService _rssService; @inject RssService _rssService;
<MudText Typo="Typo.h1">Nothing here yet!</MudText>
<MudStack Spacing="2" Class="ml-2 mr-2">
@if (isLoading)
{
<div class="justify-self: center">
<MudProgressCircular Color="Color.Primary" Indeterminate="true" />
<MudText>Loading...</MudText>
</div>
}
else if (faulted)
{
<MudAlert Severity="Severity.Error" Variant="Variant.Filled">Could not load feeds!</MudAlert>
}
else
{
foreach (var feedItemData in items)
{
<MudItem Style="backdrop-filter: blur(16px) saturate(180%);">
<MudCard Style=" background: rgba(0,0,0,0.5);">
<MudCardContent>
<div style="justify-self: start;" class="d-flex align-center">
@if (feedItemData.FaviconUrl != null)
{
<MudImage Src="@feedItemData.FaviconUrl" ObjectFit="ObjectFit.Contain" />
}
<div class="d-inline pa-2 align-center" style="font-size: 16px;">
@((MarkupString)feedItemData.Title)
</div>
@*<MudText Class="d-inline pa-2 align-center">@feedItemData.Title</MudText>*@
</div>
<div>
@((MarkupString)feedItemData.Description)
</div>
@*<MudText Typo="Typo.body2">@feedItemData.Description</MudText>*@
<MudText Typo="Typo.overline">@feedItemData.PublishingDate.ToString()</MudText>
</MudCardContent>
</MudCard>
</MudItem>
}
}
</MudStack>
@code { @code {
[Parameter]
[SupplyParameterFromQuery(Name = "fid")]
public string? Fid
{
get => _fid;
set
{
_fid = value;
LoadItems();
}
}
private string? _fid;
[Parameter]
[SupplyParameterFromQuery(Name = "gid")]
public string? Gid
{
get => _gid;
set
{
_gid = value;
LoadItems();
}
}
private string? _gid;
HashSet<FeedItemData> items = new HashSet<FeedItemData>();
bool isLoading = true;
bool faulted = false;
private async void LoadItems()
{
faulted = false;
isLoading = true;
if (Fid != null)
{
var fItems = await _rssService.GetFeedItemsAsync(Fid);
items = fItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
isLoading = false;
}
else if (Gid != null)
{
var feeds = await _rssService.GetFeedsAsync(Gid);
var feedids = feeds.Select(x => x.Id);
var feedItems = await _rssService.GetFeedItemsFromFeedsAsync(feedids.ToArray());
items = feedItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
}
else
{
faulted = true;
}
isLoading = false;
StateHasChanged();
}
protected override void OnInitialized()
{
LoadItems();
}
} }

View File

@ -0,0 +1,60 @@
@using WebSharpRSS.Models
@using Serilog
@using ToolQit.Extensions
@inject IDialogService _dialogService
<MudStack Spacing="2" Class="ma-2">
@if (Items != null)
{
foreach (var feedItemData in Items)
{
<MudItem @onclick="@(() => Callback(feedItemData))">
<MudPaper Height="250" Width="300" Class="px-2">
<div style="justify-self: start;" class="d-flex align-center">
@if (feedItemData.FaviconUrl != null)
{
<MudImage Src="@feedItemData.FaviconUrl" ObjectFit="ObjectFit.Contain"/>
}
<div class="d-inline pa-2 align-center" style="font-size: 16px;">
@if (feedItemData.Title != null)
{
@((MarkupString)feedItemData.Title)
}
</div>
</div>
<div>
@if (feedItemData.Description != null && !feedItemData.Description.IsNullEmptyWhiteSpace())
{
@((MarkupString)feedItemData.Description)
}
else
{
<MudText Color="Color.Dark" Typo="Typo.body2">No description found!</MudText>
}
</div>
<MudText Typo="Typo.overline">@feedItemData.PublishingDate.ToString()</MudText>
</MudPaper>
</MudItem>
}
}
else
{
<MudAlert Severity="Severity.Info" Variant="Variant.Filled">No items to load!</MudAlert>
}
</MudStack>
@code {
[Parameter]
public HashSet<FeedItemData>? Items { get; set; }
DialogOptions _dialogOptions = new DialogOptions() { FullWidth = true, MaxWidth = MaxWidth.ExtraLarge, NoHeader = true, CloseButton = true, CloseOnEscapeKey = true };
private void Callback(FeedItemData feedItem)
{
var parameters = new DialogParameters();
parameters.Add("Data", feedItem);
_dialogService.Show<ReadDialog>("", parameters, _dialogOptions);
Log.Verbose("Item: {ItemId} clicked", feedItem.Id);
}
}

View File

@ -0,0 +1,29 @@
@using WebSharpRSS.Models
@using ToolQit.Extensions
@if (FeedItem != null)
{
<div style="justify-self: start;" class="d-flex align-center">
@if (FeedItem.FaviconUrl != null)
{
<MudImage Src="@FeedItem.FaviconUrl" ObjectFit="ObjectFit.Contain"/>
}
<div class="d-inline px-3 align-center" style="font-size: 30px;">
@((MarkupString)(FeedItem?.Title ?? "This item doesn't contains a title!"))
</div>
</div>
<MudDivider DividerType="DividerType.FullWidth" Light="false" Class="my-2"/>
<div>
@((MarkupString)((FeedItem?.Content == null || FeedItem.Content.IsNullEmptyWhiteSpace() ? FeedItem?.Description : FeedItem.Content) ?? "This item doesn't contain any content!"))
</div>
}
else
{
<MudAlert Severity="Severity.Error" Variant="Variant.Filled">Could not load data!</MudAlert>
}
@code {
[Parameter]
public FeedItemData? FeedItem { get; set; }
}

View File

@ -0,0 +1,13 @@
@using WebSharpRSS.Models
<MudDialog>
<DialogContent>
<ItemView FeedItem="Data"/>
</DialogContent>
</MudDialog>
@code {
[Parameter]
public FeedItemData? Data { get; set; }
}

View File

@ -7,10 +7,10 @@
@using ToolQit.Extensions; @using ToolQit.Extensions;
@inject RssService _rssService @inject RssService _rssService
@inject NavigationManager Navigation @inject NavigationManager _navigation
<MudStack Spacing="2"> <MudStack Spacing="2">
<MudTreeView Items="_guideItems" @bind-SelectedValue="SelectedItem" Hover="true"> <MudTreeView Color="Color.Success" Items="_guideItems" @bind-SelectedValue="SelectedItem" Hover="true">
<ItemTemplate> <ItemTemplate>
<MudTreeViewItem @bind-Expanded="@context.IsExpanded" Value="@context" Items="@context.Children" CanExpand="@context.HasChild" @onclick="ItemClicked"> <MudTreeViewItem @bind-Expanded="@context.IsExpanded" Value="@context" Items="@context.Children" CanExpand="@context.HasChild" @onclick="ItemClicked">
<Content> <Content>
@ -19,7 +19,7 @@
<MudTreeViewItemToggleButton ExpandedChanged="@(() => ExpandedChanged(context))" Loading="@context.Loading" Visible="@context.HasChild" LoadingIconColor="Color.Info" /> <MudTreeViewItemToggleButton ExpandedChanged="@(() => ExpandedChanged(context))" Loading="@context.Loading" Visible="@context.HasChild" LoadingIconColor="Color.Info" />
@if (context.FaviconUrl == null && context.Icon != null) @if (context.FaviconUrl == null && context.Icon != null)
{ {
<MudIcon Icon="@context.Icon" Style="@($"color:{context.GroupModel?.HexColor ?? Theme.Palette.Primary.Value}")"/> <MudIcon Icon="@context.Icon" Style="@($"color:{context.GroupModel?.HexColor ?? _theme.Palette.Primary.Value}")"/>
} }
else else
{ {
@ -27,9 +27,6 @@
} }
<MudText Class="ml-2">@context.Title</MudText> <MudText Class="ml-2">@context.Title</MudText>
</div> </div>
<div style="justify-self: end;">
@*<MudText Color="Color.Dark" Style="justify-self: end;" Typo="Typo.caption">@context.FeeditemCount</MudText>*@
</div>
</div> </div>
</Content> </Content>
</MudTreeViewItem> </MudTreeViewItem>
@ -38,7 +35,7 @@
</MudStack> </MudStack>
@code { @code {
private MudTheme Theme = new MudTheme(); private MudTheme _theme = new MudTheme();
private readonly HashSet<TreeItemData> _guideItems = new HashSet<TreeItemData>(); private readonly HashSet<TreeItemData> _guideItems = new HashSet<TreeItemData>();
private TreeItemData? _selectedItem; private TreeItemData? _selectedItem;
private TreeItemData? SelectedItem private TreeItemData? SelectedItem
@ -55,11 +52,11 @@
if (_selectedItem == null) return; if (_selectedItem == null) return;
if (_selectedItem.FeedModel != null) if (_selectedItem.FeedModel != null)
{ {
Navigation.NavigateTo($"/read?fid={_selectedItem.FeedModel.Id}"); _navigation.NavigateTo($"/list?fid={_selectedItem.FeedModel.Id}");
} }
else if (_selectedItem.GroupModel != null) else if (_selectedItem.GroupModel != null)
{ {
Navigation.NavigateTo($"/read?gid={_selectedItem.GroupModel.Id}"); _navigation.NavigateTo($"/list?gid={_selectedItem.GroupModel.Id}");
} }
} }
private async void ExpandedChanged(TreeItemData treeItemData) private async void ExpandedChanged(TreeItemData treeItemData)