V2 #1
|
@ -76,6 +76,20 @@ type TagMapIdConverter () =
|
|||
override _.ReadJson (reader : JsonReader, _ : Type, _ : TagMapId, _ : bool, _ : JsonSerializer) =
|
||||
(string >> TagMapId) reader.Value
|
||||
|
||||
type ThemeAssetIdConverter () =
|
||||
inherit JsonConverter<ThemeAssetId> ()
|
||||
override _.WriteJson (writer : JsonWriter, value : ThemeAssetId, _ : JsonSerializer) =
|
||||
writer.WriteValue (ThemeAssetId.toString value)
|
||||
override _.ReadJson (reader : JsonReader, _ : Type, _ : ThemeAssetId, _ : bool, _ : JsonSerializer) =
|
||||
(string >> ThemeAssetId.ofString) reader.Value
|
||||
|
||||
type ThemeIdConverter () =
|
||||
inherit JsonConverter<ThemeId> ()
|
||||
override _.WriteJson (writer : JsonWriter, value : ThemeId, _ : JsonSerializer) =
|
||||
writer.WriteValue (ThemeId.toString value)
|
||||
override _.ReadJson (reader : JsonReader, _ : Type, _ : ThemeId, _ : bool, _ : JsonSerializer) =
|
||||
(string >> ThemeId) reader.Value
|
||||
|
||||
type WebLogIdConverter () =
|
||||
inherit JsonConverter<WebLogId> ()
|
||||
override _.WriteJson (writer : JsonWriter, value : WebLogId, _ : JsonSerializer) =
|
||||
|
@ -106,6 +120,8 @@ let all () : JsonConverter seq =
|
|||
PageIdConverter ()
|
||||
PostIdConverter ()
|
||||
TagMapIdConverter ()
|
||||
ThemeAssetIdConverter ()
|
||||
ThemeIdConverter ()
|
||||
WebLogIdConverter ()
|
||||
WebLogUserIdConverter ()
|
||||
// Handles DUs with no associated data, as well as option fields
|
||||
|
|
|
@ -20,6 +20,12 @@ module Table =
|
|||
/// The tag map table
|
||||
let TagMap = "TagMap"
|
||||
|
||||
/// The theme table
|
||||
let Theme = "Theme"
|
||||
|
||||
/// The theme asset table
|
||||
let ThemeAsset = "ThemeAsset"
|
||||
|
||||
/// The web log table
|
||||
let WebLog = "WebLog"
|
||||
|
||||
|
@ -27,7 +33,7 @@ module Table =
|
|||
let WebLogUser = "WebLogUser"
|
||||
|
||||
/// A list of all tables
|
||||
let all = [ Category; Comment; Page; Post; TagMap; WebLog; WebLogUser ]
|
||||
let all = [ Category; Comment; Page; Post; TagMap; Theme; ThemeAsset; WebLog; WebLogUser ]
|
||||
|
||||
|
||||
/// Functions to assist with retrieving data
|
||||
|
@ -697,6 +703,68 @@ module TagMap =
|
|||
}
|
||||
|
||||
|
||||
/// Functions to manipulate themes
|
||||
module Theme =
|
||||
|
||||
/// Get all themes
|
||||
let list =
|
||||
rethink<Theme list> {
|
||||
withTable Table.Theme
|
||||
filter (fun row -> row["id"].Ne "admin" :> obj)
|
||||
without [ "templates" ]
|
||||
orderBy "id"
|
||||
result; withRetryDefault
|
||||
}
|
||||
|
||||
/// Retrieve a theme by its ID
|
||||
let findById (themeId : ThemeId) =
|
||||
rethink<Theme> {
|
||||
withTable Table.Theme
|
||||
get themeId
|
||||
resultOption; withRetryOptionDefault
|
||||
}
|
||||
|
||||
/// Save a theme
|
||||
let save (theme : Theme) =
|
||||
rethink {
|
||||
withTable Table.Theme
|
||||
get theme.id
|
||||
replace theme
|
||||
write; withRetryDefault; ignoreResult
|
||||
}
|
||||
|
||||
|
||||
/// Functions to manipulate theme assets
|
||||
module ThemeAsset =
|
||||
|
||||
/// Delete all assets for a theme
|
||||
let deleteByTheme themeId =
|
||||
let keyPrefix = $"^{ThemeId.toString themeId}/"
|
||||
rethink {
|
||||
withTable Table.ThemeAsset
|
||||
filter (fun row -> row["id"].Match keyPrefix :> obj)
|
||||
delete
|
||||
write; withRetryDefault; ignoreResult
|
||||
}
|
||||
|
||||
/// Find a theme asset by its ID
|
||||
let findById (assetId : ThemeAssetId) =
|
||||
rethink<ThemeAsset> {
|
||||
withTable Table.ThemeAsset
|
||||
get assetId
|
||||
resultOption; withRetryOptionDefault
|
||||
}
|
||||
|
||||
/// Save a theme assed
|
||||
let save (asset : ThemeAsset) =
|
||||
rethink {
|
||||
withTable Table.ThemeAsset
|
||||
get asset.id
|
||||
replace asset
|
||||
write; withRetryDefault; ignoreResult
|
||||
}
|
||||
|
||||
|
||||
/// Functions to manipulate web logs
|
||||
module WebLog =
|
||||
|
||||
|
|
|
@ -246,6 +246,47 @@ module TagMap =
|
|||
}
|
||||
|
||||
|
||||
/// A theme
|
||||
type Theme =
|
||||
{ /// The ID / path of the theme
|
||||
id : ThemeId
|
||||
|
||||
/// A long name of the theme
|
||||
name : string
|
||||
|
||||
/// The version of the theme
|
||||
version : string
|
||||
|
||||
/// The templates for this theme
|
||||
templates: ThemeTemplate list
|
||||
}
|
||||
|
||||
/// Functions to support themes
|
||||
module Theme =
|
||||
|
||||
/// An empty theme
|
||||
let empty =
|
||||
{ id = ThemeId ""
|
||||
name = ""
|
||||
version = ""
|
||||
templates = []
|
||||
}
|
||||
|
||||
|
||||
/// A theme asset (a file served as part of a theme, at /themes/[theme]/[asset-path])
|
||||
type ThemeAsset =
|
||||
{
|
||||
/// The ID of the asset (consists of theme and path)
|
||||
id : ThemeAssetId
|
||||
|
||||
/// The updated date (set from the file date from the ZIP archive)
|
||||
updatedOn : DateTime
|
||||
|
||||
/// The data for the asset
|
||||
data : byte[]
|
||||
}
|
||||
|
||||
|
||||
/// A web log
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
type WebLog =
|
||||
|
|
|
@ -373,6 +373,39 @@ module TagMapId =
|
|||
let create () = TagMapId (newId ())
|
||||
|
||||
|
||||
/// An identifier for a theme (represents its path)
|
||||
type ThemeId = ThemeId of string
|
||||
|
||||
/// Functions to support theme IDs
|
||||
module ThemeId =
|
||||
let toString = function ThemeId ti -> ti
|
||||
|
||||
|
||||
/// An identifier for a theme asset
|
||||
type ThemeAssetId = ThemeAssetId of ThemeId * string
|
||||
|
||||
/// Functions to support theme asset IDs
|
||||
module ThemeAssetId =
|
||||
|
||||
/// Convert a theme asset ID into a path string
|
||||
let toString = function ThemeAssetId (ThemeId theme, asset) -> $"{theme}/{asset}"
|
||||
|
||||
/// Convert a string into a theme asset ID
|
||||
let ofString (it : string) =
|
||||
let themeIdx = it.IndexOf "/"
|
||||
ThemeAssetId (ThemeId it[..(themeIdx - 1)], it[(themeIdx + 1)..])
|
||||
|
||||
|
||||
/// A template for a theme
|
||||
type ThemeTemplate =
|
||||
{ /// The name of the template
|
||||
name : string
|
||||
|
||||
/// The text of the template
|
||||
text : string
|
||||
}
|
||||
|
||||
|
||||
/// An identifier for a web log
|
||||
type WebLogId = WebLogId of string
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ module CategoryCache =
|
|||
module TemplateCache =
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.Text.RegularExpressions
|
||||
open DotLiquid
|
||||
|
||||
|
@ -107,19 +106,28 @@ module TemplateCache =
|
|||
/// Custom include parameter pattern
|
||||
let private hasInclude = Regex ("""{% include_template \"(.*)\" %}""", RegexOptions.None, TimeSpan.FromSeconds 2)
|
||||
|
||||
/// Get a template for the given theme and template nate
|
||||
let get (theme : string) (templateName : string) = backgroundTask {
|
||||
let templatePath = $"themes/{theme}/{templateName}"
|
||||
/// Get a template for the given theme and template name
|
||||
let get (themeId : string) (templateName : string) conn = backgroundTask {
|
||||
let templatePath = $"{themeId}/{templateName}"
|
||||
match _cache.ContainsKey templatePath with
|
||||
| true -> ()
|
||||
| false ->
|
||||
let! file = File.ReadAllTextAsync $"{templatePath}.liquid"
|
||||
let mutable text = file
|
||||
match! Data.Theme.findById (ThemeId themeId) conn with
|
||||
| Some theme ->
|
||||
let mutable text = (theme.templates |> List.find (fun t -> t.name = templateName)).text
|
||||
while hasInclude.IsMatch text do
|
||||
let child = hasInclude.Match text
|
||||
let! file = File.ReadAllTextAsync $"themes/{theme}/{child.Groups[1].Value}.liquid"
|
||||
text <- text.Replace (child.Value, file)
|
||||
let childText = (theme.templates |> List.find (fun t -> t.name = child.Groups[1].Value)).text
|
||||
text <- text.Replace (child.Value, childText)
|
||||
_cache[templatePath] <- Template.Parse (text, SyntaxCompatibility.DotLiquid22)
|
||||
| None -> ()
|
||||
return _cache[templatePath]
|
||||
}
|
||||
|
||||
/// Invalidate all template cache entries for the given theme ID
|
||||
let invalidateTheme (themeId : string) =
|
||||
_cache.Keys
|
||||
|> Seq.filter (fun key -> key.StartsWith themeId)
|
||||
|> List.ofSeq
|
||||
|> List.iter (fun key -> match _cache.TryRemove key with _, _ -> ())
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ let dashboard : HttpHandler = fun next ctx -> task {
|
|||
|
||||
// GET /admin/categories
|
||||
let listCategories : HttpHandler = fun next ctx -> task {
|
||||
let! catListTemplate = TemplateCache.get "admin" "category-list-body"
|
||||
let! catListTemplate = TemplateCache.get "admin" "category-list-body" ctx.Conn
|
||||
let hash = Hash.FromAnonymousObject {|
|
||||
web_log = ctx.WebLog
|
||||
categories = CategoryCache.get ctx
|
||||
|
@ -271,49 +271,6 @@ let savePage : HttpHandler = fun next ctx -> task {
|
|||
| None -> return! Error.notFound next ctx
|
||||
}
|
||||
|
||||
// -- WEB LOG SETTINGS --
|
||||
|
||||
// GET /admin/settings
|
||||
let settings : HttpHandler = fun next ctx -> task {
|
||||
let webLog = ctx.WebLog
|
||||
let! allPages = Data.Page.findAll webLog.id ctx.Conn
|
||||
return!
|
||||
Hash.FromAnonymousObject
|
||||
{| csrf = csrfToken ctx
|
||||
model = SettingsModel.fromWebLog webLog
|
||||
pages =
|
||||
seq {
|
||||
KeyValuePair.Create ("posts", "- First Page of Posts -")
|
||||
yield! allPages
|
||||
|> List.sortBy (fun p -> p.title.ToLower ())
|
||||
|> List.map (fun p -> KeyValuePair.Create (PageId.toString p.id, p.title))
|
||||
}
|
||||
|> Array.ofSeq
|
||||
themes = themes ()
|
||||
web_log = webLog
|
||||
page_title = "Web Log Settings"
|
||||
|}
|
||||
|> viewForTheme "admin" "settings" next ctx
|
||||
}
|
||||
|
||||
// POST /admin/settings
|
||||
let saveSettings : HttpHandler = fun next ctx -> task {
|
||||
let webLog = ctx.WebLog
|
||||
let conn = ctx.Conn
|
||||
let! model = ctx.BindFormAsync<SettingsModel> ()
|
||||
match! Data.WebLog.findById webLog.id conn with
|
||||
| Some webLog ->
|
||||
let webLog = model.update webLog
|
||||
do! Data.WebLog.updateSettings webLog conn
|
||||
|
||||
// Update cache
|
||||
WebLogCache.set webLog
|
||||
|
||||
do! addMessage ctx { UserMessage.success with message = "Web log settings saved successfully" }
|
||||
return! redirectToGet (WebLog.relativeUrl webLog (Permalink "admin/settings")) next ctx
|
||||
| None -> return! Error.notFound next ctx
|
||||
}
|
||||
|
||||
// -- TAG MAPPINGS --
|
||||
|
||||
open Microsoft.AspNetCore.Http
|
||||
|
@ -332,7 +289,7 @@ let private tagMappingHash (ctx : HttpContext) = task {
|
|||
// GET /admin/settings/tag-mappings
|
||||
let tagMappings : HttpHandler = fun next ctx -> task {
|
||||
let! hash = tagMappingHash ctx
|
||||
let! listTemplate = TemplateCache.get "admin" "tag-mapping-list-body"
|
||||
let! listTemplate = TemplateCache.get "admin" "tag-mapping-list-body" ctx.Conn
|
||||
|
||||
hash.Add ("tag_mapping_list", listTemplate.Render hash)
|
||||
hash.Add ("page_title", "Tag Mappings")
|
||||
|
@ -392,3 +349,156 @@ let deleteMapping tagMapId : HttpHandler = fun next ctx -> task {
|
|||
| false -> do! addMessage ctx { UserMessage.error with message = "Tag mapping not found; nothing deleted" }
|
||||
return! tagMappingsBare next ctx
|
||||
}
|
||||
|
||||
// -- THEMES --
|
||||
|
||||
open System.IO.Compression
|
||||
open System.Text.RegularExpressions
|
||||
|
||||
// GET /admin/theme/update
|
||||
let themeUpdatePage : HttpHandler = fun next ctx -> task {
|
||||
return!
|
||||
Hash.FromAnonymousObject {|
|
||||
csrf = csrfToken ctx
|
||||
page_title = "Upload Theme"
|
||||
|}
|
||||
|> viewForTheme "admin" "upload-theme" next ctx
|
||||
}
|
||||
|
||||
/// Update the name and version for a theme based on the version.txt file, if present
|
||||
let private updateNameAndVersion (theme : Theme) (zip : ZipArchive) = backgroundTask {
|
||||
let now () = DateTime.UtcNow.ToString "yyyyMMdd.HHmm"
|
||||
match zip.Entries |> Seq.filter (fun it -> it.FullName = "version.txt") |> Seq.tryHead with
|
||||
| Some versionItem ->
|
||||
use versionFile = new StreamReader(versionItem.Open ())
|
||||
let! versionText = versionFile.ReadToEndAsync ()
|
||||
let parts = versionText.Trim().Replace("\r", "").Split "\n"
|
||||
let displayName = if parts[0] > "" then parts[0] else ThemeId.toString theme.id
|
||||
let version = if parts.Length > 1 && parts[1] > "" then parts[1] else now ()
|
||||
return { theme with name = displayName; version = version }
|
||||
| None ->
|
||||
return { theme with name = ThemeId.toString theme.id; version = now () }
|
||||
}
|
||||
|
||||
/// Delete all theme assets, and remove templates from theme
|
||||
let private checkForCleanLoad (theme : Theme) cleanLoad conn = backgroundTask {
|
||||
if cleanLoad then
|
||||
do! Data.ThemeAsset.deleteByTheme theme.id conn
|
||||
return { theme with templates = [] }
|
||||
else
|
||||
return theme
|
||||
}
|
||||
|
||||
/// Update the theme with all templates from the ZIP archive
|
||||
let private updateTemplates (theme : Theme) (zip : ZipArchive) = backgroundTask {
|
||||
let tasks =
|
||||
zip.Entries
|
||||
|> Seq.filter (fun it -> it.Name.EndsWith ".liquid")
|
||||
|> Seq.map (fun templateItem -> backgroundTask {
|
||||
use templateFile = new StreamReader (templateItem.Open ())
|
||||
let! template = templateFile.ReadToEndAsync ()
|
||||
return { name = templateItem.Name.Replace (".liquid", ""); text = template }
|
||||
})
|
||||
let! templates = Task.WhenAll tasks
|
||||
return
|
||||
templates
|
||||
|> Array.fold (fun t template ->
|
||||
{ t with templates = template :: (t.templates |> List.filter (fun it -> it.name <> template.name)) })
|
||||
theme
|
||||
}
|
||||
|
||||
/// Update theme assets from the ZIP archive
|
||||
let private updateAssets themeId (zip : ZipArchive) conn = backgroundTask {
|
||||
for asset in zip.Entries |> Seq.filter (fun it -> it.FullName.StartsWith "wwwroot") do
|
||||
let assetName = asset.FullName.Replace ("wwwroot/", "")
|
||||
if assetName <> "" && not (assetName.EndsWith "/") then
|
||||
use stream = new MemoryStream ()
|
||||
do! asset.Open().CopyToAsync stream
|
||||
do! Data.ThemeAsset.save
|
||||
{ id = ThemeAssetId (themeId, assetName)
|
||||
updatedOn = asset.LastWriteTime.DateTime
|
||||
data = stream.ToArray ()
|
||||
} conn
|
||||
}
|
||||
|
||||
/// Load a theme from the given stream, which should contain a ZIP archive
|
||||
let loadThemeFromZip themeName file clean conn = backgroundTask {
|
||||
use zip = new ZipArchive (file, ZipArchiveMode.Read)
|
||||
let themeId = ThemeId themeName
|
||||
let! theme = backgroundTask {
|
||||
match! Data.Theme.findById themeId conn with
|
||||
| Some t -> return t
|
||||
| None -> return { Theme.empty with id = themeId }
|
||||
}
|
||||
let! theme = updateNameAndVersion theme zip
|
||||
let! theme = checkForCleanLoad theme clean conn
|
||||
let! theme = updateTemplates theme zip
|
||||
do! updateAssets themeId zip conn
|
||||
do! Data.Theme.save theme conn
|
||||
}
|
||||
|
||||
// POST /admin/theme/update
|
||||
let updateTheme : HttpHandler = fun next ctx -> task {
|
||||
if ctx.Request.HasFormContentType && ctx.Request.Form.Files.Count > 0 then
|
||||
let themeFile = Seq.head ctx.Request.Form.Files
|
||||
let themeName = themeFile.FileName.Split(".").[0].ToLowerInvariant().Replace (" ", "-")
|
||||
// TODO: add restriction for admin theme based on role
|
||||
if Regex.IsMatch (themeName, """^[a-z0-9\-]+$""") then
|
||||
use stream = new MemoryStream ()
|
||||
do! themeFile.CopyToAsync stream
|
||||
do! loadThemeFromZip themeName stream true ctx.Conn
|
||||
do! addMessage ctx { UserMessage.success with message = "Theme updated successfully" }
|
||||
return! redirectToGet (WebLog.relativeUrl ctx.WebLog (Permalink "admin/dashboard")) next ctx
|
||||
else
|
||||
do! addMessage ctx { UserMessage.error with message = $"Theme name {themeName} is invalid" }
|
||||
return! redirectToGet (WebLog.relativeUrl ctx.WebLog (Permalink "admin/theme/update")) next ctx
|
||||
else
|
||||
return! RequestErrors.BAD_REQUEST "Bad request" next ctx
|
||||
}
|
||||
|
||||
// -- WEB LOG SETTINGS --
|
||||
|
||||
// GET /admin/settings
|
||||
let settings : HttpHandler = fun next ctx -> task {
|
||||
let webLog = ctx.WebLog
|
||||
let! allPages = Data.Page.findAll webLog.id ctx.Conn
|
||||
let! themes = Data.Theme.list ctx.Conn
|
||||
return!
|
||||
Hash.FromAnonymousObject
|
||||
{| csrf = csrfToken ctx
|
||||
model = SettingsModel.fromWebLog webLog
|
||||
pages =
|
||||
seq {
|
||||
KeyValuePair.Create ("posts", "- First Page of Posts -")
|
||||
yield! allPages
|
||||
|> List.sortBy (fun p -> p.title.ToLower ())
|
||||
|> List.map (fun p -> KeyValuePair.Create (PageId.toString p.id, p.title))
|
||||
}
|
||||
|> Array.ofSeq
|
||||
themes = themes
|
||||
|> Seq.ofList
|
||||
|> Seq.map (fun it -> KeyValuePair.Create (ThemeId.toString it.id, $"{it.name} (v{it.version})"))
|
||||
|> Array.ofSeq
|
||||
web_log = webLog
|
||||
page_title = "Web Log Settings"
|
||||
|}
|
||||
|> viewForTheme "admin" "settings" next ctx
|
||||
}
|
||||
|
||||
// POST /admin/settings
|
||||
let saveSettings : HttpHandler = fun next ctx -> task {
|
||||
let webLog = ctx.WebLog
|
||||
let conn = ctx.Conn
|
||||
let! model = ctx.BindFormAsync<SettingsModel> ()
|
||||
match! Data.WebLog.findById webLog.id conn with
|
||||
| Some webLog ->
|
||||
let webLog = model.update webLog
|
||||
do! Data.WebLog.updateSettings webLog conn
|
||||
|
||||
// Update cache
|
||||
WebLogCache.set webLog
|
||||
|
||||
do! addMessage ctx { UserMessage.success with message = "Web log settings saved successfully" }
|
||||
return! redirectToGet (WebLog.relativeUrl webLog (Permalink "admin/settings")) next ctx
|
||||
| None -> return! Error.notFound next ctx
|
||||
}
|
||||
|
|
|
@ -108,12 +108,12 @@ let viewForTheme theme template next ctx = fun (hash : Hash) -> task {
|
|||
// the net effect is a "layout" capability similar to Razor or Pug
|
||||
|
||||
// Render view content...
|
||||
let! contentTemplate = TemplateCache.get theme template
|
||||
let! contentTemplate = TemplateCache.get theme template ctx.Conn
|
||||
hash.Add ("content", contentTemplate.Render hash)
|
||||
|
||||
// ...then render that content with its layout
|
||||
let isHtmx = ctx.Request.IsHtmx && not ctx.Request.IsHtmxRefresh
|
||||
let! layoutTemplate = TemplateCache.get theme (if isHtmx then "layout-partial" else "layout")
|
||||
let! layoutTemplate = TemplateCache.get theme (if isHtmx then "layout-partial" else "layout") ctx.Conn
|
||||
|
||||
return! htmlString (layoutTemplate.Render hash) next ctx
|
||||
}
|
||||
|
@ -123,10 +123,10 @@ let bareForTheme theme template next ctx = fun (hash : Hash) -> task {
|
|||
do! populateHash hash ctx
|
||||
|
||||
// Bare templates are rendered with layout-bare
|
||||
let! contentTemplate = TemplateCache.get theme template
|
||||
let! contentTemplate = TemplateCache.get theme template ctx.Conn
|
||||
hash.Add ("content", contentTemplate.Render hash)
|
||||
|
||||
let! layoutTemplate = TemplateCache.get theme "layout-bare"
|
||||
let! layoutTemplate = TemplateCache.get theme "layout-bare" ctx.Conn
|
||||
|
||||
// add messages as HTTP headers
|
||||
let messages = hash["messages"] :?> UserMessage[]
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
module MyWebLog.Handlers.Routes
|
||||
|
||||
open Giraffe
|
||||
open Microsoft.AspNetCore.Http
|
||||
open MyWebLog
|
||||
|
||||
/// Module to resolve routes that do not match any other known route (web blog content)
|
||||
module CatchAll =
|
||||
|
||||
open DotLiquid
|
||||
open Microsoft.AspNetCore.Http
|
||||
open MyWebLog.ViewModels
|
||||
|
||||
/// Sequence where the first returned value is the proper handler for the link
|
||||
|
@ -89,6 +89,48 @@ module CatchAll =
|
|||
| None -> return! Error.notFound next ctx
|
||||
}
|
||||
|
||||
|
||||
/// Serve theme assets
|
||||
module Asset =
|
||||
|
||||
open System
|
||||
open Microsoft.AspNetCore.Http.Headers
|
||||
open Microsoft.AspNetCore.StaticFiles
|
||||
open Microsoft.Net.Http.Headers
|
||||
|
||||
/// Determine if the asset has been modified since the date/time specified by the If-Modified-Since header
|
||||
let private checkModified asset (ctx : HttpContext) : HttpHandler option =
|
||||
match ctx.Request.Headers.IfModifiedSince with
|
||||
| it when it.Count < 1 -> None
|
||||
| it ->
|
||||
if asset.updatedOn > DateTime.Parse it[0] then
|
||||
None
|
||||
else
|
||||
Some (setStatusCode 304 >=> setBodyFromString "Not Modified")
|
||||
|
||||
/// An instance of ASP.NET Core's file extension to MIME type converter
|
||||
let private mimeMap = FileExtensionContentTypeProvider ()
|
||||
|
||||
// GET /theme/{theme}/{**path}
|
||||
let serveAsset (urlParts : string seq) : HttpHandler = fun next ctx -> task {
|
||||
let path = urlParts |> Seq.skip 1 |> Seq.head
|
||||
match! Data.ThemeAsset.findById (ThemeAssetId.ofString path) ctx.Conn with
|
||||
| Some asset ->
|
||||
match checkModified asset ctx with
|
||||
| Some threeOhFour -> return! threeOhFour next ctx
|
||||
| None ->
|
||||
let mimeType =
|
||||
match mimeMap.TryGetContentType path with
|
||||
| true, typ -> typ
|
||||
| false, _ -> "application/octet-stream"
|
||||
let headers = ResponseHeaders ctx.Response.Headers
|
||||
headers.LastModified <- Some (DateTimeOffset asset.updatedOn) |> Option.toNullable
|
||||
headers.ContentType <- MediaTypeHeaderValue mimeType
|
||||
return! setBody asset.data next ctx
|
||||
| None -> return! Error.notFound next ctx
|
||||
}
|
||||
|
||||
|
||||
/// The primary myWebLog router
|
||||
let router : HttpHandler = choose [
|
||||
GET >=> choose [
|
||||
|
@ -126,6 +168,7 @@ let router : HttpHandler = choose [
|
|||
routef "/%s/edit" Admin.editMapping
|
||||
])
|
||||
])
|
||||
route "/theme/update" >=> Admin.themeUpdatePage
|
||||
route "/user/edit" >=> User.edit
|
||||
]
|
||||
POST >=> validateCsrf >=> choose [
|
||||
|
@ -155,15 +198,17 @@ let router : HttpHandler = choose [
|
|||
routef "/%s/delete" Admin.deleteMapping
|
||||
])
|
||||
])
|
||||
route "/theme/update" >=> Admin.updateTheme
|
||||
route "/user/save" >=> User.save
|
||||
]
|
||||
])
|
||||
GET >=> routexp "/category/(.*)" Post.pageOfCategorizedPosts
|
||||
GET >=> routef "/page/%i" Post.pageOfPosts
|
||||
GET >=> routef "/page/%i/" Post.redirectToPageOfPosts
|
||||
GET >=> routexp "/tag/(.*)" Post.pageOfTaggedPosts
|
||||
GET_HEAD >=> routexp "/category/(.*)" Post.pageOfCategorizedPosts
|
||||
GET_HEAD >=> routef "/page/%i" Post.pageOfPosts
|
||||
GET_HEAD >=> routef "/page/%i/" Post.redirectToPageOfPosts
|
||||
GET_HEAD >=> routexp "/tag/(.*)" Post.pageOfTaggedPosts
|
||||
GET_HEAD >=> routexp "/themes/(.*)" Asset.serveAsset
|
||||
subRoute "/user" (choose [
|
||||
GET >=> choose [
|
||||
GET_HEAD >=> choose [
|
||||
route "/log-on" >=> User.logOn None
|
||||
route "/log-off" >=> User.logOff
|
||||
]
|
||||
|
@ -171,7 +216,7 @@ let router : HttpHandler = choose [
|
|||
route "/log-on" >=> User.doLogOn
|
||||
]
|
||||
])
|
||||
GET >=> CatchAll.route
|
||||
GET_HEAD >=> CatchAll.route
|
||||
Error.notFound
|
||||
]
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include=".\themes\**" CopyToOutputDirectory="Always" />
|
||||
<None Include=".\wwwroot\**" CopyToOutputDirectory="Always" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"hostname": "data02.bitbadger.solutions",
|
||||
"database": "myWebLog_dev"
|
||||
},
|
||||
"Generator": "myWebLog 2.0-alpha33",
|
||||
"Generator": "myWebLog 2.0-alpha34",
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"MyWebLog.Handlers": "Debug"
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{%- assign ot_books = "ZPSOFpd27EeFQvrTZE296Q|VERPK2rYN0G44bo7LjBSRw|fA6zV4ON002oMPoVUZs17Q|vLsJo3GL1ECOQbSIEMUaig|WZ933xSw6kmo7644X9mmXw|68f2_zVlekaaIZD_BX0sZg|WffJH3t68kuVUyNZXYSFYw|xNlTF35s_UulA7S-NTgcAA|0y4PDhOc7kiw9hp0RwaJCg|59ysY5363EaVCG_g7fUH5A|aBlyuIzm206LTKx-uYIGnA|YoQKqdkrbUivAeUf3DISow|WOAq8A9bB0a8TKmYAB7IdA|TsxpRv1lrUiNNeGGfIx6XA|rJkq5d_MyUGPgACkMm0iTw|F_X9vUdpAUy957_qSejcnw|5jvC66CtG06zRlkKuP1naw|su8Qq5KUwEyoDmssUQhjHQ|FtVxmNkn_EavFJY3jqodfA|oToPYf8OQkCBsB6J65j3SA|rKzSJptZjU6YAOy6nIhfbw|K2lHyseO6UWdHftwLswhgg|rpThtWd1HUuSeyHLIs7gpw|CD8jYdoi0kGyXTbsD6F0aA|ttObDyRHnUudsSNUsdQ8BA|fi4ORg0B90C-DeQGTrOaMA|6AW2cZfbAkWX5HT4XEGjig|Pf6Gllf9gU-IF9xDcmWd0g|7cDaYscN6kmKsgwuiwPt9Q|WG_j96GOH0KzGORwKL8YVA|p7wi1sNiGUWhUa1tqRhS8Q|CgIcCoHtpUiCshdHe8wMoA|V1PTu4Xoq0eUnniYIb8Mkw|1h1LTN1XyU-qWIPHVY398A|t34QuaRN6kOWizvKNPtdSg|Tw5oe-kzfkiqCc6_4AVskQ|At7RBOfiN0aWMKln0Dkreg|JiUy9RgUZUOrjeMdBpln9g|hc7roSimX0mukJPTe6clWA|kTbX-fYdFk6TJ8Tikec-AQ" | split: "|" -%}
|
||||
{%- assign nt_books = "Ksr4Dto97Um5NxhLpoRk5A|w-4_O87lYE-9_nrIXOuIHw|oJ_dgZir80mv2hat1rK4Qg|9QCQnNlevES8cYwHZWzrJw|DbkcRuTlnUyPXPPQso3L6g|CJZtcewtvUKqJH-rIUoR6g|xMRsXDsvDUiylTlFq6Tv-w|RmItBW75JUG7Iish-KRw1g|lKSYua82uE-YeMAzxqfrMg|Bopzxr31bkWJrFqO6o1oxg|KhiJGiHzvkiHXvkk9fEUOg|vFCY7egZskyaH-0jwDdQTQ|uxYuSzlDzU-AYGK-uo3RTg|VANy1bANREmh2DLujlaKGQ|CyO7saVd8kWHwzs3MaLe5w|71tayZrmnk6E8E-z8IWeIw|5H2xaOfutEyeZ755pY0mmA|uPHRl846Xk-SG-HEmITW-w|DF4Ub1Vqg0GSBIGWYJgCGw|-LfywKHkMEqRb1WVNSkcxg|AgO2o_kbG0GVTNVNT0233A|R6oXNiKgIkqjGhp-42inxg|WI1S5jo5-kOb5bgoNSb8Hg|MVsyPrQ8iUa_M6DJ4IR0CQ|6iDQYEk4yUa6B_-z49KYHA|MznlCejhZUqq_rxf4xrmwg|kG4B-4Pt6ECSxm14f3FWiA|T9GJpphYiUGYVgw7lmkmDA" | split: "|" -%}
|
||||
{%- assign series_ids = "fpgE1kmfr0-xNBMbxUWxMA|FP7IiNghSEeZLBW21kkAgw|ca1OWFTvMU2H-lHpjsm5MQ|aK4djQBz_UCObjyPq5At_A" | split: "|" -%}
|
||||
{%- assign series_details = "FP7IiNghSEeZLBW21kkAgw,Advent Readings,2019/advent-readings.html|aK4djQBz_UCObjyPq5At_A,Twisted Scripture,2017/twisted-scripture.html|ca1OWFTvMU2H-lHpjsm5MQ,The “3:16”s of the New Testament,2007/the-316s-of-the-new-testament.html" | split: "|" -%}
|
|
@ -1,154 +0,0 @@
|
|||
{% include_template "_books" %}
|
||||
<div class="content">
|
||||
{%- if is_category or is_tag %}
|
||||
<h1 class="index-title">{{ page_title }}</h1>
|
||||
{%- if is_category %}
|
||||
{%- assign cat = categories | where: "slug", slug | first -%}
|
||||
{%- if cat.description %}<h2 class="index-title">{{ cat.description.value }}</h2>{% endif -%}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{% for post in model.posts %}
|
||||
<article class="item">
|
||||
<h1 class="item-heading">
|
||||
<a href="{{ post.permalink | relative_link }}"
|
||||
title="Permanent Link to “{{ post.title | strip_html | escape_once }}”">
|
||||
{{ post.title }}
|
||||
</a>
|
||||
</h1>
|
||||
<p class="item-meta">
|
||||
<i class="fa fa-calendar" title="Date"></i> {{ post.published_on | date: "dddd, MMMM d, yyyy" }}
|
||||
{% if logged_on %} • <a href="{{ post | edit_post_link }}">Edit Post</a>{% endif %}
|
||||
</p>
|
||||
{%- assign media = post.metadata | value: "episode_media_file" -%}
|
||||
{%- unless media == "-- episode_media_file not found --" %}
|
||||
<aside class="podcast">
|
||||
<p class="text-center"><strong>Listen While<br>You Read</strong></p>
|
||||
<audio controls onplaying="awftw.countPlay('{{ media }}')">
|
||||
<source src="https://files.bitbadger.solutions/devotions/{{ media }}">
|
||||
</audio>
|
||||
<p class="text-center">
|
||||
<a class="dl" href="https://pdcst.click/c/awftw/files.bitbadger.solutions/devotions/{{ media }}" download>
|
||||
<i class="fa fa-download" title="Download Audio"></i>
|
||||
</a>
|
||||
</p>
|
||||
</aside>
|
||||
{%- endunless %}
|
||||
{{ post.text }}
|
||||
</article>
|
||||
{% endfor %}
|
||||
<nav aria-label="pagination">
|
||||
<div>{% if model.newer_link %}<a href="{{ model.newer_link.value }}">« Newer Posts</a>{% endif %}</div>
|
||||
<div>{% if model.older_link %}<a href="{{ model.older_link.value }}">Older Posts »</a>{% endif %}</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="sidebar">
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Author</h4>
|
||||
<p>Daniel is a man who wants to be used of God however He sees fit.</p>
|
||||
<hr class="sidebar-sep">
|
||||
<ul>
|
||||
<li><a href="https://daniel.summershome.org/my-testimony">Daniel’s Testimony</a></li>
|
||||
<li><a href="{{ "2007/about-daniels-weekly-devotions.html" | relative_link }}">About This Site</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Series</h4>
|
||||
{%- for series in series_details %}
|
||||
{% assign parts = series | split: "," %}
|
||||
{% assign cat = categories | where: "id", parts[0] | first %}
|
||||
<h4 class="text-center">{{ cat.name }}</h4>
|
||||
<p class="text-center">
|
||||
<a href="{{ parts[2] | relative_link }}"
|
||||
title="About the series “{{ cat.name | escape_once }}” • A Word from the Word">
|
||||
About the Series
|
||||
</a> •
|
||||
<a href="{{ cat | category_link }}">Read All</a> <small class="count">({{ cat.post_count }})</small>
|
||||
</p>
|
||||
{% unless forloop.last %}<hr class="sidebar-sep">{% endunless %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Books</h4>
|
||||
<p>Each devotion is categorized under the books of the Bible which are referenced within it.</p>
|
||||
<hr class="sidebar-sep">
|
||||
<h4 class="text-center">Old Testament</h4>
|
||||
<p class="text-center">
|
||||
{%- assign cat_id = ot_books | first -%}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
See All
|
||||
</a> <small class="count">({{ cat.post_count }})</small>
|
||||
</p>
|
||||
<ul>
|
||||
{%- assign first_time = true -%}
|
||||
{% for cat_id in ot_books -%}
|
||||
{%- if first_time -%}
|
||||
{%- assign first_time = false -%}
|
||||
{%- else %}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<li>
|
||||
{% if cat.post_count == 0 -%}
|
||||
<span{% if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</span> <small class="count">(0)</small>
|
||||
{%- else -%}
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</a> <small class="count">({{ cat.post_count }})</small>
|
||||
{%- endif %}
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
<hr class="sidebar-sep">
|
||||
<h4 class="text-center">New Testament</h4>
|
||||
<p class="text-center">
|
||||
{%- assign cat_id = nt_books | first -%}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
See All
|
||||
</a> <small class="count">({{ cat.post_count }})</small>
|
||||
</p>
|
||||
<ul>
|
||||
{%- assign first_time = true -%}
|
||||
{%- for cat_id in nt_books -%}
|
||||
{%- if first_time -%}
|
||||
{%- assign first_time = false -%}
|
||||
{%- else %}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<li>
|
||||
{% if cat.post_count == 0 -%}
|
||||
<span{% if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</span> <small class="count">(0)</small>
|
||||
{%- else -%}
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</a> <small class="count">({{ cat.post_count }})</small>
|
||||
{%- endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Topics</h4>
|
||||
<ul>
|
||||
{%- for cat in categories -%}
|
||||
{%- unless ot_books contains cat.id or nt_books contains cat.id or series_ids contains cat.id -%}
|
||||
<li>
|
||||
{%- for it in cat.parent_names %} {% endfor -%}
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</a> <small class="count">({{ cat.post_count }})</small>
|
||||
</li>
|
||||
{% endunless %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
|
@ -1,47 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
{%- if is_home -%}
|
||||
{{ web_log.name }}{% if web_log.subtitle %} | {{ web_log.subtitle.value }}{% endif %}
|
||||
{%- else -%}
|
||||
{{ page_title | strip_html }}{% if page_title and page_title != "" %} » {% endif %}{{ web_log.name }}
|
||||
{%- endif -%}
|
||||
</title>
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css?family=Quicksand|Federo|Istok+Web" as="style">
|
||||
<link rel="preload" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" as="style">
|
||||
<link rel="preload" href="{{ "style.css" | theme_asset }}" as="style">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
|
||||
{% page_head -%}
|
||||
</head>
|
||||
<body {% comment %} hx-boost="true" hx-target="main" hx-indicator="#loadOverlay" hx-swap="innerHTML show:body:top" {% endcomment %}>
|
||||
<header class="site-header">
|
||||
<p class="site-title"><a class="navbar-brand" href="{{ "" | relative_link }}">{{ web_log.name }}</a></p>
|
||||
{%- if web_log.subtitle %}<p class="site-subtitle">{{ web_log.subtitle.value }}</p>{% endif -%}
|
||||
<p class="site-page">
|
||||
<a href="{{ "gods-simple-plan-of-salvation/" | relative_link }}">God’s Simple Plan of Salvation</a>
|
||||
</p>
|
||||
<p class="site-page"><a href="{{ "podcast/" | relative_link }}">Podcast</a></p>
|
||||
</header>
|
||||
{% comment %}<div class="load-overlay" id="loadOverlay"><h1>Loading...</h1></div>{% endcomment %}
|
||||
<main class="container">{{ content }}</main>
|
||||
<footer class="part-1"></footer>
|
||||
<footer class="page-footer">
|
||||
Designed by
|
||||
<a href="https://bitbadger.solutions" title="Building the site you need to ensure your success!" target="_blank"
|
||||
rel="noopener">
|
||||
Bit Badger Solutions
|
||||
</a> • Powered by
|
||||
<a href="https://github.com/bit-badger/myWebLog/tree/v2" target="_blank" rel="noopener">myWebLog</a> •
|
||||
{% if logged_on %}
|
||||
<a href="{{ "admin/dashboard" | relative_link }}">Dashboard</a>
|
||||
{% else %}
|
||||
<a href="{{ "user/log-on" | relative_link }}">Log On</a>
|
||||
{%- endif %}
|
||||
</footer>
|
||||
{% page_foot %}
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
<div class="content">
|
||||
<article class="item">
|
||||
<h1 class="item-heading">{{ page.title }}</h1>
|
||||
{%- if logged_on %}<p class="item-meta"><a href="{{ page | edit_page_link }}">Edit Page</a></p>{% endif %}
|
||||
{{ page.text }}
|
||||
</article>
|
||||
</div>
|
|
@ -1,173 +0,0 @@
|
|||
{% include_template "_books" %}
|
||||
{%- assign post = model.posts | first -%}
|
||||
<div class="content">
|
||||
<article class="item">
|
||||
<h1 class="item-heading">{{ post.title }}</h1>
|
||||
{%- if logged_on %}<p class="item-meta"><a href="{{ post | edit_post_link }}">Edit Post</a></p>{% endif %}
|
||||
{% assign media = post.metadata | value: "episode_media_file" %}
|
||||
{%- unless media == "-- episode_media_file not found --" %}
|
||||
<aside class="podcast">
|
||||
<p class="text-center"><strong>Listen While<br>You Read</strong></p>
|
||||
<audio controls onplaying="awftw.countPlay('{{ media }}')">
|
||||
<source src="https://files.bitbadger.solutions/devotions/{{ media }}">
|
||||
</audio>
|
||||
<p class="text-center">
|
||||
<a class="dl" href="https://pdcst.click/c/awftw/files.bitbadger.solutions/devotions/{{ media }}" download>
|
||||
<i class="fa fa-download" title="Download Audio"></i>
|
||||
</a>
|
||||
</p>
|
||||
</aside>
|
||||
{%- endunless %}
|
||||
{{ post.text }}
|
||||
</article>
|
||||
<nav aria-label="pagination">
|
||||
<div class="nav-previous">
|
||||
{% if model.newer_link %}
|
||||
<span class="post-nav">Previous Post</span><br>
|
||||
<a class="post-nav-title" href="{{ model.newer_link.value | relative_link }}">{{ model.newer_name.value }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="nav-next">
|
||||
{% if model.older_link %}
|
||||
<span class="post-nav">Next Post</span> <br>
|
||||
<a class="post-nav-title" href="{{ model.older_link.value | relative_link }}">{{ model.older_name.value }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="sidebar post-sidebar">
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Date</h4>
|
||||
<div class="date-posted">
|
||||
<i class="fa fa-calendar" title="Date" aria-hidden="true"></i>
|
||||
{{ post.published_on | date: "dddd, MMMM d, yyyy" }}
|
||||
</div>
|
||||
</div>
|
||||
{%- assign has_ot = false -%}
|
||||
{%- for ot_id in ot_books -%}
|
||||
{%- if post.category_ids contains ot_id %}{% assign has_ot = true %}{% endif -%}
|
||||
{%- endfor -%}
|
||||
{%- assign has_nt = false -%}
|
||||
{%- for nt_id in nt_books -%}
|
||||
{%- if post.category_ids contains nt_id %}{% assign has_nt = true %}{% endif -%}
|
||||
{%- endfor -%}
|
||||
{%- if has_ot or has_nt %}
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Scripture</h4>
|
||||
{%- if has_ot %}
|
||||
<ul>
|
||||
<li>
|
||||
{%- assign cat_id = ot_books | first -%}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<i class="fa fa-book" title="Book" aria-hidden="true"></i>
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</a>
|
||||
<ul>
|
||||
{%- assign first_time = true -%}
|
||||
{%- for cat_id in ot_books %}
|
||||
{%- if first_time %}
|
||||
{%- assign first_time = false -%}
|
||||
{%- elsif post.category_ids contains cat_id %}
|
||||
{% assign cat = categories | where: "id", cat_id | first %}
|
||||
<li>
|
||||
<i class="fa fa-book" title="Book" aria-hidden="true"></i>
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</a>
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{%- endif %}
|
||||
{%- if has_nt %}
|
||||
<ul>
|
||||
<li>
|
||||
{%- assign cat_id = nt_books | first -%}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<i class="fa fa-book" title="Book" aria-hidden="true"></i>
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</a>
|
||||
<ul>
|
||||
{%- assign first_time = true -%}
|
||||
{%- for cat_id in nt_books %}
|
||||
{%- if first_time %}
|
||||
{%- assign first_time = false -%}
|
||||
{%- elsif post.category_ids contains cat_id %}
|
||||
{% assign cat = categories | where: "id", cat_id | first %}
|
||||
<li>
|
||||
<i class="fa fa-book" title="Book" aria-hidden="true"></i>
|
||||
<a href="{{ cat | category_link }}"
|
||||
{%- if cat.description %} title="{{ cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ cat.name }}
|
||||
</a>
|
||||
</li>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{%- endif %}
|
||||
{%- assign in_series = false -%}
|
||||
{%- for series_id in series_ids %}
|
||||
{%- if post.category_ids contains series_id -%}
|
||||
{%- assign in_series = true -%}
|
||||
{%- assign series_cat = categories | where: "id", series_id | first -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- if in_series %}
|
||||
<div class="item text-center">
|
||||
<h4 class="item-heading">Series</h4>
|
||||
<a href="{{ series_cat | category_link }}"
|
||||
{% if series_cat.description %} title="{{ series_cat.description.value | escape_once }}"{% endif %}>
|
||||
{{ series_cat.name }}
|
||||
</a>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{%- assign has_topics = false -%}
|
||||
{% for cat_id in post.category_ids -%}
|
||||
{%- unless ot_books contains cat_id or nt_books contains cat_id or series_ids contains cat_id -%}
|
||||
{% assign has_topics = true -%}
|
||||
{%- endunless -%}
|
||||
{% endfor %}
|
||||
{%- if has_topics %}
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Topics</h4>
|
||||
<ul>
|
||||
{%- for cat_id in post.category_ids %}
|
||||
{% unless ot_books contains cat_id or nt_books contains cat_id or series_ids contains cat_id %}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<li>
|
||||
<i class="fa fa-folder-open-o" title="Category" aria-hidden="true"></i>
|
||||
<a href="{{ cat | category_link }}" rel="tag" title="Categorized under {{ cat.name | escape }}">
|
||||
{{ cat.name }}
|
||||
</a>
|
||||
</li>
|
||||
{% endunless %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{%- assign tag_count = post.tags | size -%}
|
||||
{%- if tag_count > 0 %}
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Tags</h4>
|
||||
<ul>
|
||||
{%- for tag in post.tags %}
|
||||
<li>
|
||||
<a href="{{ tag | tag_link }}" title="Tagged “{{ tag }}”">
|
||||
<i class="fa fa-tag" aria-hidden="true"></i> {{ tag }}
|
||||
</a>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{%- endif %}
|
||||
</div>
|
|
@ -1,131 +0,0 @@
|
|||
<div class="home">
|
||||
<article class="content auto">
|
||||
{{ page.text }}
|
||||
{% if logged_on -%}
|
||||
<p><small><a hx-boost="false" href="{{ page | edit_page_link }}">Edit This Page</a></small></p>
|
||||
{% endif %}
|
||||
</article>
|
||||
<aside class="app-sidebar">
|
||||
<div>
|
||||
<div class="app-sidebar-head">Web Sites and Applications</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>PrayerTracker</strong><br>
|
||||
<a href="{{ "solutions/prayer-tracker" | relative_link }}"
|
||||
title="About PrayerTracker • Bit Badger Solutions">
|
||||
About
|
||||
</a> •
|
||||
<a href="https://prayer.bitbadger.solutions" title="PrayerTracker" target="_blank" rel="noopener">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">
|
||||
A prayer request tracking website (Free for any church or Sunday School class!)
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>myPrayerJournal</strong><br>
|
||||
<a href="{{ "solutions/my-prayer-journal" | relative_link }}"
|
||||
title="About myPrayerJournal • Bit Badger Solutions">
|
||||
About
|
||||
</a> •
|
||||
<a href="https://prayerjournal.me" title="myPrayerJournal" target="_blank" rel="noopener">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">Minimalist personal prayer journal</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>Linux Resources</strong><br>
|
||||
<a href="https://blog.bitbadger.solutions/linux/" title="Linux Resources" target="_blank" rel="noopener">
|
||||
Visit
|
||||
</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">Handy information for Linux folks</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="app-sidebar-head">WordPress</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>Futility Closet</strong><br>
|
||||
<a href="{{ "solutions/futility-closet" | relative_link }}"
|
||||
title="About Futility Closet • Bit Badger Solutions">
|
||||
About
|
||||
</a> •
|
||||
<a href="https://www.futilitycloset.com" title="Futility Closet" target="_blank" rel="noopener">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">An idler’s miscellany of compendious amusements</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>Mindy Mackenzie</strong><br>
|
||||
<a href="{{ "solutions/mindy-mackenzie" | relative_link }}"
|
||||
title="About Mindy Mackenzie • Bit Badger Solutions">
|
||||
About
|
||||
</a> •
|
||||
<a href="https://mindymackenzie.com" title="Mindy Mackenzie" target="_blank" rel="noopener">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description"><em>WSJ</em>-best-selling author of <em>The Courage Solution</em></p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>Riehl World News</strong><br>
|
||||
<a href="{{ "solutions/riehl-world-news" | relative_link }}"
|
||||
title="About Riehl World News • Bit Badger Solutions">
|
||||
About
|
||||
</a> •
|
||||
<a href="http://riehlworldview.com" title="Riehl World News" target="_blank" rel="noopener">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">Riehl news for real people</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="app-sidebar-head">Static Sites</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>Bay Vista Baptist Church</strong><br>
|
||||
<a href="{{ "solutions/bay-vista" | relative_link }}"
|
||||
title="About Bay Vista Baptist Church • Bit Badger Solutions">
|
||||
About
|
||||
</a> •
|
||||
<a href="https://bayvista.org" title="Bay Vista Baptist Church" target="_blank" rel="noopener">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">Biloxi, Mississippi</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<div class="app-sidebar-head">myWebLog</div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>The Bit Badger Blog</strong><br>
|
||||
<a href="{{ "solutions/tech-blog" | relative_link }}"
|
||||
title="About The Bit Badger Blog • Bit Badger Solutions">
|
||||
About
|
||||
</a> •
|
||||
<a href="https://bitbadger.solutions/blog" title="The Bit Badger Blog" target="_blank" rel="noopener">
|
||||
Visit
|
||||
</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">Technical information (“geek stuff”) from Bit Badger Solutions</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="app-sidebar-head">Personal</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>Daniel J. Summers</strong><br>
|
||||
<a href="https://daniel.summershome.org" title="Daniel J. Summers" target="_blank" rel="noopener">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">Daniel’s personal blog</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="app-sidebar-name">
|
||||
<strong>A Word from the Word</strong><br>
|
||||
<a href="https://devotions.summershome.org" title="A Word from the Word" target="_blank" rel="noopener">
|
||||
Visit
|
||||
</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description">Devotions by Daniel</p>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ page_title }} » Bit Badger Solutions</title>
|
||||
</head>
|
||||
<body>
|
||||
{{ content }}
|
||||
</body>
|
||||
</html>
|
|
@ -1,49 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>{{ page_title }} » Bit Badger Solutions</title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Oswald|Raleway">
|
||||
{% page_head -%}
|
||||
</head>
|
||||
<body hx-boost="true" hx-target="main" hx-indicator="#loadOverlay" hx-swap="innerHTML show:body:top">
|
||||
<header class="site-header">
|
||||
<div class="header-logo">
|
||||
<a href="{{ "" | relative_link }}">
|
||||
<img src="{{ "bitbadger.png" | theme_asset }}"
|
||||
alt="A cartoon badger looking at a computer screen, with his paw on a mouse"
|
||||
title="Bit Badger Solutions">
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-title"><a href="{{ "" | relative_link }}">Bit Badger Solutions</a></div>
|
||||
<div class="header-spacer"> </div>
|
||||
<div class="header-social">
|
||||
<a href="https://twitter.com/Bit_Badger" title="Bit_Badger on Twitter" target="_blank">
|
||||
<img src="{{ "twitter.png" | theme_asset }}" alt="Twitter">
|
||||
</a>
|
||||
<a href="https://www.facebook.com/bitbadger.solutions" title="Bit Badger Solutions on Facebook" target="_blank">
|
||||
<img src="{{ "facebook.png" | theme_asset }}" alt="Facebook">
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="load-overlay" id="loadOverlay"><h1>Loading…</h1></div>
|
||||
<main>{{ content }}</main>
|
||||
<footer hx-boost="false">
|
||||
<div>
|
||||
<small>
|
||||
{% if logged_on -%}
|
||||
<a href="{{ "admin/dashboard" | relative_link }}">Dashboard</a> ~
|
||||
<a href="{{ "user/log-off" | relative_link }}">Log Off</a>
|
||||
{% else %}
|
||||
<a href="{{ "user/log-on" | relative_link }}">Log On</a>
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
<div class="footer-by">
|
||||
A <strong><a href="{{ "" | relative_link }}">Bit Badger Solutions</a></strong> original design
|
||||
</div>
|
||||
</footer>
|
||||
{% page_foot %}
|
||||
</body>
|
||||
</html>
|
|
@ -1,33 +0,0 @@
|
|||
<article class="content auto">
|
||||
{%- assign parts = page.title | split: ' » ' -%}
|
||||
{%- assign parts_count = parts | size -%}
|
||||
<h1 class="project-title">
|
||||
{% if parts_count == 1 -%}
|
||||
{{ page.title }}<br>
|
||||
<small><small>
|
||||
<a href="https://github.com/bit-badger/{{ page.title }}" target="_blank" rel="noopener"
|
||||
title="{{ parts[0] }} on GitHub">
|
||||
View on GitHub
|
||||
</a>
|
||||
{% if logged_on %} • <a hx-boost="false" href="{{ page | edit_page_link }}">Edit Page</a>{% endif %}
|
||||
</small></small>
|
||||
{%- else -%}
|
||||
<small><small>
|
||||
<a href="." title="{{ parts[0] }} Home">{{ parts[0] }}</a>
|
||||
{% if logged_on %} • <a hx-boost="false" href="{{ page | edit_page_link }}">Edit</a>{% endif %}
|
||||
</small></small>
|
||||
<br>
|
||||
{{ parts[1] }}
|
||||
{%- endif %}
|
||||
</h1>
|
||||
{{ page.text }}
|
||||
{% if parts_count > 1 -%}
|
||||
<p class="project-footer">
|
||||
<a href="." title="{{ parts[0] }} Home">« {{ parts[0] }} Home</a>
|
||||
<a href="https://github.com/bit-badger/{{ parts[0] }}" target="_blank" rel="noopener"
|
||||
title="{{ parts[0] }} on GitHub">
|
||||
View GitHub Repo
|
||||
</a>
|
||||
</p>
|
||||
{%- endif %}
|
||||
</article>
|
|
@ -1,8 +0,0 @@
|
|||
<article class="content auto">
|
||||
<h1>{{ page.title }}</h1>
|
||||
{{ page.text }}
|
||||
<p><br><a href="{{ "" | relative_link }}" title="Home">« Home</a></p>
|
||||
{% if logged_on -%}
|
||||
<p><small><a hx-boost="false" href="{{ page | edit_page_link }}">Edit This Page</a></small></p>
|
||||
{% endif %}
|
||||
</article>
|
|
@ -1,112 +0,0 @@
|
|||
<h1 class="solution-header">
|
||||
{{ page.title }}<br>
|
||||
<small><small>
|
||||
{%- assign url = page.metadata | value: "url" -%}
|
||||
{%- assign no_link = page.metadata | value: "no_link" -%}
|
||||
{%- assign archive = page.metadata | where: "name", "archive_url" | size -%}
|
||||
{% if no_link == "true" -%}
|
||||
{{ url }}
|
||||
{%- else -%}
|
||||
<a href="{{ url }}" target="_blank" rel="noopener">{{ url }}</a>
|
||||
{%- endif %}
|
||||
{% if archive > 0 -%}
|
||||
|
||||
<a href="{{ page.metadata | value: "archive_url" }}" target="_blank" rel="noopener"><small>(Archive)</small></a>
|
||||
{%- endif %}
|
||||
</small></small>
|
||||
</h1>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<aside>
|
||||
{%- capture screen_url %}screenshots/{{ page.permalink | split: "/" | last }}.png{% endcapture -%}
|
||||
<img src="{{ screen_url | theme_asset }}" alt="Screen shot of {{ page.title | escape }}">
|
||||
</aside>
|
||||
{{ page.text }}
|
||||
{%- assign curr_tech = page.metadata | where: "name", "tech" -%}
|
||||
{%- assign past_tech = page.metadata | where: "name", "past_tech" -%}
|
||||
{%- assign curr_count = curr_tech | size -%}
|
||||
{%- assign past_count = past_tech | size -%}
|
||||
{% if curr_count > 0 or past_count > 0 -%}
|
||||
{% comment %} TODO / WIP
|
||||
{% capture all_links -%}
|
||||
ASP.NET MVC|https://dotnet.microsoft.com/apps/aspnet/mvc,
|
||||
Azure|https://azure.microsoft.com/,
|
||||
BlogEngine.NET|http://www.dotnetblogengine.net/,
|
||||
Database Abstraction|https://github.com/danieljsummers/DatabaseAbstraction,
|
||||
Digital Ocean|https://www.digitalocean.com/,
|
||||
Giraffe|https://github.com/giraffe-fsharp/Giraffe,
|
||||
GitHub|https://github.com/,
|
||||
GitHub Pages|https://pages.github.com/,
|
||||
Hexo|https://hexo.io/,
|
||||
Hugo|https://gohugo.io/,
|
||||
Jekyll|https://jekyllrb.com/,
|
||||
MongoDB|https://www.mongodb.com/,
|
||||
MySQL|https://www.mysql.com/,
|
||||
myWebLog|https://github.com/bit-badger/myWebLog,
|
||||
nginx|http://nginx.org/,
|
||||
Orchard|https://orchardproject.net/,
|
||||
PHP|https://www.php.net/,
|
||||
PostgreSQL|https://www.postgresql.org/,
|
||||
Rackspace Cloud|https://www.rackspace.com/cloud,
|
||||
RavenDB|https://ravendb.net/,
|
||||
RethinkDB|https://rethinkdb.com/,
|
||||
SQL Server|https://www.microsoft.com/en-us/sql-server/,
|
||||
Vue.js|https://vuejs.org/,
|
||||
WordPress|https://wordpress.org
|
||||
{%- endcapture %}
|
||||
{% endcomment %}
|
||||
<section>
|
||||
<h3 onclick="toggle('techStack')">
|
||||
The Technology Stack<span id="techStackArrow" class="arrow">▼</span>
|
||||
</h3>
|
||||
<div id="techStack" class="collapse-panel hidden">
|
||||
{% if curr_count > 0 -%}
|
||||
{% if past_count > 0 -%}
|
||||
<p><small><strong>Current:</strong></small></p>
|
||||
{%- endif %}
|
||||
<ul>
|
||||
{% for curr in curr_tech -%}
|
||||
{%- assign tech = curr.value | split: "|" -%}
|
||||
<li>
|
||||
{% comment %} <a v-if="hasLink(tech[0])" :href="techLinks[tech[0]]" target="_blank">{{ tech[0] }}</a> {% endcomment %}
|
||||
{{ tech[0] }} for {{ tech[1] }}
|
||||
</li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{%- endif %}
|
||||
{% if past_count > 0 -%}
|
||||
{% if curr_count > 0 %}
|
||||
<p><small><strong>Previously:</strong></small></p>
|
||||
{% endif %}
|
||||
<ul>
|
||||
{% for past in past_tech -%}
|
||||
{%- assign tech = past.value | split: "|" -%}
|
||||
<li>
|
||||
{% comment %} <a v-if="hasLink(tech[0])" :href="techLinks[tech[0]]" target="_blank">{{ tech[0] }}</a> {% endcomment %}
|
||||
{{ tech[0] }} for {{ tech[1] }}
|
||||
</li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{%- endif %}
|
||||
<p><br><a href="{{ "solutions" | relative_link }}">« Back to All Solutions</a></p>
|
||||
{% if logged_on -%}
|
||||
<p><small><a hx-boost="false" href="{{ page | edit_page_link }}">Edit This Page</a></small></p>
|
||||
{% endif %}
|
||||
</article>
|
||||
</div>
|
||||
<script>
|
||||
function toggle(id) {
|
||||
const section = document.getElementById(id)
|
||||
const arrow = document.getElementById(`${id}Arrow`)
|
||||
if (section.className.indexOf("shown") === -1) {
|
||||
section.className = `${section.className} shown`
|
||||
arrow.innerHTML = "▲"
|
||||
} else {
|
||||
section.className = section.className.replace(" shown", "")
|
||||
arrow.innerHTML = "▼"
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,84 +0,0 @@
|
|||
<div class="content">
|
||||
{% if is_category or is_tag %}
|
||||
<h2>{{ page_title }}</h2>
|
||||
{%- if subtitle %}
|
||||
<p>{{ subtitle }}</p>
|
||||
{%- endif %}
|
||||
{% endif %}
|
||||
{%- for post in model.posts %}
|
||||
<article class="item">
|
||||
<h1 class="item-heading">
|
||||
<a href="{{ post | relative_link }}"
|
||||
title="Permanent Link to "{{ post.title | strip_html | escape }}"">
|
||||
{{ post.title }}
|
||||
</a>
|
||||
</h1>
|
||||
<h4 class="post-meta">
|
||||
<span title="Published On">
|
||||
<i class="fa fa-calendar"></i> {{ post.published_on | date: "dddd, MMMM d, yyyy" }}
|
||||
</span>
|
||||
<span title="Published At">
|
||||
<i class="fa fa-clock-o"></i> {{ post.published_on | date: "h:mm tt" | downcase }}
|
||||
</span>
|
||||
<span title="Author">
|
||||
<i class="fa fa-user"></i> {{ model.authors | value: post.author_id }}
|
||||
</span>
|
||||
{% if logged_on %}
|
||||
<span>
|
||||
<a hx-boost="false" href="{{ post | edit_post_link }}"><i class="fa fa-pencil-square-o"></i> Edit Post</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
</h4>
|
||||
{{ post.text }}
|
||||
</article>
|
||||
{%- endfor %}
|
||||
<nav aria-label="pagination">
|
||||
<ul class="pager">
|
||||
{% if model.newer_link -%}
|
||||
<li class="previous item"><a href="{{ model.newer_link.value }}">« Newer Posts</a></li>
|
||||
{%- else -%}
|
||||
<li></li>
|
||||
{% endif %}
|
||||
{% if model.older_link -%}
|
||||
<li class="next item"><a href="{{ model.older_link.value }}">Older Posts »</a></li>
|
||||
{%- endif -%}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="sidebar">
|
||||
<br>
|
||||
<div class="item votd-item">
|
||||
<h4 class="item-heading votd-heading">Verse of the Day</h4>
|
||||
<div>
|
||||
<span class="verse"></span> –
|
||||
<a class="votd-reference" target="_blank" rel="noopener"></a>
|
||||
<small> <a class="version-link" target="_blank" rel="noopener">(ESV)</a></small><br>
|
||||
<div class="votd-credits">
|
||||
<small>Powered by <a href="https://biblegateway.com" target="_blank" rel="noopener">Bible Gateway</a></small>
|
||||
</div>
|
||||
<script src="https://www.biblegateway.com/votd/get/?format=json&version=ESV&callback=djs.displayVotd">
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">#VoteGold</h4>
|
||||
<div class="text-center">
|
||||
<p><em>
|
||||
(Don't blame me;<br>
|
||||
I voted for <a href="https://jo20.com/" title="Jorgensen / Cohen 2020" target="_blank" rel="noopener">Jo</a>)
|
||||
</em></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Categories</h4>
|
||||
<ul class="cat-list">
|
||||
{% for cat in categories -%}
|
||||
{%- assign indent = cat.parent_names | size -%}
|
||||
<li class="cat-list-item"{% if indent > 0 %} style="padding-left:{{ indent }}rem;"{% endif %}>
|
||||
<a href="{{ cat | category_link }}" class="cat-list-link">{{ cat.name }}</a>
|
||||
<span class="cat-list-count">{{ cat.post_count }}</span>
|
||||
</li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>
|
||||
{%- if is_home -%}
|
||||
{{ web_log.name }}{% if web_log.subtitle %} | {{ web_log.subtitle.value }}{% endif %}
|
||||
{%- else -%}
|
||||
{{ page_title | strip_html }}{% if page_title and page_title != "" %} » {% endif %}{{ web_log.name }}
|
||||
{%- endif -%}
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
{{ content }}
|
||||
</body>
|
||||
</html>
|
|
@ -1,151 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
{%- if is_home -%}
|
||||
{{ web_log.name }}{% if web_log.subtitle %} | {{ web_log.subtitle.value }}{% endif %}
|
||||
{%- else -%}
|
||||
{{ page_title | strip_html }}{% if page_title and page_title != "" %} » {% endif %}{{ web_log.name }}
|
||||
{%- endif -%}
|
||||
</title>
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css?family=Quicksand|Oswald" as="style">
|
||||
<link rel="preload" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" as="style">
|
||||
<link rel="preload" href="{{ "style.css" | theme_asset }}" as="style">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
|
||||
<script src="{{ "djs.js" | theme_asset }}"></script>
|
||||
{% page_head -%}
|
||||
</head>
|
||||
<body hx-boost="true" hx-target="main" hx-indicator="#loadOverlay" hx-swap="innerHTML show:body:top">
|
||||
<nav class="site-header" role="navigation">
|
||||
<p><a class="nav-home" href="{{ "" | relative_link }}">{{ web_log.name }}</a></p>
|
||||
{%- if web_log.subtitle %}<p>{{ web_log.subtitle.value }}</p>{% endif -%}
|
||||
<p class="nav-spacer"></p>
|
||||
{%- for page in page_list %}
|
||||
<p class="desktop"><a href="{{ page | relative_link }}">{{ page.title }}</a></p>
|
||||
{%- endfor %}
|
||||
<p class="desktop">
|
||||
<a href="https://devotions.summershome.org" target="_blank" rel="noopener">A Word from the Word</a>
|
||||
</p>
|
||||
<p class="mobile"><a href="#links">Site Links</a></p>
|
||||
</nav>
|
||||
<div class="load-overlay" id="loadOverlay"><h1>Loading...</h1></div>
|
||||
<main>{{ content }}</main>
|
||||
<footer class="part-1" id="links">
|
||||
{%- for page in page_list %}
|
||||
<p class="mobile"><a href="{{ page | relative_link }}">{{ page.title }}</a></p>
|
||||
{%- endfor %}
|
||||
<p class="mobile">
|
||||
<a href="https://devotions.summershome.org" target="_blank" rel="noopener">A Word from the Word</a>
|
||||
</p>
|
||||
</footer>
|
||||
<footer class="part-2">
|
||||
<div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Tip Jar</h4>
|
||||
<div class="text-center">
|
||||
<p style="padding: 5px 0;">What do we holler?<br>“Thanks for the dollar!”</p>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="encrypted"
|
||||
value="-----BEGIN PKCS7-----MIIHXwYJKoZIhvcNAQcEoIIHUDCCB0wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYCdeo4jz/VlsdAgHXG/9uV7zVyd+OWxLhPx/nGdCcANMelbjAUPFj7a9/cisuUG0hyH//qJWdOptVIjKrWrcyC6fNZxqPezHfmw7oNogLmMpVmpT771cGD4YkrB/okzs8KyDBGxJ/HW9kXXoQtZXFmz/Pu9Z9XQSAtFw5e4qmoF/DELMAkGBSsOAwIaBQAwgdwGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIJlQtvH21m3CAgbhQUNrfjKQIQuNDYkPZH7BUhnjpmratPAdk18397qsJ7y/loyL64E8u8G8AHo6T+uA+ANibr5h2EypKbcYaFQKjBg1o/jdDcRaznIySw6d8uzOZMS4U/lSeaWKH3I5H2LYzfBO9upEhnBDJt5Hxns1rSKnkC+WOrfdJJdgSTXIsiVKfarXRQnm+AeFeXlgiwAv+2S3K+SgGZuEeDxsgMpo2lyYFJmE1xcjMeHtCU9P6lum8VCKEpXaMoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTIwNjE1MDA1MjMxWjAjBgkqhkiG9w0BCQQxFgQUe9ggMne5iX9doWN/3fDOuOmLgPswDQYJKoZIhvcNAQEBBQAEgYAphf2/hGBj64tOF4Q25S7rf2e7VO6aUHmT7oimydTWVKg3tWK0avKTuG6OS5GMw8gVv2GSrqHLz4KPBdjEDKu3y2WwrfNYaMKeQU1eRPquE4C+f6xcEf5RxqelUHoPUjiU46grnu51MPl+jQf3PERmbkK3N0hOax8QBx+N7gR1mQ==-----END PKCS7-----">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" style="border:0;"
|
||||
name="submit" alt="PayPal - The safer, easier way to pay online!">
|
||||
<img src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" alt="" style="border:0;" width="1"
|
||||
height="1">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Let’s Go Geocaching</h4>
|
||||
<div class="text-center">
|
||||
<a href="https://www.geocaching.com/guide/" title="What Is Geocaching?" target="_blank" rel="noopener">
|
||||
<img src="https://img.geocaching.com/stats/img.aspx?txt=I+am+the+search+engine!&uid=61a3c13b-9dbb-41d2-a695-9e3432d4d5ea"
|
||||
alt="My Geocaching Stats" title="What Is Geocaching?" style="border:0;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Tennessee Football</h4>
|
||||
<div class="football-panel">
|
||||
<span>
|
||||
<a href="https://utsports.com" style="background:none;padding:0;" target="_blank" rel="noopener">
|
||||
<img src="{{ "tennessee.png" | theme_asset }}" alt="T" title="Tennessee Sports" style="border:0;"
|
||||
width="75px">
|
||||
</a>
|
||||
</span>
|
||||
<div>
|
||||
2021 Season — <strong>NR</strong><br>
|
||||
<small>
|
||||
(7-6 • 4-4 SEC/3<sup>rd</sup> East)<br><br>
|
||||
Last — L* (45-48) vs. Purdue<br>
|
||||
<em>Music City Bowl</em>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Colorado State Football</h4>
|
||||
<div class="football-panel">
|
||||
<span>
|
||||
<a href="https://csurams.com" style="background:none;padding:0;" target="_blank" rel="noopener">
|
||||
<img src="{{ "csurams.png" | theme_asset }}" alt="CSU Rams Logo"
|
||||
title="Colorado State Sports" style="border:0;" height="75px" width="75px">
|
||||
</a>
|
||||
</span>
|
||||
<div>
|
||||
2021 Season — <strong>NR</strong><br>
|
||||
<small>
|
||||
(3-9 • 2-6 MWC/5<sup>th</sup> Mountain)<br><br>
|
||||
Last — L (10-52) at Nevada
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="item">
|
||||
<h4 class="item-heading">Some Other Places to Find Me</h4>
|
||||
<div class="text-center">
|
||||
<a class="twitter-timeline" href="https://twitter.com/DanJSum" data-height="300">Tweets by DanJSum</a>
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
<br><br>
|
||||
<a href="https://www.facebook.com/daniel.j.summers" title="Daniel J. Summers’s Facebook profile">
|
||||
<img src="https://badge.facebook.com/badge/1270539383.37.619606444.png" style="border:0;"
|
||||
alt="Daniel J. Summers’s Facebook profile">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<footer class="part-3">
|
||||
<div class="pull-left">
|
||||
<a rel="license noopener" href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank">
|
||||
<img src="https://licensebuttons.net/l/by-nc/4.0/88x31.png" alt="Creative Commons License"
|
||||
style="border-width:0;">
|
||||
</a>
|
||||
</div>
|
||||
<div class="copy" hx-boost="false">
|
||||
Licensed by the
|
||||
<a rel="license noopener" href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank">
|
||||
Creative Commons Attribution-NonCommercial 4.0 International License
|
||||
</a><br>
|
||||
Designed by
|
||||
<a href="https://bitbadger.solutions" title="Building the site you need to ensure your success!">
|
||||
Bit Badger Solutions
|
||||
</a>
|
||||
• Powered by <a href="https://github.com/bit-badger/myWebLog/tree/v2">myWebLog</a> •
|
||||
{% if logged_on %}
|
||||
<a href="{{ "admin/dashboard" | relative_link }}">Dashboard</a>
|
||||
{% else %}
|
||||
<a href="{{ "user/log-on" | relative_link }}">Log On</a>
|
||||
{%- endif %}
|
||||
</div>
|
||||
</footer>
|
||||
{% page_foot %}
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
<div class="content single">
|
||||
<article class="item">
|
||||
<h1 class="item-heading">{{ page.title }}</h1>
|
||||
{{ page.text }}
|
||||
</article>
|
||||
</div>
|
|
@ -1,77 +0,0 @@
|
|||
{%- assign post = model.posts | first -%}
|
||||
<div class="content single">
|
||||
<article class="item">
|
||||
<h1 class="item-heading">{{ post.title }}</h1>
|
||||
<h4 class="post-meta">
|
||||
{% if post.published_on -%}
|
||||
<span title="Published On">
|
||||
<i class="fa fa-calendar"></i> {{ post.published_on | date: "dddd, MMMM d, yyyy" }}
|
||||
</span>
|
||||
<span title="Published At">
|
||||
<i class="fa fa-clock-o"></i> {{ post.published_on | date: "h:mm tt" | downcase }}
|
||||
</span>
|
||||
{%- else -%}
|
||||
<span>**DRAFT**</span>
|
||||
{% endif %}
|
||||
<span title="Author"><i class="fa fa-user"></i> {{ model.authors | value: post.author_id }}</span>
|
||||
{% if logged_on %}
|
||||
<span>
|
||||
<a hx-boost="false" href="{{ post | edit_post_link }}">
|
||||
<i class="fa fa-pencil-square-o"></i> Edit Post
|
||||
</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
</h4>
|
||||
<div>{{ post.text }}</div>
|
||||
{%- assign cat_count = post.category_ids | size -%}
|
||||
{% if cat_count > 0 -%}
|
||||
<h4>
|
||||
Categorized
|
||||
{% for cat_id in post.category_ids -%}
|
||||
{% assign cat = categories | where: "id", cat_id | first %}
|
||||
<span class="no-wrap">
|
||||
<i class="fa fa-folder-open-o" title="Category"></i>
|
||||
<a href="{{ cat | category_link }}" title="Categorized under “{{ cat.name | escape }}”">
|
||||
{{ cat.name }}
|
||||
</a>
|
||||
</span>
|
||||
{%- endfor %}
|
||||
</h4>
|
||||
{%- endif %}
|
||||
{%- assign tag_count = post.tags | size -%}
|
||||
{% if tag_count > 0 -%}
|
||||
<h4>
|
||||
Tagged
|
||||
{% for tag in post.tags %}
|
||||
<span class="no-wrap">
|
||||
<a href="{{ tag | tag_link }}" title="Posts tagged “{{ tag | escape }}”" rel="tag">
|
||||
<i class="fa fa-tag"></i> {{ tag }}
|
||||
</a>
|
||||
</span>
|
||||
{%- endfor %}
|
||||
</h4>
|
||||
{%- endif %}
|
||||
</article>
|
||||
<div>
|
||||
<nav aria-label="pagination">
|
||||
<ul class="pager">
|
||||
{% if model.newer_link -%}
|
||||
<li class="previous item">
|
||||
<h4 class="item-heading">
|
||||
<a href="{{ model.newer_link.value | relative_link }}">«</a> Previous Post
|
||||
</h4>
|
||||
<a href="{{ model.newer_link.value | relative_link }}">{{ model.newer_name.value }}</a>
|
||||
</li>
|
||||
{%- else -%}
|
||||
<li></li>
|
||||
{% endif %}
|
||||
{% if model.older_link -%}
|
||||
<li class="next item">
|
||||
<h4 class="item-heading">Next Post <a href="{{ model.older_link.value | relative_ling }}">»</a></h4>
|
||||
<a href="{{ model.older_link.value | relative_link }}">{{ model.older_name.value }}</a>
|
||||
</li>
|
||||
{%- endif -%}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
|
@ -1,56 +0,0 @@
|
|||
{% if is_category or is_tag %}
|
||||
<h1>{{ page_title }}</h1>
|
||||
{%- if subtitle %}
|
||||
<p>{{ subtitle }}</p>
|
||||
{%- endif %}
|
||||
{% endif %}
|
||||
{%- for post in model.posts %}
|
||||
<article class="auto">
|
||||
<div>
|
||||
<h1 class="home-title">
|
||||
<small class="home-lead">{{ post.published_on | date: "dddd, MMMM d, yyyy" }}</small><br>
|
||||
|
||||
<a href="{{ post | relative_link }}"
|
||||
id="{{ post.title | strip_html | downcase | replace: " ", "-" | replace: ":", "" }}"
|
||||
title="Permanent Link to "{{ post.title | strip_html | escape }}"">
|
||||
{{ post.title }}
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="entry-content">{{ post.text }}</div>
|
||||
{%- assign cat_count = post.category_ids | size -%}
|
||||
{%- if cat_count > 0 %}
|
||||
<small>
|
||||
Categorized under
|
||||
{% for cat_id in post.category_ids -%}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<a href="{{ cat | category_link }}" title="Categorized under {{ cat.name | strip_html | escape }}"
|
||||
rel="tag">{{ cat.name }}</a>{% unless forloop.last %}, {% endunless %}
|
||||
{%- endfor %}
|
||||
</small><br>
|
||||
{%- endif %}
|
||||
{%- assign tag_count = post.tags | size -%}
|
||||
{%- if tag_count > 0 %}
|
||||
<small>
|
||||
Tagged
|
||||
{% for tag in post.tags -%}
|
||||
<a href="{{ tag | tag_link }}" title="Tagged “{{ tag | escape }}”"
|
||||
rel="tag">{{ tag }}</a>{% unless forloop.last %}, {% endunless %}
|
||||
{%- endfor %}
|
||||
</small><br>
|
||||
{%- endif %}
|
||||
{%- if logged_on %}<small><a hx-boost="false" href="{{ post | edit_post_link }}">Edit Post</a></small>{% endif %}
|
||||
</article>
|
||||
{%- endfor %}
|
||||
<div class="bottom-nav" role="navigation">
|
||||
<div class="nav-previous">
|
||||
{% if model.newer_link -%}
|
||||
<a href="{{ model.newer_link.value }}">« Newer Posts</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="nav-next">
|
||||
{% if model.older_link -%}
|
||||
<a href="{{ model.older_link.value }}">Older Posts »</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
|
@ -1,14 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>
|
||||
{%- if is_home -%}
|
||||
{{ web_log.name }}{% if web_log.subtitle %} | {{ web_log.subtitle.value }}{% endif %}
|
||||
{%- else -%}
|
||||
{{ page_title | strip_html }}{% if page_title and page_title != "" %} » {% endif %}{{ web_log.name }}
|
||||
{%- endif -%}
|
||||
</title>
|
||||
</head>
|
||||
<body>{{ content }}</body>
|
||||
</html>
|
|
@ -1,92 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
{%- if is_home -%}
|
||||
{{ web_log.name }}{% if web_log.subtitle %} | {{ web_log.subtitle.value }}{% endif %}
|
||||
{%- else -%}
|
||||
{{ page_title | strip_html }}{% if page_title and page_title != "" %} » {% endif %}{{ web_log.name }}
|
||||
{%- endif -%}
|
||||
</title>
|
||||
{% page_head -%}
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header" id="top">
|
||||
<div class="header-logo">
|
||||
<a href="{{ "" | relative_link }}" hx-boost="true" hx-target="#content" hx-swap="innerHTML show:#top:top"
|
||||
hx-indicator="#loadOverlay">
|
||||
<img src="{{ "img/bitbadger.png" | theme_asset }}"
|
||||
alt="A cartoon badger looking at a computer screen, with his paw on a mouse"
|
||||
title="Bit Badger Solutions">
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-title">
|
||||
<a href="{{ "" | relative_link }}" hx-boost="true" hx-target="#content" hx-swap="innerHTML show:#top:top"
|
||||
hx-indicator="#loadOverlay">
|
||||
The Bit Badger Blog
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-spacer"> </div>
|
||||
<div class="header-social">
|
||||
<a href="{{ "feed.xml" | relative_link }}" title="Subscribe to The Bit Badger Blog via RSS">
|
||||
<img src="{{ "img/rss.png" | theme_asset }}" alt="RSS">
|
||||
</a>
|
||||
<a href="https://twitter.com/Bit_Badger" title="Bit_Badger on Twitter">
|
||||
<img src="{{ "img/twitter.png" | theme_asset }}" alt="Twitter">
|
||||
</a>
|
||||
<a href="https://www.facebook.com/bitbadger.solutions" title="Bit Badger Solutions on Facebook">
|
||||
<img src="{{ "img/facebook.png" | theme_asset }}" alt="Facebook">
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="content-wrapper" hx-boost="true" hx-target="#content" hx-swap="innerHTML show:#top:top"
|
||||
hx-indicator="#loadOverlay">
|
||||
<div class="load-overlay" id="loadOverlay">
|
||||
<h1>Loading…</h1>
|
||||
</div>
|
||||
<main class="content" id="content" role="main">
|
||||
{{ content }}
|
||||
</main>
|
||||
<aside class="blog-sidebar">
|
||||
<div>
|
||||
<div class="sidebar-head">Linux Resources</div>
|
||||
<ul><li><a href="{{ "linux/" | relative_link }}">Browse Resources</a></li></ul>
|
||||
</div>
|
||||
<div>
|
||||
<div class="sidebar-head">Categories</div>
|
||||
<ul class="cat-list">
|
||||
{% for cat in categories -%}
|
||||
{%- assign indent = cat.parent_names | size -%}
|
||||
<li class="cat-list-item"{% if indent > 0 %} style="padding-left:{{ indent }}rem;"{% endif %}>
|
||||
<a href="{{ cat | category_link }}" class="cat-list-link">{{ cat.name }}</a>
|
||||
<span class="cat-list-count">{{ cat.post_count }}</span>
|
||||
</li>
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<footer class="site-footer">
|
||||
<span>
|
||||
A production of
|
||||
<a href="https://bitbadger.solutions" title="Bit Badger Solutions" target="_blank" rel="noopener"
|
||||
class="no-wrap">
|
||||
Bit Badger Solutions
|
||||
</a>
|
||||
</span>
|
||||
<span>
|
||||
Powered by <a href="https://github.com/bit-badger/myWebLog/tree/v2" target="_blank" rel="noopener">myWebLog</a>
|
||||
•
|
||||
{% if logged_on %}
|
||||
<a href="{{ "admin" | relative_link }}">Dashboard</a>
|
||||
{% else %}
|
||||
<a href="{{ "user/log-on" | relative_link }}">Log On</a>
|
||||
{%- endif %}
|
||||
</span>
|
||||
</footer>
|
||||
{% page_foot %}
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
<article class="auto">
|
||||
<h1 class="entry-title">{{ page.title }}</h1>
|
||||
<div class="entry-content">{{ page.text }}</div>
|
||||
{%- if logged_on %}
|
||||
<p><small><a hx-boost="false" href="{{ page | edit_page_link }}">Edit Page</a></small></p>
|
||||
{% endif -%}
|
||||
</article>
|
|
@ -1,64 +0,0 @@
|
|||
{%- assign post = model.posts | first -%}
|
||||
<article class="auto">
|
||||
<h1 class="entry-title">
|
||||
{{ post.title }}
|
||||
</h1>
|
||||
<header class="entry-header">
|
||||
<p>
|
||||
Posted by {{ model.authors | value: post.author_id }} on {{ post.published_on | date: "dddd, MMMM d, yyyy" }}
|
||||
at {{ post.published_on | date: "h:mm tt" | downcase }}
|
||||
</p>
|
||||
{%- assign cat_count = post.category_ids | size -%}
|
||||
{%- if cat_count > 0 %}
|
||||
<p>
|
||||
<small>
|
||||
Categorized under
|
||||
{% for cat_id in post.category_ids -%}
|
||||
{%- assign cat = categories | where: "id", cat_id | first -%}
|
||||
<a href="{{ cat | category_link }}" title="Categorized under {{ cat.name | strip_html | escape }}"
|
||||
rel="tag">{{ cat.name }}</a>{% unless forloop.last %}, {% endunless %}
|
||||
{%- endfor %}
|
||||
</small>
|
||||
</p>
|
||||
{%- endif %}
|
||||
</header>
|
||||
<div class="entry-content">{{ post.text }}</div>
|
||||
<footer class="entry-footer">
|
||||
{%- assign tag_count = post.tags | size -%}
|
||||
{%- if tag_count > 0 %}
|
||||
<p>
|
||||
Tagged:
|
||||
{% for tag in post.tags -%}
|
||||
<a href="{{ tag | tag_link }}" title="Tagged “{{ tag | escape }}”"
|
||||
rel="tag">{{ tag }}</a>{% unless forloop.last %}, {% endunless %}
|
||||
{%- endfor %}
|
||||
</p>
|
||||
{%- endif %}
|
||||
<p>
|
||||
Bookmark:
|
||||
<a href="{{ post | absolute_link }}" rel="bookmark"
|
||||
title="Permanent link to “{{ post.title | strip_html | escape }}”">
|
||||
the permalink
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
{%- if logged_on %}
|
||||
Edit: <a hx-boost="false" href="{{ post | edit_post_link }}">this post</a>
|
||||
{% else %}
|
||||
|
||||
{% endif -%}
|
||||
</p>
|
||||
{% if model.newer_link -%}
|
||||
<p>
|
||||
Next Newer Post:
|
||||
<a href="{{ model.newer_link.value | relative_link }}">{{ model.newer_name.value }}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if model.older_link -%}
|
||||
<p>
|
||||
Next Older Post:
|
||||
<a href="{{ model.older_link.value | relative_link }}">{{ model.older_name.value }}</a>
|
||||
</p>
|
||||
{%- endif -%}
|
||||
</footer>
|
||||
</article>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,12 +0,0 @@
|
|||
const awftw = {
|
||||
counted: false,
|
||||
countPlay: function (fileLink) {
|
||||
if (!this.counted) {
|
||||
const request = new XMLHttpRequest()
|
||||
request.open('HEAD', 'https://pdcst.click/c/awftw/files.bitbadger.solutions/devotions/' + fileLink, true)
|
||||
request.onload = function () { awftw.counted = true }
|
||||
request.onerror = function () { }
|
||||
request.send()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,349 +0,0 @@
|
|||
@import url('https://fonts.googleapis.com/css?family=Quicksand|Federo|Istok+Web');
|
||||
:root {
|
||||
--text-color: hsl(0, 0%, 10%);
|
||||
--accent-color: green;
|
||||
--link-color: green;
|
||||
--superscript-color: #707070;
|
||||
--bkg-color: lightgray;
|
||||
--heading-bkg-color: darkgray;
|
||||
--item-bkg-color: white;
|
||||
--title-text-color: white;
|
||||
--audio-bkg-color: hsla(0, 0%, 0%, .05);
|
||||
--audio-text-color: hsla(0, 0%, 0%, .5);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--text-color: hsl(0, 0%, 80%);
|
||||
--accent-color: hsl(120, 100%, 15%);
|
||||
--link-color: hsl(120, 100%, 34%);
|
||||
--superscript-color: hsl(0, 0%, 70%);
|
||||
--bkg-color: hsl(0, 0%, 20%);
|
||||
--heading-bkg-color: hsla(0, 0%, 100%, .2);
|
||||
--item-bkg-color: hsla(0, 0%, 7%);
|
||||
--audio-bkg-color: hsl(0, 0%, 10%);
|
||||
--audio-text-color: hsl(0, 0%, 50%);
|
||||
}
|
||||
blockquote {
|
||||
background-color: var(--bkg-color);
|
||||
background-image: linear-gradient(hsl(0, 0%, 85%), hsl(0, 0%, 85%)), url('../img/paper.png') repeat;
|
||||
background-blend-mode: soft-light;
|
||||
color: hsl(0, 0%, 95%);
|
||||
}
|
||||
blockquote.standard {
|
||||
background: unset;
|
||||
color: unset;
|
||||
border-top: none;
|
||||
}
|
||||
.ref {
|
||||
text-shadow: white 0 0 6px, white 0 0 6px, white 0 0 6px, white 0 0 6px;
|
||||
}
|
||||
.ref sup {
|
||||
text-shadow: none;
|
||||
}
|
||||
.index-title {
|
||||
text-shadow: white 0 0 6px, white 0 0 6px;
|
||||
}
|
||||
}
|
||||
html {
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
body {
|
||||
font-family: "Istok Web",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
||||
font-size: 1.1rem;
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
background-color: var(--bkg-color);
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:link, a:visited {
|
||||
color: var(--link-color);
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
h1, h2, h3, h4, p, ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
sup {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
.site-header {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: flex-end;
|
||||
margin-bottom: 1rem;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(var(--accent-color)), to(var(--bkg-color)));
|
||||
background-image: -webkit-linear-gradient(top, var(--accent-color), var(--bkg-color));
|
||||
background-image: -moz-linear-gradient(top, var(--accent-color), var(--bkg-color));
|
||||
background-image: linear-gradient(to bottom, var(--accent-color), var(--bkg-color));
|
||||
}
|
||||
.site-header a {
|
||||
color: var(--title-text-color);
|
||||
}
|
||||
.site-header p {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
.site-title,
|
||||
.index-title,
|
||||
.item-heading,
|
||||
.item-meta,
|
||||
.post-meta,
|
||||
.post-nav-title,
|
||||
.page-footer a {
|
||||
font-family: Federo,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
||||
}
|
||||
.site-title {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
padding-left: 1rem;
|
||||
padding-top: .3rem;
|
||||
}
|
||||
.site-title a {
|
||||
color: var(--title-text-color);
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
max-width: 1400px;
|
||||
margin: auto;
|
||||
}
|
||||
@media all and (max-width:81rem) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.index-title {
|
||||
color: black;
|
||||
text-align: center;
|
||||
}
|
||||
.content {
|
||||
max-width: 60rem;
|
||||
margin: 0;
|
||||
}
|
||||
.sidebar {
|
||||
min-width: 10rem;
|
||||
max-width: 20rem;
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@media all and (max-width:60rem) {
|
||||
.content {
|
||||
padding: 0 .4rem;
|
||||
}
|
||||
}
|
||||
@media all and (max-width:81rem) {
|
||||
.sidebar {
|
||||
width: 100%;
|
||||
max-width: 60rem;
|
||||
padding: 0;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.sidebar .item {
|
||||
max-width: 12rem;
|
||||
}
|
||||
}
|
||||
.sidebar h4 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.sidebar ul {
|
||||
padding-left: 1rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
.sidebar ul li {
|
||||
list-style-type: none;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
.sidebar ul li ul > li {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
.sidebar .item > ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
.post-sidebar {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
@media all and (max-width:81rem) {
|
||||
.post-sidebar {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
hr.sidebar-sep {
|
||||
margin: 0 -.4rem .5rem -.4rem;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
color: var(--accent-color);
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
blockquote {
|
||||
margin: 1rem 2rem;
|
||||
/* from bible */
|
||||
padding: 11px;
|
||||
border: 0;
|
||||
background: var(--bkg-color) url('img/paper.png') repeat;
|
||||
font-family: Quicksand, serif;
|
||||
border-top: solid 1px black;
|
||||
display: flow-root;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
blockquote p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
blockquote p:nth-last-of-type(2) {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
blockquote.standard p:nth-last-of-type(2) {
|
||||
margin-bottom: inherit;
|
||||
}
|
||||
blockquote.standard, blockquote blockquote {
|
||||
margin: 1rem 2rem 1rem 1rem;
|
||||
border-left: solid 3px var(--accent-color);
|
||||
border-top: unset;
|
||||
font-family: inherit;
|
||||
}
|
||||
blockquote cite {
|
||||
display: block;
|
||||
padding-right: 11px;
|
||||
text-align: right;
|
||||
background: var(--item-bkg-color) url('img/ribbon.png') no-repeat bottom left;
|
||||
color: var(--text-color);
|
||||
height: 28px;
|
||||
font-style: normal;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
margin: 0 -11px -11px -12px;
|
||||
}
|
||||
blockquote cite::before {
|
||||
content: "— ";
|
||||
}
|
||||
.ref {
|
||||
color: red;
|
||||
}
|
||||
blockquote sup {
|
||||
color: var(--superscript-color);
|
||||
padding-right: .25rem;
|
||||
}
|
||||
.lord, .sc {
|
||||
font-variant: small-caps;
|
||||
}
|
||||
.u {
|
||||
text-decoration: underline;
|
||||
}
|
||||
blockquote.standard footer {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
blockquote.standard footer cite {
|
||||
font-style: italic;
|
||||
background: unset;
|
||||
display: inline;
|
||||
text-align: left;
|
||||
height: unset;
|
||||
background: unset;
|
||||
position: unset;
|
||||
top: unset;
|
||||
margin: inherit;
|
||||
}
|
||||
cite {
|
||||
font-size: 1rem;
|
||||
}
|
||||
nav {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.nav-next {
|
||||
text-align: right;
|
||||
}
|
||||
.post-nav {
|
||||
font-size: .8rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
footer.part-1 {
|
||||
height: 2rem;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(var(--bkg-color)), to(var(--accent-color)));
|
||||
background-image: -webkit-linear-gradient(top, var(--bkg-color), var(--accent-color));
|
||||
background-image: -moz-linear-gradient(top, var(--bkg-color), var(--accent-color));
|
||||
background-image: linear-gradient(to bottom, var(--bkg-color), var(--accent-color));
|
||||
}
|
||||
footer.page-footer {
|
||||
padding: 0 .5rem .5rem 0;
|
||||
text-align: right;
|
||||
background-color: var(--accent-color);
|
||||
color: var(--title-text-color);
|
||||
font-size: 1rem;
|
||||
}
|
||||
footer.page-footer a:link,
|
||||
footer.page-footer a:visited {
|
||||
color: var(--title-text-color);
|
||||
}
|
||||
small.count {
|
||||
padding-left: .35rem;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
.item {
|
||||
border: solid 1px black;
|
||||
background-color: var(--item-bkg-color);
|
||||
padding: .4rem;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
.item-heading {
|
||||
margin: -.4rem -.4rem .4rem -.4rem;
|
||||
border-bottom: solid 2px var(--link-color);
|
||||
padding-top: .4rem;
|
||||
padding-bottom: .2rem;
|
||||
text-align: center;
|
||||
background-color: var(--heading-bkg-color);
|
||||
}
|
||||
.item-heading,
|
||||
.item-heading a {
|
||||
color: var(--title-text-color);
|
||||
}
|
||||
.item-meta {
|
||||
margin-bottom: 1.2rem;
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
.date-posted {
|
||||
padding: 0 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
aside.podcast {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
background: var(--audio-bkg-color);
|
||||
border: solid 1px var(--accent-color);
|
||||
border-radius: .5rem;
|
||||
color: var(--audio-text-color);
|
||||
margin: 0 .5rem 1rem .5rem;
|
||||
}
|
||||
aside.podcast audio {
|
||||
width: 100%;
|
||||
}
|
||||
aside.podcast p {
|
||||
margin: 0 .5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
a.dl:link,
|
||||
a.dl:visited {
|
||||
color: var(--audio-text-color);
|
||||
}
|
||||
@media all and (max-width: 40rem) {
|
||||
blockquote {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,372 +0,0 @@
|
|||
:root {
|
||||
--heading-fonts: Oswald, "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
--accent-color: navy;
|
||||
--app-color: maroon;
|
||||
--edge-color: lightgray;
|
||||
--bkg-color: #fffafa;
|
||||
}
|
||||
html {
|
||||
background-color: var(--edge-color);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Raleway, "Segoe UI", Ubuntu, Tahoma, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
background-color: var(--bkg-color);
|
||||
}
|
||||
a {
|
||||
color: var(--accent-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
border-bottom: dotted 1px var(--accent-color);
|
||||
}
|
||||
a img {
|
||||
border: 0;
|
||||
}
|
||||
acronym {
|
||||
border-bottom: dotted 1px black;
|
||||
}
|
||||
header, h1, h2, h3, .footer-by a {
|
||||
font-family: var(--heading-fonts);
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 1.4rem 0;
|
||||
font-size: 2rem;
|
||||
}
|
||||
h1.project-title {
|
||||
line-height: 1.2;
|
||||
}
|
||||
h2 {
|
||||
margin: 1.2rem 0;
|
||||
}
|
||||
h3 {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
h2, h3 {
|
||||
border-bottom: solid 2px var(--accent-color);
|
||||
width: 95%;
|
||||
}
|
||||
@media all and (min-width: 40rem) {
|
||||
h1 {
|
||||
margin: 0 0 1.4rem 0;
|
||||
}
|
||||
h2, h3 {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
p {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
code, pre {
|
||||
font-family: "JetBrains Mono","SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;
|
||||
font-size: 80%;
|
||||
}
|
||||
code {
|
||||
background-color: rgba(0, 0, 0, .1);
|
||||
padding: 0 .25rem;
|
||||
white-space: pre;
|
||||
}
|
||||
pre {
|
||||
background-color: rgba(0, 0, 0, .9);
|
||||
color: rgba(255, 255, 255, .9);
|
||||
padding: .5rem;
|
||||
border-radius: .5rem;
|
||||
overflow: auto;
|
||||
}
|
||||
pre > code {
|
||||
background-color: unset;
|
||||
}
|
||||
div[style="color:#DADADA;background-color:#1E1E1E;"] {
|
||||
background-color: unset !important;
|
||||
}
|
||||
#content {
|
||||
margin: 0 1rem;
|
||||
}
|
||||
.content {
|
||||
font-size: 1.1rem;
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
.auto {
|
||||
margin: 0 auto;
|
||||
}
|
||||
@media all and (min-width: 68rem) {
|
||||
.content {
|
||||
width: 66rem;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
}
|
||||
.hdr {
|
||||
font-size: 14pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
.strike {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.alignleft {
|
||||
float: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
ul {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
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, var(--edge-color), var(--bkg-color));
|
||||
}
|
||||
.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 var(--edge-color);
|
||||
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 var(--edge-color);
|
||||
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: var(--heading-fonts);
|
||||
font-weight: bold;
|
||||
color: var(--app-color);
|
||||
margin-bottom: .8rem;
|
||||
padding: 3px 12px;
|
||||
border-bottom: solid 2px var(--edge-color);
|
||||
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: var(--heading-fonts);
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: var(--app-color);
|
||||
}
|
||||
/* Individual solution pages */
|
||||
h1.solution-header {
|
||||
line-height: 1;
|
||||
}
|
||||
.app-info aside {
|
||||
float: right;
|
||||
background-color: #FFFAFA;
|
||||
padding-left: .5rem;
|
||||
}
|
||||
@media all and (max-width: 40rem) {
|
||||
.app-info aside {
|
||||
float: none;
|
||||
text-align: center;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
.app-info aside > img {
|
||||
overflow: hidden;
|
||||
border: dotted 1px darkgray;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
.tech-stack p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.tech-stack ul {
|
||||
margin-top: 0;
|
||||
}
|
||||
blockquote {
|
||||
border-left: solid 1px darkgray;
|
||||
margin-left: 25px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.quote {
|
||||
font-style: italic;
|
||||
}
|
||||
.source {
|
||||
text-align: right;
|
||||
padding-right: 60px;
|
||||
}
|
||||
.app-info h3:hover {
|
||||
cursor: hand;
|
||||
cursor: pointer;
|
||||
}
|
||||
.app-info .arrow {
|
||||
font-size: .75rem;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
.collapse-panel {
|
||||
max-height: 0;
|
||||
transition: max-height .5s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
.collapse-panel.shown {
|
||||
max-height: 25rem;
|
||||
overflow: auto;
|
||||
}
|
||||
.collapse-panel p:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
/* Footer */
|
||||
.project-footer {
|
||||
padding-top: 1rem;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
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, var(--bkg-color), var(--edge-color));
|
||||
}
|
||||
footer a:link, footer a:visited {
|
||||
color: black;
|
||||
}
|
||||
/* htmx "Loading" overlay */
|
||||
.load-overlay {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: center;
|
||||
width: 95%;
|
||||
margin-left: 2.5%;
|
||||
height: 0;
|
||||
z-index: 2000;
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
border-radius: 1rem;
|
||||
animation: fadeOut .25s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
.load-overlay h1 {
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, .75);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 1rem;
|
||||
width: 50%;
|
||||
padding: 1rem;
|
||||
}
|
||||
.load-overlay.htmx-request {
|
||||
height: 80vh;
|
||||
animation: fadeIn .25s ease-in-out;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: 80vh;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: 80vh;
|
||||
}
|
||||
}
|
||||
@keyframes fadeOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
height: 80vh;
|
||||
}
|
||||
99% {
|
||||
opacity: 0;
|
||||
height: 80vh;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -1,18 +0,0 @@
|
|||
djs = {
|
||||
|
||||
displayVotd: res => {
|
||||
const votd = res.votd
|
||||
const votdItem = document.querySelector('.votd-item')
|
||||
votdItem.querySelector('.verse').innerHTML = votd.text
|
||||
const reference = votdItem.querySelector('.votd-reference')
|
||||
reference.href = votd.permalink.replace('&', '&')
|
||||
const ref = votd.display_ref
|
||||
const isPassage = ref.indexOf(',') >= 0 || ref.indexOf('-') >= 0 || ref.indexOf(';') >= 0
|
||||
if (isPassage) {
|
||||
document.querySelector('.votd-heading').innerText = 'Passage of the Day'
|
||||
}
|
||||
reference.innerHTML = ref
|
||||
votdItem.querySelector('.version-link').href = votd.copyrightlink.replace('&', '&').replace('&', '&')
|
||||
votdItem.style.display = 'block'
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,345 +0,0 @@
|
|||
@import "https://fonts.googleapis.com/css?family=Quicksand|Oswald";
|
||||
:root {
|
||||
--text-color: rgb(0, 0, 0);
|
||||
--accent-color: rgb(21, 140, 186);
|
||||
--bkg-color: rgb(68, 68, 68);
|
||||
--hdr-text-color: hsl(0, 0%, 100%);
|
||||
--hdr-bkg-color: hsl(0, 0%, 95%);
|
||||
--item-bkg-color: hsl(0, 0%, 100%);
|
||||
--overlay-bkg-color: rgba(0, 0, 0, .5)
|
||||
}
|
||||
@media ( prefers-color-scheme: dark ) {
|
||||
:root {
|
||||
--text-color: rgb(210, 210, 210);
|
||||
--hdr-bkg-color: hsl(0, 0%, 7%);
|
||||
--item-bkg-color: hsl(0, 0%, 12%);
|
||||
--overlay-bgk-color: rgba(255, 255, 255, .2)
|
||||
}
|
||||
}
|
||||
html {
|
||||
background-color: var(--bkg-color);
|
||||
}
|
||||
body {
|
||||
font-family: Quicksand, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
font-size: 1.2rem;
|
||||
background-color: var(--bkg-color);
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
}
|
||||
a:link, a:visited {
|
||||
color: var(--accent-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
h1, h2, h3, h4 {
|
||||
font-family: Oswald, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
h1 a:link, h1 a:visited {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
blockquote {
|
||||
margin: 1rem 2rem 1rem 1rem;
|
||||
border-left: solid 3px var(--accent-color);
|
||||
padding-left: 1rem;
|
||||
}
|
||||
sup, sub {
|
||||
font-size: smaller;
|
||||
}
|
||||
sup {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
sub {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
main {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto;
|
||||
}
|
||||
.content img {
|
||||
max-width: 100%;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
.content img.flat {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ----- SITE HEADER ----- */
|
||||
.site-header p, footer.part-1 p {
|
||||
margin-top: .8rem;
|
||||
margin-right: 1.2rem;
|
||||
color: var(--hdr-text-color);
|
||||
}
|
||||
.site-header p a:link, .site-header p a:visited {
|
||||
font-size: 1rem;
|
||||
color: var(--hdr-text-color);
|
||||
}
|
||||
.site-header {
|
||||
min-height: 4rem;
|
||||
padding: 0 .4rem;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: flex-end;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(var(--accent-color)), to(var(--bkg-color)));
|
||||
background-image: -webkit-linear-gradient(top, var(--accent-color), var(--bkg-color));
|
||||
background-image: -moz-linear-gradient(top, var(--accent-color), var(--bkg-color));
|
||||
background-image: linear-gradient(to bottom, var(--accent-color), var(--bkg-color));
|
||||
}
|
||||
.site-header p {
|
||||
margin: 0;
|
||||
}
|
||||
.site-header p a.nav-home {
|
||||
font-family: Oswald, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
font-weight: bold;
|
||||
margin-left: .2rem;
|
||||
color: var(--hdr-text-color);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.nav-spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/* ----- CONTENT STYLES ----- */
|
||||
.index-title {
|
||||
color: var(--hdr-text-color);
|
||||
border-bottom: solid 2px var(--accent-color);
|
||||
}
|
||||
.content {
|
||||
max-width: 60rem;
|
||||
margin: 0 auto auto;
|
||||
padding: 0 .4rem;
|
||||
}
|
||||
.item {
|
||||
border: solid 1px black;
|
||||
border-radius: .5rem;
|
||||
background-color: var(--item-bkg-color);
|
||||
padding: .4rem;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
.item-heading {
|
||||
margin: -.4rem -.4rem .4rem;
|
||||
border-top-left-radius: .5rem;
|
||||
border-top-right-radius: .5rem;
|
||||
border-bottom: solid 1px darkgray;
|
||||
padding-bottom: .2rem;
|
||||
text-align: center;
|
||||
color: var(--accent-color);
|
||||
background-color: var(--hdr-bkg-color);
|
||||
}
|
||||
.post-meta {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
.pager {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
}
|
||||
.pager li {
|
||||
list-style-type: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* ----- SIDEBAR STYLES ----- */
|
||||
.sidebar {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.votd-item {
|
||||
display: none;
|
||||
}
|
||||
.votd-credits {
|
||||
margin-top: 1rem;
|
||||
text-align: right;
|
||||
}
|
||||
.cat-list {
|
||||
padding-left: 0
|
||||
}
|
||||
.cat-list ul {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
.cat-list li {
|
||||
list-style-type: none;
|
||||
padding-bottom: .25rem;
|
||||
}
|
||||
.cat-list ul li ul > li {
|
||||
padding-top: .2rem;
|
||||
}
|
||||
.cat-list-count {
|
||||
font-size: .8rem;
|
||||
padding-left: .4rem;
|
||||
}
|
||||
.cat-list-count:before {
|
||||
content: '(';
|
||||
}
|
||||
.cat-list-count:after {
|
||||
content: ')';
|
||||
}
|
||||
|
||||
/* ----- FOOTER STYLES ----- */
|
||||
footer.part-1 {
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(var(--bkg-color)), to(var(--accent-color)));
|
||||
background-image: -webkit-linear-gradient(top, var(--bkg-color), var(--accent-color));
|
||||
background-image: -moz-linear-gradient(top, var(--bkg-color), var(--accent-color));
|
||||
background-image: linear-gradient(to bottom, var(--bkg-color), var(--accent-color));
|
||||
min-height: 2rem;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
footer.part-2 {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(var(--accent-color)), to(var(--bkg-color)));
|
||||
background-image: -webkit-linear-gradient(top, var(--accent-color), var(--bkg-color));
|
||||
background-image: -moz-linear-gradient(top, var(--accent-color), var(--bkg-color));
|
||||
background-image: linear-gradient(to bottom, var(--accent-color), var(--bkg-color));
|
||||
padding-bottom: .4rem;
|
||||
}
|
||||
footer.part-2 > div {
|
||||
flex-basis: 30%;
|
||||
min-width: 400px;
|
||||
}
|
||||
footer.part-2 sup {
|
||||
line-height: 1;
|
||||
}
|
||||
footer.part-3 {
|
||||
padding: 0 .4rem 1rem .4rem;
|
||||
background-color: var(--bkg-color);
|
||||
}
|
||||
.copy, .copy a:link, .copy a:visited {
|
||||
font-size: 1rem;
|
||||
color: #dddddd;
|
||||
text-decoration: none;
|
||||
}
|
||||
.copy a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.football-panel {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
.football-panel div {
|
||||
text-align: center;
|
||||
line-height: 1.6rem;
|
||||
}
|
||||
|
||||
/* ----- UTILITY CLASSES ----- */
|
||||
.desktop {
|
||||
display: none;
|
||||
}
|
||||
.float-left {
|
||||
float: left;
|
||||
padding-right: .5rem;
|
||||
}
|
||||
.float-right {
|
||||
float: right;
|
||||
padding-left: .5rem;
|
||||
}
|
||||
.small-caps {
|
||||
font-variant: small-caps;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
.no-wrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ----- OVERLAY ----- */
|
||||
.load-overlay {
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
left: 1rem;
|
||||
width: 50%;
|
||||
height: 0;
|
||||
z-index: 2000;
|
||||
background-color: var(--overlay-bgk-color);
|
||||
border-radius: 1rem;
|
||||
animation: fadeOut .25s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
.load-overlay h1 {
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, .75);
|
||||
margin: 1.5rem auto;
|
||||
border-radius: 1rem;
|
||||
width: 50%;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
.load-overlay.htmx-request {
|
||||
height: unset;
|
||||
animation: fadeIn .25s ease-in-out;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: unset;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: unset;
|
||||
}
|
||||
}
|
||||
@keyframes fadeOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
height: unset;
|
||||
}
|
||||
99% {
|
||||
opacity: 0;
|
||||
height: unset;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- SCALE UP STYLES ----- */
|
||||
@media screen and ( min-width: 50rem ) {
|
||||
main {
|
||||
grid-template-columns: 1fr 16rem;
|
||||
}
|
||||
.desktop {
|
||||
display: unset;
|
||||
}
|
||||
.mobile {
|
||||
display: none;
|
||||
}
|
||||
.site-header p {
|
||||
margin-inline-end: 1.2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.load-overlay {
|
||||
width: 25%;
|
||||
}
|
||||
main > .single {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
.sidebar {
|
||||
max-width: 15rem;
|
||||
}
|
||||
footer.part-2 {
|
||||
grid-gap: 0;
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,484 +0,0 @@
|
|||
@import url('https://fonts.googleapis.com/css?family=Oswald|Raleway');
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/webfonts/JetBrainsMono-Regular.woff2') format('woff2'),
|
||||
url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/ttf/JetBrainsMono-Regular.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
:root {
|
||||
--heading-fonts: Oswald, "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
--body-fonts: Raleway, "Segoe UI", Ubuntu, Tahoma, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
--code-fonts: "JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
--accent-color: navy;
|
||||
--app-color: maroon;
|
||||
--edge-color: lightgray;
|
||||
--bkg-color: #fffafa;
|
||||
}
|
||||
html {
|
||||
background-color: lightgray;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
body, .entry-meta {
|
||||
font-family: var(--body-fonts);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #FFFAFA;
|
||||
}
|
||||
a {
|
||||
color: navy;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
border-bottom: dotted 1px var(--accent-color);
|
||||
}
|
||||
a img {
|
||||
border:0;
|
||||
}
|
||||
acronym {
|
||||
border-bottom:dotted 1px black;
|
||||
text-decoration: none;
|
||||
}
|
||||
.site-header, h1, h2, h3, .site-footer a, .home-lead a, .highlight {
|
||||
font-family: var(--heading-fonts);
|
||||
}
|
||||
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 var(--accent-color);
|
||||
width: 95%;
|
||||
}
|
||||
@media all and (min-width: 40rem) {
|
||||
h2, h3 {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
p {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
code, pre {
|
||||
font-family: var(--code-fonts);
|
||||
font-size: 80%;
|
||||
}
|
||||
code {
|
||||
background-color: rgba(0, 0, 0, .1);
|
||||
padding: 0 .25rem;
|
||||
white-space: pre;
|
||||
}
|
||||
pre {
|
||||
background-color: rgba(0, 0, 0, .9);
|
||||
color: rgba(255, 255, 255, .9);
|
||||
padding: .5rem;
|
||||
border-radius: .5rem;
|
||||
overflow: auto;
|
||||
}
|
||||
pre > code {
|
||||
background-color: unset;
|
||||
}
|
||||
div[style="color:#DADADA;background-color:#1E1E1E;"] {
|
||||
background-color: unset !important;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
.site-header {
|
||||
height: 100px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(var(--edge-color)), to(var(--bkg-color)));
|
||||
background-image: -webkit-linear-gradient(top, var(--edge-color), var(--bkg-color));
|
||||
background-image: -moz-linear-gradient(top, var(--edge-color), var(--bkg-color));
|
||||
background-image: linear-gradient(to bottom, var(--edge-color), var(--bkg-color));
|
||||
}
|
||||
.site-header a:link, .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;
|
||||
}
|
||||
.header-social {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
.content-item {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
article.page .metadata {
|
||||
display: none;
|
||||
}
|
||||
.strike {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.site-footer {
|
||||
padding: 20px 15px 10px 15px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
font-size: 1rem;
|
||||
color: black;
|
||||
clear: both;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(var(--bkg-color)), to(var(--edge-color)));
|
||||
background-image: -webkit-linear-gradient(top, var(--bkg-color), var(--edge-color));
|
||||
background-image: -moz-linear-gradient(top, var(--bkg-color), var(--edge-color));
|
||||
background-image: linear-gradient(to bottom, var(--bkg-color), var(--edge-color));
|
||||
}
|
||||
.site-footer a:link, .site-footer a:visited {
|
||||
color: black;
|
||||
}
|
||||
.alignleft {
|
||||
float:left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
ul {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
@media all and (min-width: 80rem) {
|
||||
.content-wrapper {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: flex-start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.content {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
.load-overlay {
|
||||
position: fixed;
|
||||
display: block;
|
||||
width: 90%;
|
||||
height: 0;
|
||||
z-index: 2000;
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
border-radius: 1rem;
|
||||
animation: fadeOut .25s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
.load-overlay h1 {
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, .75);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 1rem;
|
||||
width: 50%;
|
||||
padding: 1rem;
|
||||
}
|
||||
.load-overlay.htmx-request {
|
||||
display: block;
|
||||
height: 80vh;
|
||||
animation: fadeIn .25s ease-in-out;
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: 80vh;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: 80vh;
|
||||
}
|
||||
}
|
||||
@keyframes fadeOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
height: 80vh;
|
||||
}
|
||||
99% {
|
||||
opacity: 0;
|
||||
height: 80vh;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
@media all and (min-width: 68rem) {
|
||||
.content {
|
||||
width: 66rem;
|
||||
}
|
||||
.load-overlay {
|
||||
width: 60rem;
|
||||
left: 2rem;
|
||||
}
|
||||
}
|
||||
.home-title {
|
||||
text-align: left;
|
||||
line-height: 2rem;
|
||||
}
|
||||
.home-lead {
|
||||
font-family: var(--body-fonts);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.home-break {
|
||||
width: 80%;
|
||||
border: dotted 1px var(--edge-color);
|
||||
border-bottom: 0;
|
||||
}
|
||||
.blog-sidebar {
|
||||
border-top: dotted 1px var(--edge-color);
|
||||
padding-top: 1rem;
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.blog-sidebar ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
.blog-sidebar > ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.blog-sidebar li {
|
||||
list-style: none;
|
||||
}
|
||||
.blog-sidebar li:before {
|
||||
content: '» ';
|
||||
}
|
||||
@media all and (min-width: 68rem) {
|
||||
.blog-sidebar {
|
||||
width: 66rem;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
@media all and (min-width: 80rem) {
|
||||
.blog-sidebar {
|
||||
min-width: 12rem;
|
||||
max-width: 14rem;
|
||||
border-top: none;
|
||||
border-left: dotted 1px var(--edge-color);
|
||||
padding-top: 0;
|
||||
padding-left: 1rem;
|
||||
margin: 0 0 0 1rem;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
.blog-sidebar a {
|
||||
font-size: 10pt;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.sidebar-head {
|
||||
text-align: center;
|
||||
font-family: var(--heading-fonts);
|
||||
font-weight: bold;
|
||||
color: var(--app-color);
|
||||
margin-bottom: .8rem;
|
||||
padding: 3px 12px;
|
||||
border-bottom: solid 2px var(--edge-color);
|
||||
font-size: 1rem;
|
||||
}
|
||||
.app-sidebar-name, .app-sidebar-description {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.app-sidebar-description {
|
||||
font-style: italic;
|
||||
color: #555555;
|
||||
padding-bottom: .6rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.auto {
|
||||
margin: 0 auto;
|
||||
}
|
||||
.auto > div {
|
||||
max-width: 66rem;
|
||||
}
|
||||
.entry-title {
|
||||
line-height: 1;
|
||||
}
|
||||
.entry-header {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.entry-content {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
.entry-footer {
|
||||
font-size: 85%;
|
||||
border-top: solid 1px rgba(0, 0, 0, .2);
|
||||
}
|
||||
.entry-header p, .entry-footer p {
|
||||
margin: .5rem 0;
|
||||
}
|
||||
.cat-list-count {
|
||||
font-size: .8rem;
|
||||
}
|
||||
.cat-list-count:before {
|
||||
content: '(';
|
||||
}
|
||||
.cat-list-count:after {
|
||||
content: ')';
|
||||
}
|
||||
.bottom-nav {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
padding-top: 1.5rem;
|
||||
}
|
||||
.no-wrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
figure.highlight {
|
||||
background-color: #F8F8F8;
|
||||
}
|
||||
figure.highlight table {
|
||||
background-color: #002b36;
|
||||
width: 100%;
|
||||
}
|
||||
figure.highlight td.gutter,
|
||||
figure.highlight td.code,
|
||||
figure.highlight pre {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background-color: #002b36;
|
||||
color: #839496;
|
||||
}
|
||||
figure.highlight td.gutter {
|
||||
text-align:right;
|
||||
padding-right: .4rem;
|
||||
}
|
||||
figure.highlight td.gutter div.line:after {
|
||||
content: ':';
|
||||
color: #586e75;
|
||||
}
|
||||
figure.highlight td.code pre div.line:after {
|
||||
content: '.';
|
||||
visibility: hidden;
|
||||
}
|
||||
figure.highlight pre div.line,
|
||||
figure.highlight pre div.line > * {
|
||||
font-family: var(--code-fonts);
|
||||
}
|
||||
figure.highlight {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
color: #839496;
|
||||
border:1px dashed #ddd;
|
||||
}
|
||||
figure.highlight .comment,
|
||||
figure.highlight .quote {
|
||||
color: #586e75;
|
||||
}
|
||||
/* Solarized Green */
|
||||
figure.highlight .keyword,
|
||||
figure.highlight .selector-tag,
|
||||
figure.highlight .addition {
|
||||
color: #859900;
|
||||
}
|
||||
/* Solarized Cyan */
|
||||
figure.highlight .number,
|
||||
figure.highlight .string,
|
||||
figure.highlight .meta .meta-string,
|
||||
figure.highlight .literal,
|
||||
figure.highlight .doctag,
|
||||
figure.highlight .regexp {
|
||||
color: #2aa198;
|
||||
}
|
||||
/* Solarized Blue */
|
||||
figure.highlight .title,
|
||||
figure.highlight .section,
|
||||
figure.highlight .name,
|
||||
figure.highlight .selector-id,
|
||||
figure.highlight .selector-class {
|
||||
color: #268bd2;
|
||||
}
|
||||
/* Solarized Yellow */
|
||||
figure.highlight .attribute,
|
||||
figure.highlight .attr,
|
||||
figure.highlight .variable,
|
||||
figure.highlight .template-variable,
|
||||
figure.highlight .class .title,
|
||||
figure.highlight .type {
|
||||
color: #b58900;
|
||||
}
|
||||
/* Solarized Orange */
|
||||
figure.highlight .symbol,
|
||||
figure.highlight .bullet,
|
||||
figure.highlight .subst,
|
||||
figure.highlight .meta,
|
||||
figure.highlight .meta .keyword,
|
||||
figure.highlight .selector-attr,
|
||||
figure.highlight .selector-pseudo,
|
||||
figure.highlight .link {
|
||||
color: #cb4b16;
|
||||
}
|
||||
/* Solarized Red */
|
||||
figure.highlight .built_in,
|
||||
figure.highlight .deletion {
|
||||
color: #dc322f;
|
||||
}
|
||||
figure.highlight .formula {
|
||||
background: #eee8d5;
|
||||
}
|
||||
figure.highlight .emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
figure.highlight .strong {
|
||||
font-weight: bold;
|
||||
}
|
26
src/admin-theme/upload-theme.liquid
Normal file
26
src/admin-theme/upload-theme.liquid
Normal file
|
@ -0,0 +1,26 @@
|
|||
<h2>Upload a Theme</h2>
|
||||
<article>
|
||||
<form action="{{ "admin/theme/update" | relative_link }}"
|
||||
method="post" class="container" enctype="multipart/form-data" hx-boost="false">
|
||||
<input type="hidden" name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 offset-sm-3 pb-3">
|
||||
<div class="form-floating">
|
||||
<input type="file" id="file" name="file" class="form-control" accept=".zip" placeholder="Theme File" required>
|
||||
<label for="file">Theme File</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 pb-3">
|
||||
<div class="form-check form-switch pb-2">
|
||||
<input type="checkbox" name="clean" id="clean" class="form-check-input" value="true">
|
||||
<label for="clean" class="form-check-label">Delete Existing Theme Files</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pb-3">
|
||||
<div class="col text-center">
|
||||
<button type="submit" class="btn btn-primary">Upload Theme</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</article>
|
2
src/admin-theme/version.txt
Normal file
2
src/admin-theme/version.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
myWebLog Admin
|
||||
2.0.0-alpha34
|
Loading…
Reference in New Issue
Block a user