diff --git a/src/MyWebLog.Data/Data.fs b/src/MyWebLog.Data/Data.fs index efdb6e6..e335d33 100644 --- a/src/MyWebLog.Data/Data.fs +++ b/src/MyWebLog.Data/Data.fs @@ -342,8 +342,10 @@ module Page = "permalink", page.permalink "updatedOn", page.updatedOn "showInPageList", page.showInPageList + "template", page.template "text", page.text "priorPermalinks", page.priorPermalinks + "metadata", page.metadata "revisions", page.revisions ] write; withRetryDefault; ignoreResult diff --git a/src/MyWebLog.Domain/DataTypes.fs b/src/MyWebLog.Domain/DataTypes.fs index 27cb1a2..89147f2 100644 --- a/src/MyWebLog.Domain/DataTypes.fs +++ b/src/MyWebLog.Domain/DataTypes.fs @@ -1,6 +1,7 @@ namespace MyWebLog open System +open MyWebLog /// A category under which a post may be identified [] @@ -119,6 +120,9 @@ type Page = /// The current text of the page text : string + /// Metadata for this page + metadata : MetaItem list + /// Permalinks at which this page may have been previously served (useful for migrated content) priorPermalinks : Permalink list @@ -141,6 +145,7 @@ module Page = showInPageList = false template = None text = "" + metadata = [] priorPermalinks = [] revisions = [] } @@ -182,6 +187,9 @@ type Post = /// The tags for the post tags : string list + /// Metadata for the post + metadata : MetaItem list + /// Permalinks at which this post may have been previously served (useful for migrated content) priorPermalinks : Permalink list @@ -205,6 +213,7 @@ module Post = text = "" categoryIds = [] tags = [] + metadata = [] priorPermalinks = [] revisions = [] } diff --git a/src/MyWebLog.Domain/SupportTypes.fs b/src/MyWebLog.Domain/SupportTypes.fs index f36f65a..f5127c8 100644 --- a/src/MyWebLog.Domain/SupportTypes.fs +++ b/src/MyWebLog.Domain/SupportTypes.fs @@ -98,7 +98,14 @@ type MetaItem = value : string } +/// Functions to support metadata items +module MetaItem = + /// An empty metadata item + let empty = + { name = ""; value = "" } + + /// A revision of a page or post [] type Revision = diff --git a/src/MyWebLog.Domain/ViewModels.fs b/src/MyWebLog.Domain/ViewModels.fs index cee7e04..b9b73e3 100644 --- a/src/MyWebLog.Domain/ViewModels.fs +++ b/src/MyWebLog.Domain/ViewModels.fs @@ -1,7 +1,6 @@ namespace MyWebLog.ViewModels open System -open System.Collections.Generic open MyWebLog /// Details about a category, used to display category lists @@ -136,13 +135,21 @@ type EditPageModel = /// The text of the page text : string + + /// Names of metadata items + metaNames : string[] + + /// Values of metadata items + metaValues : string[] } + /// Create an edit model from an existing page static member fromPage (page : Page) = let latest = match page.revisions |> List.sortByDescending (fun r -> r.asOf) |> List.tryHead with | Some rev -> rev | None -> Revision.empty + let page = if page.metadata |> List.isEmpty then { page with metadata = [ MetaItem.empty ] } else page { pageId = PageId.toString page.id title = page.title permalink = Permalink.toString page.permalink @@ -150,6 +157,8 @@ type EditPageModel = isShownInPageList = page.showInPageList source = MarkupText.sourceType latest.text text = MarkupText.text latest.text + metaNames = page.metadata |> List.map (fun m -> m.name) |> Array.ofList + metaValues = page.metadata |> List.map (fun m -> m.value) |> Array.ofList } @@ -182,6 +191,12 @@ type EditPostModel = /// Whether this post should be published doPublish : bool + + /// Names of metadata items + metaNames : string[] + + /// Values of metadata items + metaValues : string[] } /// Create an edit model from an existing past static member fromPost (post : Post) = @@ -189,15 +204,18 @@ type EditPostModel = match post.revisions |> List.sortByDescending (fun r -> r.asOf) |> List.tryHead with | Some rev -> rev | None -> Revision.empty - { postId = PostId.toString post.id - title = post.title - permalink = Permalink.toString post.permalink - source = MarkupText.sourceType latest.text - text = MarkupText.text latest.text - tags = String.Join (", ", post.tags) - categoryIds = post.categoryIds |> List.map CategoryId.toString |> Array.ofList - status = PostStatus.toString post.status - doPublish = false + let post = if post.metadata |> List.isEmpty then { post with metadata = [ MetaItem.empty ] } else post + { postId = PostId.toString post.id + title = post.title + permalink = Permalink.toString post.permalink + source = MarkupText.sourceType latest.text + text = MarkupText.text latest.text + tags = String.Join (", ", post.tags) + categoryIds = post.categoryIds |> List.map CategoryId.toString |> Array.ofList + status = PostStatus.toString post.status + doPublish = false + metaNames = post.metadata |> List.map (fun m -> m.name) |> Array.ofList + metaValues = post.metadata |> List.map (fun m -> m.value) |> Array.ofList } @@ -251,6 +269,9 @@ type PostListItem = /// Tags for the post tags : string list + + /// Metadata for the post + meta : MetaItem list } /// Create a post list item from a post @@ -265,6 +286,7 @@ type PostListItem = text = post.text categoryIds = post.categoryIds |> List.map CategoryId.toString tags = post.tags + meta = post.metadata } diff --git a/src/MyWebLog/Handlers.fs b/src/MyWebLog/Handlers.fs index c8d5276..86bc180 100644 --- a/src/MyWebLog/Handlers.fs +++ b/src/MyWebLog/Handlers.fs @@ -361,10 +361,13 @@ module Page = } match result with | Some (title, page) -> + let model = EditPageModel.fromPage page return! Hash.FromAnonymousObject {| csrf = csrfToken ctx - model = EditPageModel.fromPage page + model = model + metadata = Array.zip model.metaNames model.metaValues + |> Array.mapi (fun idx (name, value) -> [| string idx; name; value |]) page_title = title templates = templatesForTheme ctx "page" |} @@ -408,6 +411,10 @@ module Page = showInPageList = model.isShownInPageList template = match model.template with "" -> None | tmpl -> Some tmpl text = MarkupText.toHtml revision.text + metadata = Seq.zip model.metaNames model.metaValues + |> Seq.filter (fun it -> fst it > "") + |> Seq.map (fun it -> { name = fst it; value = snd it }) + |> List.ofSeq revisions = revision :: page.revisions } do! (match model.pageId with "new" -> Data.Page.add | _ -> Data.Page.update) page conn diff --git a/src/MyWebLog/Program.fs b/src/MyWebLog/Program.fs index 9ad58a3..f931fa2 100644 --- a/src/MyWebLog/Program.fs +++ b/src/MyWebLog/Program.fs @@ -25,8 +25,8 @@ type WebLogMiddleware (next : RequestDelegate) = /// DotLiquid filters module DotLiquidBespoke = - open DotLiquid open System.IO + open DotLiquid /// A filter to generate nav links, highlighting the active link (exact match) type NavLinkFilter () = @@ -166,7 +166,7 @@ let main args = builder.Services .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(fun opts -> - opts.ExpireTimeSpan <- TimeSpan.FromMinutes 20. + opts.ExpireTimeSpan <- TimeSpan.FromMinutes 60. opts.SlidingExpiration <- true opts.AccessDeniedPath <- "/forbidden") let _ = builder.Services.AddLogging () diff --git a/src/MyWebLog/themes/admin/page-edit.liquid b/src/MyWebLog/themes/admin/page-edit.liquid index c5eb1a1..c94e7e3 100644 --- a/src/MyWebLog/themes/admin/page-edit.liquid +++ b/src/MyWebLog/themes/admin/page-edit.liquid @@ -56,6 +56,50 @@ +
+
+
+ + Metadata + + +
+
+ {%- for meta in metadata %} +
+
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+ {% endfor -%} +
+ + +
+
+
+
diff --git a/src/MyWebLog/themes/bit-badger/home-page.liquid b/src/MyWebLog/themes/bit-badger/home-page.liquid new file mode 100644 index 0000000..9b83987 --- /dev/null +++ b/src/MyWebLog/themes/bit-badger/home-page.liquid @@ -0,0 +1,98 @@ +
+
+ {{ page.text }} +
+ +
diff --git a/src/MyWebLog/themes/bit-badger/layout.liquid b/src/MyWebLog/themes/bit-badger/layout.liquid new file mode 100644 index 0000000..b71ab5a --- /dev/null +++ b/src/MyWebLog/themes/bit-badger/layout.liquid @@ -0,0 +1,45 @@ + + + + + {{ page_title }} » Bit Badger Solutions + + + + + + {{ content }} + + + \ No newline at end of file diff --git a/src/MyWebLog/themes/bit-badger/single-page.liquid b/src/MyWebLog/themes/bit-badger/single-page.liquid new file mode 100644 index 0000000..23adf69 --- /dev/null +++ b/src/MyWebLog/themes/bit-badger/single-page.liquid @@ -0,0 +1,5 @@ +
+

