diff --git a/src/TerribleDev.Blog.Web/Controllers/HomeController.cs b/src/TerribleDev.Blog.Web/Controllers/HomeController.cs index 51d3c96..45b54e8 100644 --- a/src/TerribleDev.Blog.Web/Controllers/HomeController.cs +++ b/src/TerribleDev.Blog.Web/Controllers/HomeController.cs @@ -65,12 +65,17 @@ namespace TerribleDev.Blog.Web.Controllers { return Redirect($"/404/?from=/{postUrl}/{amp}/"); } - if(!postCache.UrlToPost.TryGetValue(postUrl, out var currentPost)) + if(postCache.UrlToPost.TryGetValue(postUrl, out var currentPost)) { - this.StatusCode(404); - return View(nameof(FourOhFour)); + return View("Post", model: new PostViewModel() { Post = currentPost, IsAmp = amp == "amp" }); } - return View("Post", model: new PostViewModel() { Post = currentPost, IsAmp = amp == "amp" }); + if(postCache.LandingPagesUrl.TryGetValue(postUrl, out var landingPage)) + { + return View("Post", model: new PostViewModel() { Post = landingPage, IsAmp = amp == "amp" }); + } + + this.StatusCode(404); + return View(nameof(FourOhFour)); } [Route("/Error")] diff --git a/src/TerribleDev.Blog.Web/Extensions/IPostExtensions.cs b/src/TerribleDev.Blog.Web/Extensions/IPostExtensions.cs index d4cbc8c..86d1763 100644 --- a/src/TerribleDev.Blog.Web/Extensions/IPostExtensions.cs +++ b/src/TerribleDev.Blog.Web/Extensions/IPostExtensions.cs @@ -9,7 +9,7 @@ namespace TerribleDev.Blog.Web { public static class IPostExtensions { - public static SyndicationItem ToSyndicationItem(this IPost x) + public static SyndicationItem ToSyndicationItem(this Post x) { Uri.TryCreate(x.CanonicalUrl, UriKind.Absolute, out var url); var syn = new SyndicationItem() @@ -22,7 +22,7 @@ namespace TerribleDev.Blog.Web syn.AddLink(new SyndicationLink(url)); return syn; } - public static ISet ToNormalizedTagList(this IPost x) + public static ISet ToNormalizedTagList(this Post x) { if(x.tags == null) { diff --git a/src/TerribleDev.Blog.Web/Factories/BlogCacheFactory.cs b/src/TerribleDev.Blog.Web/Factories/BlogCacheFactory.cs index 488d4ea..7602ff2 100644 --- a/src/TerribleDev.Blog.Web/Factories/BlogCacheFactory.cs +++ b/src/TerribleDev.Blog.Web/Factories/BlogCacheFactory.cs @@ -11,73 +11,84 @@ namespace TerribleDev.Blog.Web.Factories { public static class BlogCacheFactory { - + public static PostCache ProjectPostCache(IEnumerable rawPosts) { var orderedPosts = rawPosts.OrderByDescending(a => a.PublishDate); var posts = new List(orderedPosts); var urlToPosts = new Dictionary(); - var tagsToPost = new Dictionary>(); - var postsByPage = new Dictionary>(); + var tagsToPost = new Dictionary>(); + var postsByPage = new Dictionary>(); var syndicationPosts = new List(); - + var landingPagesUrl = new Dictionary(); var blogPostsLD = new List(); - foreach(var post in orderedPosts) + foreach (var post in orderedPosts) { - urlToPosts.Add(post.UrlWithoutPath, post); - syndicationPosts.Add(post.ToSyndicationItem()); - blogPostsLD.Add(post.Content.Value.JsonLD); - foreach(var tag in post.ToNormalizedTagList()) + + if (post is Post) { - if(tagsToPost.TryGetValue(tag, out var list)) + var castedPost = post as Post; + urlToPosts.Add(post.UrlWithoutPath, castedPost); + syndicationPosts.Add(castedPost.ToSyndicationItem()); + blogPostsLD.Add(post.Content.Value.JsonLD); + foreach (var tag in castedPost.ToNormalizedTagList()) { - list.Add(post); + if (tagsToPost.TryGetValue(tag, out var list)) + { + list.Add(castedPost); + } + else + { + tagsToPost.Add(tag, new List() { castedPost }); + } + } + if (postsByPage.Keys.Count < 1) + { + postsByPage.Add(1, new List() { castedPost }); } else { - tagsToPost.Add(tag, new List() { post }); + var highestPageKey = postsByPage.Keys.Max(); + var highestPage = postsByPage[highestPageKey]; + if (highestPage.Count < 10) + { + highestPage.Add(castedPost); + + } + else + { + postsByPage.Add(highestPageKey + 1, new List() { castedPost }); + } } + } - if(postsByPage.Keys.Count < 1) + if (post is LandingPage) { - postsByPage.Add(1, new List() { post }); - } - else - { - var highestPageKey = postsByPage.Keys.Max(); - var highestPage = postsByPage[highestPageKey]; - if(highestPage.Count < 10) - { - highestPage.Add(post); - - } - else - { - postsByPage.Add(highestPageKey + 1, new List() { post }); - } + var castedPost = post as LandingPage; + landingPagesUrl.Add(castedPost.UrlWithoutPath, castedPost); } } - var ld = new Schema.NET.Blog() - { - Name = "TerribleDev Blog", - Description = "The blog of Tommy Parnell", - Author = new Schema.NET.Person() { Name = "TerribleDev" }, - Image = new Schema.NET.ImageObject() { Url = new Schema.NET.OneOrMany(new Uri("https://blog.terrible.dev/content/tommyAvatar4.jpg")) }, - Url = new Schema.NET.OneOrMany(new Uri("https://blog.terrible.dev/" )), - SameAs = new Schema.NET.OneOrMany(new Uri("https://twitter.com/terribledev")), - BlogPost = new Schema.NET.OneOrMany(blogPostsLD), - }; + var ld = new Schema.NET.Blog() + { + Name = "TerribleDev Blog", + Description = "The blog of Tommy Parnell", + Author = new Schema.NET.Person() { Name = "TerribleDev" }, + Image = new Schema.NET.ImageObject() { Url = new Schema.NET.OneOrMany(new Uri("https://blog.terrible.dev/content/tommyAvatar4.jpg")) }, + Url = new Schema.NET.OneOrMany(new Uri("https://blog.terrible.dev/")), + SameAs = new Schema.NET.OneOrMany(new Uri("https://twitter.com/terribledev")), + BlogPost = new Schema.NET.OneOrMany(blogPostsLD), + }; var website = new Schema.NET.WebSite() { Name = "TerribleDev Blog", Description = "The blog of Tommy Parnell", Author = new Schema.NET.Person() { Name = "TerribleDev" }, Image = new Schema.NET.ImageObject() { Url = new Schema.NET.OneOrMany(new Uri("https://blog.terrible.dev/content/tommyAvatar4.jpg")) }, - Url = new Schema.NET.OneOrMany(new Uri("https://blog.terrible.dev/" )), + Url = new Schema.NET.OneOrMany(new Uri("https://blog.terrible.dev/")), SameAs = new Schema.NET.OneOrMany(new Uri("https://twitter.com/terribledev")), PotentialAction = new Schema.NET.OneOrMany( // search action - new List() + new List() { new Schema.NET.SearchAction() { @@ -95,13 +106,14 @@ namespace TerribleDev.Blog.Web.Factories ValueMaxLength = 500, } ) - ) + ) } } ) }; return new PostCache() { + LandingPagesUrl = landingPagesUrl, PostsAsLists = posts, TagsToPosts = tagsToPost, UrlToPost = urlToPosts, diff --git a/src/TerribleDev.Blog.Web/Factories/BlogFactory.cs b/src/TerribleDev.Blog.Web/Factories/BlogFactory.cs index 7ab33ca..50247f2 100644 --- a/src/TerribleDev.Blog.Web/Factories/BlogFactory.cs +++ b/src/TerribleDev.Blog.Web/Factories/BlogFactory.cs @@ -71,6 +71,11 @@ namespace TerribleDev.Blog.Web var resolvedUrl = !string.IsNullOrWhiteSpace(postSettings.permalink) ? postSettings.permalink : fileName.Split('.')[0].Replace(' ', '-').WithoutSpecialCharacters(); var canonicalUrl = $"https://blog.terrible.dev/{resolvedUrl}/"; var ampUrl = $"https://blog.terrible.dev/{resolvedUrl}/amp/"; + return postSettings.isLanding ? BuildLandingPage(fileName, domain, markdownText, postSettings, resolvedUrl, canonicalUrl, ampUrl) : BuildPost(fileName, domain, markdownText, postSettings, resolvedUrl, canonicalUrl, ampUrl); + } + + private Post BuildPost(string fileName, string domain, string markdownText, PostSettings postSettings, string resolvedUrl, string canonicalUrl, string ampUrl) + { return new Post() { PublishDate = postSettings.date.ToUniversalTime(), @@ -81,6 +86,7 @@ namespace TerribleDev.Blog.Web CanonicalUrl = canonicalUrl, AMPUrl = ampUrl, UrlWithoutPath = resolvedUrl, + isLanding = postSettings.isLanding, Content = new Lazy(() => { (string postContent, string postContentPlain, string summary, string postSummaryPlain, IList postImages) = ResolveContentForPost(markdownText, fileName, resolvedUrl, domain); @@ -129,5 +135,53 @@ namespace TerribleDev.Blog.Web }), }; } + private LandingPage BuildLandingPage(string fileName, string domain, string markdownText, PostSettings postSettings, string resolvedUrl, string canonicalUrl, string ampUrl) + { + return new LandingPage() + { + PublishDate = postSettings.date.ToUniversalTime(), + UpdatedDate = postSettings.updated?.ToUniversalTime() ?? null, + Title = postSettings.title, + RelativeUrl = $"/{resolvedUrl}/", + CanonicalUrl = canonicalUrl, + AMPUrl = ampUrl, + UrlWithoutPath = resolvedUrl, + isLanding = postSettings.isLanding, + Content = new Lazy(() => + { + (string postContent, string postContentPlain, string summary, string postSummaryPlain, IList postImages) = ResolveContentForPost(markdownText, fileName, resolvedUrl, domain); + var breadcrumb = new Schema.NET.BreadcrumbList() + { + ItemListElement = new List() // Required + { + new ListItem() // Required + { + Position = 1, // Required + Url = new Uri("https://blog.terrible.dev/") // Required + }, + new ListItem() + { + Position = 2, + Name = postSettings.title, + }, + }, + }; + // regex remove picture and source tags but not the child elements + var postContentClean = Regex.Replace(postContent, "|||", "", RegexOptions.Singleline); + return new PostContent() + { + AmpContent = new HtmlString(postContentClean), + Content = new HtmlString(postContent), + Images = postImages, + ContentPlain = postContentPlain, + Summary = new HtmlString(summary), + SummaryPlain = postSummaryPlain, + SummaryPlainShort = (postContentPlain.Length <= 147 ? postContentPlain : postContentPlain.Substring(0, 146)) + "...", + JsonLDBreadcrumb = breadcrumb, + JsonLDBreadcrumbString = breadcrumb.ToHtmlEscapedString().Replace("https://schema.org", "https://schema.org/true"), + }; + }), + }; + } } } diff --git a/src/TerribleDev.Blog.Web/Models/IPost.cs b/src/TerribleDev.Blog.Web/Models/IPost.cs index 1d6752b..1f7e0ac 100644 --- a/src/TerribleDev.Blog.Web/Models/IPost.cs +++ b/src/TerribleDev.Blog.Web/Models/IPost.cs @@ -16,8 +16,8 @@ namespace TerribleDev.Blog.Web.Models string Title { get; set; } DateTime PublishDate { get; set; } DateTime? UpdatedDate { get; set; } - IList tags { get; set; } Lazy Content { get; set; } + bool isLanding { get; set; } } } diff --git a/src/TerribleDev.Blog.Web/Models/IPostSettings.cs b/src/TerribleDev.Blog.Web/Models/IPostSettings.cs index ab26f6a..bcdb2f4 100644 --- a/src/TerribleDev.Blog.Web/Models/IPostSettings.cs +++ b/src/TerribleDev.Blog.Web/Models/IPostSettings.cs @@ -12,5 +12,6 @@ namespace TerribleDev.Blog.Web.Models string thumbnailImage { get; set; } DateTimeOffset date { get; set; } DateTimeOffset updated { get; set; } + bool isLanding { get; set; } } } diff --git a/src/TerribleDev.Blog.Web/Models/LandingPage.cs b/src/TerribleDev.Blog.Web/Models/LandingPage.cs new file mode 100644 index 0000000..0486d51 --- /dev/null +++ b/src/TerribleDev.Blog.Web/Models/LandingPage.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Html; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace TerribleDev.Blog.Web.Models +{ + [DebuggerDisplay("{Title}")] + public class LandingPage : IPost + { + public string AMPUrl { get; set; } + public string CanonicalUrl { get; set; } + public string UrlWithoutPath { get; set; } + public string RelativeUrl { get; set; } + public string Title { get; set; } + public DateTime PublishDate { get; set; } + public DateTime? UpdatedDate { get; set; } + public Lazy Content { get; set; } + + public bool isLanding { get; set; } = false; + } +} diff --git a/src/TerribleDev.Blog.Web/Models/Post.cs b/src/TerribleDev.Blog.Web/Models/Post.cs index c26a451..9fabe0e 100644 --- a/src/TerribleDev.Blog.Web/Models/Post.cs +++ b/src/TerribleDev.Blog.Web/Models/Post.cs @@ -18,5 +18,7 @@ namespace TerribleDev.Blog.Web.Models public DateTime? UpdatedDate { get; set; } public IList tags { get; set; } public Lazy Content { get; set; } + + public bool isLanding { get; set; } = false; } } diff --git a/src/TerribleDev.Blog.Web/Models/PostCache.cs b/src/TerribleDev.Blog.Web/Models/PostCache.cs index 72d4261..7fa647f 100644 --- a/src/TerribleDev.Blog.Web/Models/PostCache.cs +++ b/src/TerribleDev.Blog.Web/Models/PostCache.cs @@ -6,15 +6,17 @@ namespace TerribleDev.Blog.Web.Models public class PostCache { public IList PostsAsLists { get; set;} - public IDictionary> TagsToPosts { get; set; } + public IDictionary> TagsToPosts { get; set; } public IDictionary UrlToPost { get; set; } - public IDictionary> PostsByPage { get; set; } + public IDictionary> PostsByPage { get; set; } public IList PostsAsSyndication { get; set; } public Schema.NET.Blog BlogLD { get; set; } public Schema.NET.WebSite SiteLD { get; set; } public string BlogLDString { get; set; } public string SiteLDString { get; set; } + + public Dictionary LandingPagesUrl { get; set; } } } \ No newline at end of file diff --git a/src/TerribleDev.Blog.Web/Models/PostSettings.cs b/src/TerribleDev.Blog.Web/Models/PostSettings.cs index d7cfe2a..6c0756b 100644 --- a/src/TerribleDev.Blog.Web/Models/PostSettings.cs +++ b/src/TerribleDev.Blog.Web/Models/PostSettings.cs @@ -15,5 +15,7 @@ namespace TerribleDev.Blog.Web.Models public string thumbnailImage { get; set; } public string thumbnail_image_position { get; set; } public string layout { get; set; } + + public bool isLanding { get; set; } = false; } } diff --git a/src/TerribleDev.Blog.Web/Posts/Must-Have-Tool-NDepend.md b/src/TerribleDev.Blog.Web/Posts/Must-Have-Tool-NDepend.md index 299be5c..f7e491b 100644 --- a/src/TerribleDev.Blog.Web/Posts/Must-Have-Tool-NDepend.md +++ b/src/TerribleDev.Blog.Web/Posts/Must-Have-Tool-NDepend.md @@ -80,7 +80,7 @@ So the major feature I was blown away by with NDepend was how clean, and organiz The code quality rules, uses the NDepends querying engine to get your code. When you click on a rule the Linq query used will be displayed in a separate window. You can use this window to create your own rules, using the same querying engine. The following is a query to find code that should not be declared public.
- //Avoid public methods not publicly visible
+ //Avoid public methods not publicly visible
 // Matched methods are declared public but are not publicly visible by assemblies consumers.
 // Their visibility level must be decreased.
 
diff --git a/src/TerribleDev.Blog.Web/Posts/Parsing-cli-arguments-in-dotnet-core-Console-App.md b/src/TerribleDev.Blog.Web/Posts/Parsing-cli-arguments-in-dotnet-core-Console-App.md
index a80b815..7b3efe3 100644
--- a/src/TerribleDev.Blog.Web/Posts/Parsing-cli-arguments-in-dotnet-core-Console-App.md
+++ b/src/TerribleDev.Blog.Web/Posts/Parsing-cli-arguments-in-dotnet-core-Console-App.md
@@ -339,4 +339,105 @@ Environment.Exit(result);
 
 Here is the full source as a [gist](https://gist.github.com/TerribleDev/06abb67350745a58f9fab080bee74be1#file-program-cs):
 
-
+```csharp
+        public static void Main(string[] args)
+        {
+            var app = new Microsoft.Extensions.CommandLineUtils.CommandLineApplication();
+            var catapult = app.Command("catapult", config => { 
+                config.OnExecute(()=>{
+                    config.ShowHelp(); //show help for catapult
+                    return 1; //return error since we didn't do anything
+                });
+                config.HelpOption("-? | -h | --help"); //show help on --help
+             });
+             catapult.Command("help", config => { 
+                 config.Description = "get help!";
+                 config.OnExecute(()=>{
+                    catapult.ShowHelp("catapult");
+                     return 1;
+                 });
+              });
+             catapult.Command("list", config => {
+                    config.Description = "list catapults";
+                    config.HelpOption("-? | -h | --help");
+                    config.OnExecute(()=>{ 
+
+                        Console.WriteLine("a");
+                        Console.WriteLine("b");
+                        return 0;
+                     });   
+                });
+            catapult.Command("add", config => {
+                    config.Description = "Add a catapult";
+                    config.HelpOption("-? | -h | --help");
+                    var arg = config.Argument("name", "name of the catapult", false);
+                    config.OnExecute(()=>{ 
+                        if(!string.IsNullOrWhiteSpace(arg.Value))
+                        {
+                            //add snowballs somehow
+                            Console.WriteLine($"added {arg.Value}");
+                            return 0;
+                        }
+                        return 1;
+                        
+                        
+                     });   
+                });
+            catapult.Command("fling", config =>{ 
+                config.Description = "fling snow";
+                config.HelpOption("-? | -h | --help");
+                var ball = config.Argument("snowballId", "snowball id", false);
+                var cata = config.Argument("catapultId", "id of catapult to use", false);
+                config.OnExecute(()=>{
+
+                    //actually do something
+                    Console.WriteLine($"threw snowball: {ball.Value} with {cata.Value}");
+                    return 0;
+                });
+             });
+            var snowball = app.Command("snowball", config => { 
+                    config.OnExecute(()=>{
+                    config.ShowHelp(); //show help for catapult
+                    return 1; //return error since we didn't do anything
+                });
+                config.HelpOption("-? | -h | --help"); //show help on --help
+             });
+             snowball.Command("help", config => { 
+                 config.Description = "get help!";
+                 config.OnExecute(()=>{
+                    catapult.ShowHelp("snowball");
+                     return 1;
+                 });
+              });
+             snowball.Command("list", config => {
+                    config.HelpOption("-? | -h | --help");
+                    config.Description = "list snowballs";
+                    config.OnExecute(()=>{ 
+
+                        Console.WriteLine("1");
+                        Console.WriteLine("2");
+                        return 0;
+                     });   
+                });
+            snowball.Command("add", config => {
+                    config.Description = "Add a snowball";
+                    config.HelpOption("-? | -h | --help");
+                    var arg = config.Argument("name", "name of the snowball", false);
+                    config.OnExecute(()=>{ 
+                        if(!string.IsNullOrWhiteSpace(arg.Value))
+                        {
+                            //add snowballs somehow
+                            Console.WriteLine($"added {arg.Value}");
+                            return 0;
+                        }
+                        return 0;
+                        
+                        
+                     });   
+                });
+            //give people help with --help
+            app.HelpOption("-? | -h | --help");
+            var result = app.Execute(args);
+            Environment.Exit(result);
+        }
+```
diff --git a/src/TerribleDev.Blog.Web/Posts/Securing-AWS-Elasticsearch-Service-with-NET-NEST-API-and-why-I-love-open-source.md b/src/TerribleDev.Blog.Web/Posts/Securing-AWS-Elasticsearch-Service-with-NET-NEST-API-and-why-I-love-open-source.md
index 2e1499e..4ddd15a 100644
--- a/src/TerribleDev.Blog.Web/Posts/Securing-AWS-Elasticsearch-Service-with-NET-NEST-API-and-why-I-love-open-source.md
+++ b/src/TerribleDev.Blog.Web/Posts/Securing-AWS-Elasticsearch-Service-with-NET-NEST-API-and-why-I-love-open-source.md
@@ -34,5 +34,3 @@ Eventually we bit the bullet and decided to sign our requests to the cluster. Un
 This project totally saved my bacon. Brandon's library plugged right into the .NET sdk, and auth'd our requests to aws without us having to figure out all that crypo. Within moments of finding it I filed an [issue](https://github.com/bcuff/elasticsearch-net-aws/issues/1) thanking Brandon as it really helped me out.
 
 The Elasticsearch service offering by Amazon is pretty awesome. Like any platform its less flexible then hosting the instances yourself. You have to live with the plugins they ship, but on the plus side you get a full cluster, with monitoring, and a knob to turn up instances, or storage space without having to worry about the details.
-
-
diff --git a/src/TerribleDev.Blog.Web/Posts/about.md b/src/TerribleDev.Blog.Web/Posts/about.md
new file mode 100644
index 0000000..5af0991
--- /dev/null
+++ b/src/TerribleDev.Blog.Web/Posts/about.md
@@ -0,0 +1,10 @@
+title: About
+date: 2022-03-08 01:03
+isLanding: true
+permalink: about
+---
+
+
+I am a software engineer. I currently work at [Quala](https://www.quala.io). I have worked on all area's of the stack. From a sysadmin, network engineer, backend developer, and frontend developer. I've helped build some extremely large scale websites such as [Vistaprint](https://www.vistaprint.com) and [CarGurus](https://www.cargurus.com). I have a passion for high performing software, devops, and front end. I am a huge fan of [JavaScript](https://en.wikipedia.org/wiki/JavaScript), [C#](https://en.wikipedia.org/wiki/C_Sharp), [Golang](https://en.wikipedia.org/wiki/Go_(programming_language)), and [Rust](https://en.wikipedia.org/wiki/Rust_(programming_language)).
+
+I blog about my general pains building software.
\ No newline at end of file
diff --git a/src/TerribleDev.Blog.Web/Views/Home/Post.cshtml b/src/TerribleDev.Blog.Web/Views/Home/Post.cshtml
index 17c70f3..fb5745b 100644
--- a/src/TerribleDev.Blog.Web/Views/Home/Post.cshtml
+++ b/src/TerribleDev.Blog.Web/Views/Home/Post.cshtml
@@ -6,7 +6,7 @@
 }
 
 
-    @Html.DisplayFor(m => m.Post, "Post")
+    @await Html.PartialAsync("SharedPost", Model.Post)
 
 
 @section Head {
diff --git a/src/TerribleDev.Blog.Web/Views/Shared/DisplayTemplates/LandingPage.cshtml b/src/TerribleDev.Blog.Web/Views/Shared/DisplayTemplates/LandingPage.cshtml
new file mode 100644
index 0000000..a9f4e4a
--- /dev/null
+++ b/src/TerribleDev.Blog.Web/Views/Shared/DisplayTemplates/LandingPage.cshtml
@@ -0,0 +1,17 @@
+@model LandingPage
+@{
+    var amp = ViewData["amp"] as bool? ?? false;
+}
+
+

@Model.Title

+ + @if(amp) + { + @Model.Content.Value.AmpContent + } + else + { + @Model.Content.Value.Content + } + +
\ No newline at end of file diff --git a/src/TerribleDev.Blog.Web/Views/Shared/DisplayTemplates/Post.cshtml b/src/TerribleDev.Blog.Web/Views/Shared/DisplayTemplates/Post.cshtml index fc73a4d..7a80ab5 100644 --- a/src/TerribleDev.Blog.Web/Views/Shared/DisplayTemplates/Post.cshtml +++ b/src/TerribleDev.Blog.Web/Views/Shared/DisplayTemplates/Post.cshtml @@ -1,4 +1,4 @@ -@model IPost +@model Post @{ var amp = ViewData["amp"] as bool? ?? false; } diff --git a/src/TerribleDev.Blog.Web/Views/Shared/Nav.cshtml b/src/TerribleDev.Blog.Web/Views/Shared/Nav.cshtml index 6c71a96..0b1202e 100644 --- a/src/TerribleDev.Blog.Web/Views/Shared/Nav.cshtml +++ b/src/TerribleDev.Blog.Web/Views/Shared/Nav.cshtml @@ -18,6 +18,7 @@ Tommy "Terrible Dev" Parnell
  • Home
  • +
  • About
  • Tags
  • RSS Feed
  • Github
  • diff --git a/src/TerribleDev.Blog.Web/Views/Shared/SharedPost.cshtml b/src/TerribleDev.Blog.Web/Views/Shared/SharedPost.cshtml new file mode 100644 index 0000000..4d7b6f4 --- /dev/null +++ b/src/TerribleDev.Blog.Web/Views/Shared/SharedPost.cshtml @@ -0,0 +1,3 @@ +@model IPost + +@Html.DisplayForModel() \ No newline at end of file diff --git a/src/TerribleDev.Blog.Web/Views/Tags/AllTags.cshtml b/src/TerribleDev.Blog.Web/Views/Tags/AllTags.cshtml index d2d9ec2..010e9de 100644 --- a/src/TerribleDev.Blog.Web/Views/Tags/AllTags.cshtml +++ b/src/TerribleDev.Blog.Web/Views/Tags/AllTags.cshtml @@ -1,4 +1,4 @@ -@model IDictionary> +@model IDictionary> @{ ViewData["Title"] = "all-tags"; } diff --git a/src/TerribleDev.Blog.Web/wwwroot/img/about/.keep b/src/TerribleDev.Blog.Web/wwwroot/img/about/.keep new file mode 100644 index 0000000..e69de29