Admin tweaks plus
- Version now reports the correct version - Post edit properly renders existing selected categories as checked, and uses the description in the title attribute if it is present - Created light/dark transparent logos Ready to test the functionality of the admin area next...
This commit is contained in:
parent
ed9b8adc1c
commit
0d54fc2ec3
@ -130,7 +130,7 @@ type MyWebLogBootstrapper() =
|
||||
|
||||
|
||||
let version =
|
||||
let v = typeof<AppConfig>.GetType().GetTypeInfo().Assembly.GetName().Version
|
||||
let v = typeof<AppConfig>.GetTypeInfo().Assembly.GetName().Version
|
||||
match v.Build with
|
||||
| 0 -> match v.Minor with 0 -> string v.Major | _ -> sprintf "%d.%d" v.Major v.Minor
|
||||
| _ -> sprintf "%d.%d.%d" v.Major v.Minor v.Build
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace myWebLog.Web.AssemblyInfo
|
||||
namespace MyWebLog.AssemblyInfo
|
||||
|
||||
open System.Reflection
|
||||
open System.Runtime.CompilerServices
|
||||
@ -14,7 +14,7 @@ open System.Runtime.InteropServices
|
||||
[<assembly: AssemblyCulture("")>]
|
||||
[<assembly: ComVisible(false)>]
|
||||
[<assembly: Guid("e6ee110a-27a6-4a19-b0cb-d24f48f71b53")>]
|
||||
[<assembly: AssemblyVersion("0.9.1.0")>]
|
||||
[<assembly: AssemblyVersion("0.9.2.0")>]
|
||||
[<assembly: AssemblyFileVersion("1.0.0.0")>]
|
||||
|
||||
do
|
||||
|
@ -104,17 +104,17 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
|
||||
|
||||
do
|
||||
this.Get ("/", fun _ -> this.HomePage ())
|
||||
this.Get ("/{permalink*}", fun parms -> this.CatchAll (downcast parms))
|
||||
this.Get ("/posts/page/{page:int}", fun parms -> this.PublishedPostsPage (getPage <| downcast parms))
|
||||
this.Get ("/category/{slug}", fun parms -> this.CategorizedPosts (downcast parms))
|
||||
this.Get ("/category/{slug}/page/{page:int}", fun parms -> this.CategorizedPosts (downcast parms))
|
||||
this.Get ("/tag/{tag}", fun parms -> this.TaggedPosts (downcast parms))
|
||||
this.Get ("/tag/{tag}/page/{page:int}", fun parms -> this.TaggedPosts (downcast parms))
|
||||
this.Get ("/{permalink*}", fun p -> this.CatchAll (downcast p))
|
||||
this.Get ("/posts/page/{page:int}", fun p -> this.PublishedPostsPage (getPage <| downcast p))
|
||||
this.Get ("/category/{slug}", fun p -> this.CategorizedPosts (downcast p))
|
||||
this.Get ("/category/{slug}/page/{page:int}", fun p -> this.CategorizedPosts (downcast p))
|
||||
this.Get ("/tag/{tag}", fun p -> this.TaggedPosts (downcast p))
|
||||
this.Get ("/tag/{tag}/page/{page:int}", fun p -> this.TaggedPosts (downcast p))
|
||||
this.Get ("/feed", fun _ -> this.Feed ())
|
||||
this.Get ("/posts/list", fun _ -> this.PostList 1)
|
||||
this.Get ("/posts/list/page/{page:int}", fun parms -> this.PostList (getPage <| downcast parms))
|
||||
this.Get ("/post/{postId}/edit", fun parms -> this.EditPost (downcast parms))
|
||||
this.Post ("/post/{postId}/edit", fun parms -> this.SavePost (downcast parms))
|
||||
this.Get ("/posts/list/page/{page:int}", fun p -> this.PostList (getPage <| downcast p))
|
||||
this.Get ("/post/{postId}/edit", fun p -> this.EditPost (downcast p))
|
||||
this.Post ("/post/{postId}/edit", fun p -> this.SavePost (downcast p))
|
||||
|
||||
// ---- Display posts to users ----
|
||||
|
||||
@ -253,11 +253,10 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
|
||||
| None -> Revision.Empty
|
||||
let model = EditPostModel (this.Context, this.WebLog, post, rev)
|
||||
model.Categories <- findAllCategories data this.WebLog.Id
|
||||
|> List.map (fun cat -> string (fst cat).Id,
|
||||
sprintf "%s%s" (String.replicate (snd cat) " ")
|
||||
(fst cat).Name)
|
||||
|> List.map (fun cat ->
|
||||
DisplayCategory.Create cat (post.CategoryIds |> List.contains (fst cat).Id))
|
||||
model.PageTitle <- Strings.get <| match post.Id with "new" -> "AddNewPost" | _ -> "EditPost"
|
||||
upcast this.View.["admin/post/edit"]
|
||||
upcast this.View.["admin/post/edit", model]
|
||||
| _ -> this.NotFound ()
|
||||
|
||||
/// Save a post
|
||||
|
@ -9,7 +9,7 @@ open Newtonsoft.Json
|
||||
open NodaTime
|
||||
open NodaTime.Text
|
||||
open System
|
||||
|
||||
open System.Net
|
||||
|
||||
/// Levels for a user message
|
||||
[<RequireQualifiedAccess>]
|
||||
@ -90,7 +90,7 @@ module FormatDateTime =
|
||||
|
||||
|
||||
/// Parent view model for all myWebLog views
|
||||
type MyWebLogModel (ctx : NancyContext, webLog : WebLog) =
|
||||
type MyWebLogModel (ctx : NancyContext, webLog : WebLog) as this =
|
||||
|
||||
/// Get the messages from the session
|
||||
let getMessages () =
|
||||
@ -100,6 +100,20 @@ type MyWebLogModel (ctx : NancyContext, webLog : WebLog) =
|
||||
| _ -> ctx.Request.Session.Delete Keys.Messages
|
||||
msg
|
||||
|
||||
/// Generate a footer logo with the given scheme
|
||||
let footerLogo scheme =
|
||||
seq {
|
||||
yield sprintf "<img src=\"/content/logo-%s.png\" alt=\"myWebLog\" title=\"" scheme
|
||||
yield sprintf "%s %s • " (Strings.get "PoweredBy") this.Generator
|
||||
yield Strings.get "LoadedIn"
|
||||
yield " "
|
||||
yield TimeSpan(System.DateTime.Now.Ticks - this.RequestStart).TotalSeconds.ToString "f3"
|
||||
yield " "
|
||||
yield (Strings.get "Seconds").ToLower ()
|
||||
yield "\" height=\"30\" />"
|
||||
}
|
||||
|> Seq.reduce (+)
|
||||
|
||||
/// The web log for this request
|
||||
member this.WebLog = webLog
|
||||
/// The subtitle for the webLog (SSVE can't do IsSome that deep)
|
||||
@ -134,19 +148,11 @@ type MyWebLogModel (ctx : NancyContext, webLog : WebLog) =
|
||||
| None -> this.WebLog.Name
|
||||
| pt -> sprintf "%s | %s" pt this.WebLog.Name
|
||||
|
||||
/// An image with the version and load time in the tool tip
|
||||
member this.FooterLogo =
|
||||
seq {
|
||||
yield "<img src=\"/default/footer-logo.png\" alt=\"myWebLog\" title=\""
|
||||
yield sprintf "%s %s • " (Strings.get "PoweredBy") this.Generator
|
||||
yield Strings.get "LoadedIn"
|
||||
yield " "
|
||||
yield TimeSpan(System.DateTime.Now.Ticks - this.RequestStart).TotalSeconds.ToString "f3"
|
||||
yield " "
|
||||
yield (Strings.get "Seconds").ToLower ()
|
||||
yield "\" />"
|
||||
}
|
||||
|> Seq.reduce (+)
|
||||
/// An image with the version and load time in the tool tip (using light text)
|
||||
member this.FooterLogoLight = footerLogo "light"
|
||||
|
||||
/// An image with the version and load time in the tool tip (using dark text)
|
||||
member this.FooterLogoDark = footerLogo "dark"
|
||||
|
||||
|
||||
// ---- Admin models ----
|
||||
@ -399,6 +405,27 @@ type EditPostForm () =
|
||||
this.Text <- rev.Text
|
||||
this
|
||||
|
||||
/// Category information for display
|
||||
type DisplayCategory = {
|
||||
Id : string
|
||||
Indent : string
|
||||
Name : string
|
||||
Description : string
|
||||
IsChecked : bool
|
||||
}
|
||||
with
|
||||
/// Create a display category
|
||||
static member Create (cat : Category, indent) isChecked =
|
||||
{ Id = cat.Id
|
||||
Indent = String.replicate indent " "
|
||||
Name = WebUtility.HtmlEncode cat.Name
|
||||
IsChecked = isChecked
|
||||
Description = WebUtility.HtmlEncode (match cat.Description with Some d -> d | _ -> cat.Name)
|
||||
}
|
||||
/// The "checked" attribute for this category
|
||||
member this.CheckedAttr
|
||||
with get() = match this.IsChecked with true -> "checked=\"checked\"" | _ -> ""
|
||||
|
||||
/// View model for the edit post page
|
||||
type EditPostModel (ctx, webLog, post, revision) =
|
||||
inherit MyWebLogModel (ctx, webLog)
|
||||
@ -408,7 +435,7 @@ type EditPostModel (ctx, webLog, post, revision) =
|
||||
/// The post being edited
|
||||
member val Post = post with get, set
|
||||
/// The categories to which the post may be assigned
|
||||
member val Categories : (string * string) list = [] with get, set
|
||||
member val Categories : DisplayCategory list = [] with get, set
|
||||
/// Whether the post is currently published
|
||||
member this.IsPublished = PostStatus.Published = this.Post.Status
|
||||
/// The published date
|
||||
|
@ -100,9 +100,13 @@ let tryFindPost conn webLogId postId : Post option =
|
||||
let! p =
|
||||
r.Table(Table.Post)
|
||||
.Get(postId)
|
||||
.Filter(ReqlFunction1 (fun p -> upcast p.["WebLogId"].Eq webLogId))
|
||||
.RunAtomAsync<Post> conn
|
||||
return match box p with null -> None | post -> Some <| unbox post
|
||||
return
|
||||
match box p with
|
||||
| null -> None
|
||||
| pst ->
|
||||
let post : Post = unbox pst
|
||||
match post.WebLogId = webLogId with true -> Some post | _ -> None
|
||||
}
|
||||
|> Async.RunSynchronously
|
||||
|
||||
|
BIN
src/MyWebLog/content/logo-dark.png
Normal file
BIN
src/MyWebLog/content/logo-dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
src/MyWebLog/content/logo-light.png
Normal file
BIN
src/MyWebLog/content/logo-light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
@ -2,7 +2,7 @@
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"copyToOutput": {
|
||||
"include": "views"
|
||||
"include": [ "views", "content" ]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -1,5 +0,0 @@
|
||||
footer {
|
||||
background-color: #808080;
|
||||
border-top: solid 1px black;
|
||||
color: white;
|
||||
}
|
@ -40,7 +40,7 @@
|
||||
<footer>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-right">@Model.Generator</div>
|
||||
<div class="col-xs-12 text-right">@Model.FooterLogoLight </div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB |
@ -2,7 +2,7 @@
|
||||
|
||||
@Section['Content']
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="col-xs-4 text-center">
|
||||
<h3>@Translate.Posts <span class="badge">@Model.Posts</span></h3>
|
||||
<p>
|
||||
<a href="/posts/list"><i class="fa fa-list-ul"></i> @Translate.ListAll</a>
|
||||
@ -10,7 +10,7 @@
|
||||
<a href="/post/new/edit"><i class="fa fa-plus"></i> @Translate.AddNew</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="col-xs-4 text-center">
|
||||
<h3>@Translate.Pages <span class="badge">@Model.Pages</span></h3>
|
||||
<p>
|
||||
<a href="/pages"><i class="fa fa-list-ul"></i> @Translate.ListAll</a>
|
||||
@ -18,9 +18,7 @@
|
||||
<a href="/page/new/edit"><i class="fa fa-plus"></i> @Translate.AddNew</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="col-xs-4 text-center">
|
||||
<h3>@Translate.Categories <span class="badge">@Model.Categories</span></h3>
|
||||
<p>
|
||||
<a href="/categories"><i class="fa fa-list-ul"></i> @Translate.ListAll</a>
|
||||
@ -29,4 +27,5 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
@EndSection
|
||||
|
@ -12,7 +12,7 @@
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="Permalink">@Translate.Permalink</label>
|
||||
<input type="text" name="Permalink" id="Permalink" class="form-control" value="@Model.Form.Permalink" />
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.webLog.urlBase/ </p>
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.WebLog.UrlBase/ </p>
|
||||
</div>
|
||||
<!-- // TODO: Markdown / HTML choice -->
|
||||
<div class="form-group">
|
||||
@ -48,7 +48,7 @@
|
||||
@EndSection
|
||||
|
||||
@Section['Scripts']
|
||||
<script type="text/javascript" src="/content/scripts/tinymce-init.js"></script>
|
||||
<script type="text/javascript" src="/admin/content/tinymce-init.js"></script>
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
$(document).ready(function () { $("#Title").focus() })
|
||||
|
@ -13,7 +13,7 @@
|
||||
<label class="control-label" for="Permalink">@Translate.Permalink</label>
|
||||
<input type="text" name="Permalink" id="Permalink" class="form-control" value="@Model.Form.Permalink" />
|
||||
<!-- // FIXME: hard-coded "http" -->
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.webLog.urlBase/ </p>
|
||||
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.WebLog.UrlBase/ </p>
|
||||
</div>
|
||||
<!-- // TODO: Markdown / HTML choice -->
|
||||
<div class="form-group">
|
||||
@ -47,19 +47,11 @@
|
||||
<h4 class="panel-title">@Translate.Categories</h4>
|
||||
</div>
|
||||
<div class="panel-body" style="max-height:350px;overflow:scroll;">
|
||||
<!-- // TODO: how to check the ones that are already selected? -->
|
||||
@Each.Categories
|
||||
<!-- - var tab = 0
|
||||
while tab < item.indent
|
||||
|
|
||||
- tab++
|
||||
- var attributes = {}
|
||||
if -1 < currentCategories.indexOf(item.category.id)
|
||||
- attributes.checked = 'checked' -->
|
||||
<input type="checkbox" id="Category-@Current.Item1" name="Category", value="@Current.Item1" />
|
||||
@Current.Indent
|
||||
<input type="checkbox" id="Category-@Current.Id" name="Category" value="@Current.Id" @Current.CheckedAttr />
|
||||
|
||||
<!-- // FIXME: the title should be the category description -->
|
||||
<label for="Category-@Current.Item1" title="@Current.Item2">@Current.Item2</label>
|
||||
<label for="Category-@Current.Id" title="@Current.Description">@Current.Name</label>
|
||||
<br/>
|
||||
@EndEach
|
||||
</div>
|
||||
@ -86,7 +78,7 @@
|
||||
@EndSection
|
||||
|
||||
@Section['Scripts']
|
||||
<script type="text/javascript" src="/content/scripts/tinymce-init.js"></script>
|
||||
<script type="text/javascript" src="/admin/content/tinymce-init.js"></script>
|
||||
<script type="text/javascript">
|
||||
/** <![CDATA[ */
|
||||
$(document).ready(function () { $("#Title").focus() })
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB |
@ -3,7 +3,7 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-right">
|
||||
@Model.FooterLogo
|
||||
@Model.FooterLogoDark
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user