{{ page.title }}

+ {{ page.text }} +


« Home

+
diff --git a/src/MyWebLog/wwwroot/themes/admin/admin.js b/src/MyWebLog/wwwroot/themes/admin/admin.js index b030360..b99d5a1 100644 --- a/src/MyWebLog/wwwroot/themes/admin/admin.js +++ b/src/MyWebLog/wwwroot/themes/admin/admin.js @@ -1,4 +1,93 @@ const Admin = { + /** The next index for a metadata item */ + nextMetaIndex : 0, + + /** + * Set the next meta item index + * @param idx The index to set + */ + // Calling a function with a Liquid variable does not look like an error in the IDE... + setNextMetaIndex(idx) { + this.nextMetaIndex = idx + }, + + /** + * Add a new row for metadata entry + */ + addMetaItem() { + // Remove button + const removeBtn = document.createElement("button") + removeBtn.type = "button" + removeBtn.className = "btn btn-sm btn-danger" + removeBtn.innerHTML = "−" + removeBtn.setAttribute("onclick", `Admin.removeMetaItem(${this.nextMetaIndex})`) + + const removeCol = document.createElement("div") + removeCol.className = "col-1 text-center align-self-center" + removeCol.appendChild(removeBtn) + + // Name + const nameField = document.createElement("input") + nameField.type = "text" + nameField.name = "metaNames" + nameField.id = `metaNames_${this.nextMetaIndex}` + nameField.className = "form-control" + nameField.placeholder = "Name" + + const nameLabel = document.createElement("label") + nameLabel.htmlFor = nameField.id + nameLabel.innerText = nameField.placeholder + + const nameFloat = document.createElement("div") + nameFloat.className = "form-floating" + nameFloat.appendChild(nameField) + nameFloat.appendChild(nameLabel) + + const nameCol = document.createElement("div") + nameCol.className = "col-3" + nameCol.appendChild(nameFloat) + + // Value + const valueField = document.createElement("input") + valueField.type = "text" + valueField.name = "metaValues" + valueField.id = `metaValues_${this.nextMetaIndex}` + valueField.className = "form-control" + valueField.placeholder = "Value" + + const valueLabel = document.createElement("label") + valueLabel.htmlFor = valueField.id + valueLabel.innerText = valueField.placeholder + + const valueFloat = document.createElement("div") + valueFloat.className = "form-floating" + valueFloat.appendChild(valueField) + valueFloat.appendChild(valueLabel) + + const valueCol = document.createElement("div") + valueCol.className = "col-8" + valueCol.appendChild(valueFloat) + + // Put it all together + const newRow = document.createElement("div") + newRow.className = "row mb-3" + newRow.id = `meta_${this.nextMetaIndex}` + newRow.appendChild(removeCol) + newRow.appendChild(nameCol) + newRow.appendChild(valueCol) + + document.getElementById("metaItems").appendChild(newRow) + this.nextMetaIndex++ + }, + + /** + * Remove a metadata item + * @param idx The index of the metadata item to remove + */ + removeMetaItem(idx) { + document.getElementById(`meta_${idx}`).remove() + }, + /** * Confirm and delete a category * @param id The ID of the category to be deleted diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/bit-badger-auth.png b/src/MyWebLog/wwwroot/themes/bit-badger/bit-badger-auth.png new file mode 100644 index 0000000..42c407c Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/bit-badger-auth.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/bitbadger.png b/src/MyWebLog/wwwroot/themes/bit-badger/bitbadger.png new file mode 100644 index 0000000..62f8d76 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/bitbadger.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/facebook.png b/src/MyWebLog/wwwroot/themes/bit-badger/facebook.png new file mode 100644 index 0000000..3cdde01 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/facebook.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/favicon.ico b/src/MyWebLog/wwwroot/themes/bit-badger/favicon.ico new file mode 100644 index 0000000..22ca446 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/favicon.ico differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/bay-vista.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/bay-vista.png new file mode 100644 index 0000000..0af52cf Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/bay-vista.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/cassy-fiano.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/cassy-fiano.png new file mode 100644 index 0000000..5c96982 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/cassy-fiano.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/dr-melissa-clouthier.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/dr-melissa-clouthier.png new file mode 100644 index 0000000..1784647 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/dr-melissa-clouthier.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/emerald-mountain-christian-school.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/emerald-mountain-christian-school.png new file mode 100644 index 0000000..9275710 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/emerald-mountain-christian-school.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/futility-closet.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/futility-closet.png new file mode 100644 index 0000000..e9189fa Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/futility-closet.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/hard-corps-wife.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/hard-corps-wife.png new file mode 100644 index 0000000..31e9d11 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/hard-corps-wife.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/liberty-pundits.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/liberty-pundits.png new file mode 100644 index 0000000..1382c80 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/liberty-pundits.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/mindy-mackenzie.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/mindy-mackenzie.png new file mode 100644 index 0000000..39fef9c Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/mindy-mackenzie.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/my-prayer-journal.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/my-prayer-journal.png new file mode 100644 index 0000000..6192350 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/my-prayer-journal.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/nsx.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/nsx.png new file mode 100644 index 0000000..4083b97 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/nsx.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/olivet-baptist.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/olivet-baptist.png new file mode 100644 index 0000000..30edc33 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/olivet-baptist.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/photography-by-michelle.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/photography-by-michelle.png new file mode 100644 index 0000000..31c662b Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/photography-by-michelle.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/prayer-tracker.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/prayer-tracker.png new file mode 100644 index 0000000..0c81b77 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/prayer-tracker.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/riehl-world-news.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/riehl-world-news.png new file mode 100644 index 0000000..a6f6d57 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/riehl-world-news.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/tcms.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/tcms.png new file mode 100644 index 0000000..01c4792 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/tcms.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/tech-blog.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/tech-blog.png new file mode 100644 index 0000000..e1a479f Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/tech-blog.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/the-shark-tank.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/the-shark-tank.png new file mode 100644 index 0000000..35783d9 Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/the-shark-tank.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/virtual-prayer-room.png b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/virtual-prayer-room.png new file mode 100644 index 0000000..d9e1bed Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/screenshots/virtual-prayer-room.png differ diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/style.css b/src/MyWebLog/wwwroot/themes/bit-badger/style.css new file mode 100644 index 0000000..7c437cc --- /dev/null +++ b/src/MyWebLog/wwwroot/themes/bit-badger/style.css @@ -0,0 +1,217 @@ +html { + background-color: lightgray; +} +body { + margin: 0; + font-family: "Raleway", "Segoe UI", Ubuntu, Tahoma, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; + background-color: #FFFAFA; +} +a { + color: navy; + text-decoration: none; +} +a:hover { + border-bottom: dotted 1px navy; +} +a img { + border: 0; +} +acronym { + border-bottom: dotted 1px black; +} +header, h1, h2, h3, footer a { + font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; +} +h1 { + text-align: center; + margin: 1.4rem 0; + font-size: 2rem; +} +h2 { + margin: 1.2rem 0; +} +h3 { + margin: 1rem 0; +} +h2, h3 { + border-bottom: solid 2px navy; +} +@media all and (min-width:40rem) { + h2, h3 { + width: 80%; + } +} +p { + margin: 1rem 0; +} +#content { + margin: 0 1rem; +} +.content { + font-size: 1.1rem; +} +.auto { + margin: 0 auto; +} +@media all and (min-width: 68rem) { + .content { + width: 66rem; + } +} +.hdr { + font-size: 14pt; + font-weight: bold; +} +.strike { + text-decoration: line-through; +} +.alignleft { + float: left; + padding-right: 5px; +} +ul { + padding-left: 40px; +} +li { + list-style-type: disc; +} +.app-info { + display: flex; + flex-flow: row-reverse wrap; + justify-content: center; +} +abbr[title] { + text-decoration: none; + border-bottom: dotted 1px rgba(0, 0, 0, .5) +} +/* Page header */ +.site-header { + height: 100px; + display: flex; + flex-direction: row; + justify-content: space-between; + background-image: linear-gradient(to bottom, lightgray, #FFFAFA); +} +.site-header a, .site-header a:visited { + color: black; +} +.site-header a:hover { + border-bottom: none; +} +.header-title { + font-size: 3rem; + font-weight: bold; + line-height: 100px; + text-align: center; +} +.header-spacer { + flex-grow: 3; +} +.header-social { + padding: 25px .8rem 0 0; +} +.header-social img { + width: 50px; + height: 50px; +} +@media all and (max-width:40rem) { + .site-header { + height: auto; + flex-direction: column; + align-items: center; + } + .header-title { + line-height: 3rem; + } + .header-spacer { + display: none; + } +} +/* Home page */ +@media all and (min-width: 80rem) { + .home { + display: flex; + flex-flow: row; + align-items: flex-start; + justify-content: space-around; + } +} +.home-lead { + font-size: 1.3rem; + text-align: center; +} +.app-sidebar { + text-align: center; + border-top: dotted 1px lightgray; + padding-top: 1rem; + font-size: .9rem; + display: flex; + flex-flow: row wrap; + justify-content: space-around; +} +.app-sidebar > div { + width: 20rem; + padding-bottom: 1rem; +} +@media all and (min-width: 68rem) { + .app-sidebar { + width: 66rem; + margin: auto; + } +} +@media all and (min-width: 80rem) { + .app-sidebar { + width: 12rem; + border-top: none; + border-left: dotted 1px lightgray; + padding-top: 0; + padding-left: 2rem; + flex-direction: column; + } + .app-sidebar > div { + width: auto; + } +} +.app-sidebar a { + font-size: 10pt; + font-family: sans-serif; +} +.app-sidebar-head { + font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; + font-weight: bold; + color: maroon; + margin-bottom: .8rem; + padding: 3px 12px; + border-bottom: solid 2px lightgray; + font-size: 1rem; +} +.app-sidebar-name, .app-sidebar-description { + margin: 0; + padding: 0; +} +.app-sidebar-description { + font-style: italic; + color: #555555; + padding-bottom: .6rem; +} +/* All solution page */ +.app-name { + font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif; + font-size: 1.3rem; + font-weight: bold; + color: maroon; +} +/* Footer */ +footer { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + padding: 20px 15px 10px 15px; + font-size: 1rem; + color: black; + clear: both; + background-image: linear-gradient(to bottom, #FFFAFA, lightgray); +} +footer a:link, footer a:visited { + color: black; +} \ No newline at end of file diff --git a/src/MyWebLog/wwwroot/themes/bit-badger/twitter.png b/src/MyWebLog/wwwroot/themes/bit-badger/twitter.png new file mode 100644 index 0000000..8b5ae7c Binary files /dev/null and b/src/MyWebLog/wwwroot/themes/bit-badger/twitter.png differ