Skip to content

Commit

Permalink
Add Razor SSG Blogs, Videos and Pages features
Browse files Browse the repository at this point in the history
  • Loading branch information
mythz committed Oct 28, 2023
1 parent 58e314a commit 2e5e56d
Show file tree
Hide file tree
Showing 73 changed files with 7,045 additions and 288 deletions.
10 changes: 7 additions & 3 deletions MyApp/Components/App.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<link rel="stylesheet" href="css/app.css" />
<link href="css/typography.css" rel="stylesheet">
<link href="css/markdown.css" rel="stylesheet">
<link rel="icon" href="/img/logo.svg" type="image/svg+xml">
<link rel="stylesheet" href="css/app.css" />
<link rel="stylesheet" href="css/typography.css">
<link rel="stylesheet" href="css/highlight.css">
<link rel="stylesheet" href="css/lite-yt-embed.css">
<link rel="stylesheet" href="MyApp.styles.css" />
@BlazorHtml.ImportMap(new()
{
Expand All @@ -26,6 +27,9 @@
<script src="_framework/blazor.web.js"></script>
<script src="js/servicestack-blazor.js"></script>
<script>JS.init()</script>
<script src="lib/js/lite-yt-embed.js"></script>
<script src="lib/js/highlight.js"></script>
<script>hljs.highlightAll()</script>
</body>

</html>
2 changes: 1 addition & 1 deletion MyApp/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ loadMetadata({
<Header />

<div class="min-h-screen">
<main role="main" class="pb-16">
<main role="main">
@Body
</main>
</div>
Expand Down
190 changes: 190 additions & 0 deletions MyApp/Components/Pages/Blog.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
@page "/blog"
@inject MarkdownBlog Posts

<PageTitle>MyApp Blog</PageTitle>

<div class="container mx-auto px-5 mt-24 mb-24">
@if (primaryPost != null)
{
var authorHref = Posts.GetAuthorLink(primaryPost.Author);
<section>
<div class="mb-8 md:mb-16">
<div class="sm:mx-0">
<a aria-label="@primaryPost.Title" href="@Posts.GetPostLink(primaryPost)">
<img src="@primaryPost.Image" alt="Cover Image for @primaryPost.Title" class="shadow-sm hover:shadow-2xl transition-shadow duration-200">
</a>
</div>
</div>
<div class="md:grid md:grid-cols-2 md:gap-x-16 lg:gap-x-8 mb-20 md:mb-28">
<div>
<h3 class="mb-4 text-4xl lg:text-6xl leading-tight">
<a class="hover:underline" href="@Posts.GetPostLink(primaryPost)">@primaryPost.Title</a>
</h3>
<div class="mb-4 md:mb-0 text-lg">
<time datetime="@Posts.GetDateTimestamp(primaryPost.Date)">@Posts.GetDateLabel(primaryPost.Date)</time>
</div>
</div>
<div>
<p class="text-lg leading-relaxed mb-4">@primaryPost.Summary</p>
@if (authorHref != null)
{
<a class="flex items-center text-xl font-bold" href="@authorHref">
<img src="@Posts.GetAuthorProfileUrl(primaryPost.Author)" class="w-12 h-12 rounded-full mr-4" alt="Author">
<span>@primaryPost.Author</span>
</a>
}
else
{
<span class="flex items-center text-xl font-bold">
<img src="@Posts.GetAuthorProfileUrl(primaryPost.Author)" class="w-12 h-12 rounded-full mr-4" alt="Author">
<span>@primaryPost.Author</span>
</span>
}
</div>
</div>
</section>
}

@if (gridPosts.Count > 0)
{
<section>
<h2 class="mb-8 text-6xl md:text-7xl font-bold tracking-tighter leading-tight">More from the blog</h2>
<div class="mx-auto mt-12 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3">
@foreach (var post in gridPosts)
{
var authorHref = Posts.GetAuthorLink(post.Author);
<div class="flex flex-col overflow-hidden rounded-lg shadow-lg">
<div class="flex-shrink-0">
<a href="@Posts.GetPostLink(post)">
<img class="h-48 w-full object-cover" src="@Posts.GetSplashImage(post)" alt="">
</a>
</div>
<div class="flex flex-1 flex-col justify-between bg-white dark:bg-black p-6">
<div class="flex-1">
<p class="text-sm font-medium text-indigo-600 dark:text-indigo-300">
Article
</p>
<a href="@Posts.GetPostLink(post)" class="mt-2 block">
<p class="text-xl font-semibold text-gray-900 dark:text-gray-50">@post.Title</p>
<p class="mt-3 text-base text-gray-500">@post.Summary</p>
</a>
</div>
<div class="mt-6 flex items-center">
<div class="flex-shrink-0">
<span>
<span class="sr-only">@post.Author</span>
<img class="h-10 w-10 rounded-full" src="@Posts.GetAuthorProfileUrl(post.Author)" alt="@post.Title background">
</span>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">
@if (authorHref != null)
{
<a href="@Posts.GetAuthorLink(post.Author!)" class="hover:underline">@post.Author</a>
}
else
{
<span>@post.Author</span>
}
</p>
<div class="flex space-x-1 text-sm text-gray-500">
<time datetime="@Posts.GetDateTimestamp(post.Date)">@Posts.GetDateLabel(post.Date)</time>
<span aria-hidden="true">&middot;</span>
<span>@Posts.MinutesToRead(post.WordCount) min read</span>
</div>
</div>
</div>
</div>
</div>
}
</div>
</section>
}

@if (remainingPosts.Count > 0)
{
<section class="mt-24 flex justify-center">
<div class="flex max-w-screen-lg">
<div class="w-2/3">
@foreach (var post in remainingPosts)
{
var authorHref = Posts.GetAuthorLink(post.Author);
<div class="border-b pb-4 mb-4">
<div class="flex justify-between">
<div class="w-3/4">
<a href="@Posts.GetPostLink(post)" class="mt-2 block">
<p class="text-xl font-semibold text-gray-900 dark:text-gray-50">@post.Title</p>
<p class="mt-3 text-base text-gray-500">@post.Summary</p>
</a>
<div class="mt-6 flex items-center">
<div class="flex-shrink-0">
<span>
<span class="sr-only">@post.Author</span>
<img class="h-10 w-10 rounded-full" src="@Posts.GetAuthorProfileUrl(post.Author)" alt="@post.Title background">
</span>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">
@if (authorHref != null)
{
<a href="@Posts.GetAuthorLink(post.Author!)" class="hover:underline">@post.Author</a>
}
else
{
<span>@post.Author</span>
}
</p>
<div class="flex space-x-1 text-sm text-gray-500">
<time datetime="@Posts.GetDateTimestamp(post.Date)">@Posts.GetDateLabel(post.Date)</time>
<span aria-hidden="true">&middot;</span>
<span>@Posts.MinutesToRead(post.WordCount) min read</span>
</div>
</div>
</div>
</div>
<div class="w-1/4">
<a href="@Posts.GetPostLink(post)" class="pt-4">
<img class="w-full object-cover max-h-[130px]" src="@Posts.GetSplashImage(post)" alt="">
</a>
</div>
</div>
</div>
}
</div>
<div class="w-1/3">
<div class="pl-8">
<div class="flex items-center">
<img class="w-8 h-8 mr-1" src="img/logo.svg" alt="MyApp logo">
<span class="hidden sm:block text-lg font-semibold">MyApp</span>
</div>
<div class="p-2">
<p class="text-gray-500">Im Spencer Sharp. I live in New York City, where I design the future.</p>
<a href="about" class="text-sm font-medium text-gray-900 hover:underline">more information</a>
</div>
<div class="p-4">
<FollowLinks />
</div>
</div>
</div>
</div>
</section>
}
</div>

@code {
List<MarkdownFileInfo> posts = new();
MarkdownFileInfo? primaryPost;
List<MarkdownFileInfo> gridPosts = new();
List<MarkdownFileInfo> remainingPosts = new();

void load() {
posts = Posts.GetPosts();
primaryPost = posts.FirstOrDefault();
gridPosts = posts.Skip(1).Take(6).ToList();
remainingPosts = posts.Skip(7).Take(15).ToList();
}

protected override void OnInitialized() => load();

protected override void OnParametersSet() => load();
}
20 changes: 10 additions & 10 deletions MyApp/Components/Pages/Counter.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

<PageTitle>Counter</PageTitle>

<h1 class="@Css.H1">Counter</h1>
<div class="mt-8 mb-20 mx-auto max-w-fit">
<h1 class="@Css.H1">Counter</h1>

<p class="my-4">Current count: @currentCount</p>
<div data-component="Pages/Counter.mjs"></div>

<button class="@Css.PrimaryButton" @onclick="IncrementCount">Click me</button>
<div>
<div class="mt-8 flex justify-center gap-x-4">
<SrcRazorPage Path="Counter.razor" />
<SrcVuePage Path="Counter.mjs" />
</div>
</div>

@code {
private int currentCount = 0;
</div>

private void IncrementCount()
{
currentCount++;
}
}
62 changes: 39 additions & 23 deletions MyApp/Components/Pages/Docs.razor
Original file line number Diff line number Diff line change
@@ -1,41 +1,57 @@
@page "/docs/{path?}"
@page "/{Slug?}"
@inherits AppComponentBase

@inject MarkdownPages Markdown
@inject AppConfig AppConfig
@using Markdig
@using Markdig.Syntax

<link href="css/typography.css" rel="stylesheet" />
<link href="css/markdown.css" rel="stylesheet" />

<div class="mt-3 mb-20 mx-auto max-w-fit">
@if (render.Response?.Preview != null)
@if (doc != null)
{
<div class="prose dark:prose-invert lg:prose-xl min-vh-100 m-3" data-md=@Path>
<div class="markdown-body">
@((MarkupString)render.Response!.Preview)
<PageTitle>@doc.Title</PageTitle>

<section class="flex-col md:flex-row flex justify-center mt-16 mb-16 md:mb-12">
<h1 class="text-4xl tracking-tight font-extrabold text-gray-900 dark:text-gray-50 sm:text-5xl md:text-6xl">
@doc.Title
</h1>
</section>
<div class="mx-auto">
<div class="mx-auto prose lg:prose-xl mb-24">
@((MarkupString)doc.Preview!)
</div>
</div>
}
else if (render.Error == null)
else
{
<Loading />
<div class="mt-3 mb-20 mx-auto max-w-fit">
@if (error != null)
{
<ErrorSummary Status=@error />
}
else
{
<Loading />
}
</div>
}

<ErrorSummary Status=@render.Error />

</div>

@code {
[Parameter]
public string? Path { get; set; }
public required string Slug { get; set; }

ApiResult<MarkdownFileInfo> render { get; set; } = new();
MarkdownFileInfo? doc;
ResponseStatus? error;

async Task loadDoc() =>
render = await MarkdownUtils.LoadDocumentAsync(Path!, doc =>
HostContext.VirtualFileSources.AssertFile($"/content/{doc.FileName}").ReadAllTextAsync());
void load()
{
doc = Markdown.GetBySlug(Slug);
if (doc == null)
{
error = new() { Message = $"_pages/{Slug}.md was not found" };
return;
}
}

protected override async Task OnInitializedAsync() => await loadDoc();
protected override void OnInitialized() => load();

protected override async Task OnParametersSetAsync() => await loadDoc();
protected override void OnParametersSet() => load();
}
17 changes: 16 additions & 1 deletion MyApp/Components/Pages/Home.razor
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,22 @@
Getting Started
</h2>
<div>
<div data-component="GettingStarted"></div>
<div data-component="GettingStarted" data-props="{template:'blazor-vue'}"></div>
</div>
</div>
</section>

<div class="flex justify-center my-20 py-20 bg-slate-100 dark:bg-slate-800">
<div class="text-center">
<svg class="text-indigo-600 w-36 h-36 inline-block" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="m18 16l-4-3.2V16H6V8h8v3.2L18 8m2-4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2Z" /></svg>
<h1 class="text-6xl md:text-7xl lg:text-8xl font-bold tracking-tighter leading-tight md:leading-none mb-12 text-center md:text-left">
Videos
</h1>
</div>
</div>

<VideoGroup
Title="Blazor Templates and Components"
Summary="Use ServiceStack.Blazor Templates and Components to rapidly develop Blazor Web Apps"
Group="blazor"
LearnMore="https://servicestack.net/blazor" />
19 changes: 4 additions & 15 deletions MyApp/Components/Pages/Secure/Bookings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,6 @@
<a href="/ui/QueryBookings" data-enhance-nav="false" class="font-semibold text-indigo-600 dark:text-indigo-300 hover:text-indigo-500">API Explorer</a>
</h4>

<div class="mt-20 mx-auto text-gray-500 max-w-screen-lg">
<h2 class="mt-4 text-3xl sm:text-4xl text-slate-900 font-extrabold tracking-tight dark:text-slate-50">
Instantly Manage your data using AutoQueryGrid Vue
</h2>
<p class="my-3 mx-auto text-base text-gray-500 sm:text-lg md:mt-5 md:text-xl">
This walkthrough explores the ServiceStack Vue 3 library and the functionality of the AutoQueryGrid component.
The AutoQueryGrid component simplifies the integration of AutoQuery services by generating a customizable UI.
</p>
<iframe class="mt-4 w-full aspect-video" src="https://www.youtube.com/embed/znCoC-Ct0Ps" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</div>

<div class="mt-20 mx-auto text-gray-500 max-w-screen-lg">
<h2 class="mt-4 text-3xl sm:text-4xl text-slate-900 font-extrabold tracking-tight dark:text-slate-50">
Create a multi-user Booking system in minutes
Expand All @@ -53,13 +42,13 @@

<div class="mt-20 mx-auto text-gray-500 max-w-screen-lg">
<h2 class="mt-4 text-3xl sm:text-4xl text-slate-900 font-extrabold tracking-tight dark:text-slate-50">
Vue 3 Tailwind Components Library
Instantly Manage your data using AutoQueryGrid Vue
</h2>
<p class="my-3 mx-auto text-base text-gray-500 sm:text-lg md:mt-5 md:text-xl">
In this video, we demonstrate using the @@servicestack/vue components library for Vue.js 3
Multipage Apps (MPAs) along with the <b>vue-mjs</b> template.
This walkthrough explores the ServiceStack Vue 3 library and the functionality of the AutoQueryGrid component.
The AutoQueryGrid component simplifies the integration of AutoQuery services by generating a customizable UI.
</p>
<iframe class="mt-4 w-full aspect-video" src="https://www.youtube.com/embed/YIa0w6whe2U" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<iframe class="mt-4 w-full aspect-video" src="https://www.youtube.com/embed/znCoC-Ct0Ps" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</div>

</div>
Expand Down
Loading

0 comments on commit 2e5e56d

Please sign in to comment.