Implements new thread modal.
This commit is contained in:
parent
35930799a9
commit
c966ec8f92
4 changed files with 163 additions and 45 deletions
81
redesign/newthread.nim
Normal file
81
redesign/newthread.nim
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
when defined(js):
|
||||
import sugar, httpcore, options, json
|
||||
import dom except Event
|
||||
|
||||
include karax/prelude
|
||||
import karax / [kajax, kdom]
|
||||
|
||||
import error, replybox, threadlist, post
|
||||
import karaxutils
|
||||
|
||||
type
|
||||
NewThreadModal* = ref object
|
||||
shown: bool
|
||||
loading: bool
|
||||
onNewThread: proc (threadId, postId: int)
|
||||
error: Option[PostError]
|
||||
replyBox: ReplyBox
|
||||
|
||||
proc onCreatePost(httpStatus: int, response: kstring, state: NewThreadModal) =
|
||||
postFinished:
|
||||
state.shown = false
|
||||
state.onNewThread(0, 0) # TODO
|
||||
|
||||
proc onCreateClick(ev: Event, n: VNode, state: NewThreadModal) =
|
||||
state.loading = true
|
||||
state.error = none[PostError]()
|
||||
|
||||
let uri = makeUri("login")
|
||||
# TODO: This is a hack, karax should support this.
|
||||
let formData = newFormData()
|
||||
#formData.append("" TODO
|
||||
ajaxPost(uri, @[], cast[cstring](formData),
|
||||
(s: int, r: kstring) => onCreatePost(s, r, state))
|
||||
|
||||
proc onClose(ev: Event, n: VNode, state: NewThreadModal) =
|
||||
state.shown = false
|
||||
ev.preventDefault()
|
||||
|
||||
proc newNewThreadModal*(
|
||||
onNewThread: proc (threadId, postId: int)
|
||||
): NewThreadModal =
|
||||
NewThreadModal(
|
||||
shown: false,
|
||||
onNewThread: onNewThread,
|
||||
replyBox: newReplyBox(nil)
|
||||
)
|
||||
|
||||
proc show*(state: NewThreadModal) =
|
||||
state.shown = true
|
||||
|
||||
proc render*(state: NewThreadModal): VNode =
|
||||
result = buildHtml():
|
||||
tdiv(class=class({"active": state.shown}, "modal modal-lg"),
|
||||
id="new-thread-modal"):
|
||||
a(href="", class="modal-overlay", "aria-label"="close",
|
||||
onClick=(ev: Event, n: VNode) => onClose(ev, n, state))
|
||||
tdiv(class="modal-container"):
|
||||
tdiv(class="modal-header"):
|
||||
a(href="", class="btn btn-clear float-right",
|
||||
"aria-label"="close",
|
||||
onClick=(ev: Event, n: VNode) => onClose(ev, n, state))
|
||||
tdiv(class="modal-title h5"):
|
||||
text "New Thread"
|
||||
tdiv(class="modal-body"):
|
||||
tdiv(class="content"):
|
||||
input(class="form-input", `type`="text", name="username",
|
||||
placeholder="Type the title here")
|
||||
renderContent(state.replyBox, none[Thread](), none[Post]())
|
||||
|
||||
tdiv(class="modal-footer"):
|
||||
button(class="btn",
|
||||
onClick=(ev: Event, n: VNode) =>
|
||||
onClose(ev, n, state)):
|
||||
text "Cancel"
|
||||
button(class=class(
|
||||
{"loading": state.loading},
|
||||
"btn btn-primary"
|
||||
),
|
||||
onClick=(ev: Event, n: VNode) =>
|
||||
(onCreateClick(ev, n, state))):
|
||||
text "Create thread"
|
||||
|
|
@ -113,6 +113,23 @@ $logo-height: $navbar-height - 20px;
|
|||
}
|
||||
}
|
||||
|
||||
#new-thread-modal {
|
||||
.modal-container .modal-body {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
margin-bottom: $control-padding-y*2;
|
||||
}
|
||||
|
||||
textarea.form-input, .panel-body > div {
|
||||
margin-top: $control-padding-y*2;
|
||||
resize: none;
|
||||
min-height: 40vh;
|
||||
max-height: 45vh;
|
||||
}
|
||||
}
|
||||
|
||||
// - Thread table
|
||||
.thread-title {
|
||||
a, a:visited, a:hover {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ when defined(js):
|
|||
state.preview = true
|
||||
state.loading = true
|
||||
state.error = none[PostError]()
|
||||
state.rendering = none[kstring]()
|
||||
|
||||
let formData = newFormData()
|
||||
formData.append("msg", state.text)
|
||||
|
|
@ -55,6 +56,10 @@ when defined(js):
|
|||
ajaxPost(uri, @[], cast[cstring](formData),
|
||||
(s: int, r: kstring) => onPreviewPost(s, r, state))
|
||||
|
||||
proc onMessageClick(e: Event, n: VNode, state: ReplyBox) =
|
||||
state.preview = false
|
||||
state.error = none[PostError]()
|
||||
|
||||
proc onReplyPost(httpStatus: int, response: kstring, state: ReplyBox) =
|
||||
postFinished:
|
||||
state.text = ""
|
||||
|
|
@ -84,6 +89,53 @@ when defined(js):
|
|||
# `value` on the node? We need to document this better :)
|
||||
state.text = cast[dom.TextAreaElement](n.dom).value
|
||||
|
||||
proc renderContent*(state: ReplyBox, thread: Option[Thread],
|
||||
post: Option[Post]): VNode =
|
||||
result = buildHtml():
|
||||
tdiv(class="panel"):
|
||||
tdiv(class="panel-nav"):
|
||||
ul(class="tab tab-block"):
|
||||
li(class=class({"active": not state.preview}, "tab-item"),
|
||||
onClick=(e: Event, n: VNode) =>
|
||||
onMessageClick(e, n, state)):
|
||||
a(class="c-hand"):
|
||||
text "Message"
|
||||
li(class=class({"active": state.preview}, "tab-item"),
|
||||
onClick=(e: Event, n: VNode) =>
|
||||
onPreviewClick(e, n, state)):
|
||||
a(class="c-hand"):
|
||||
text "Preview"
|
||||
tdiv(class="panel-body"):
|
||||
if state.preview:
|
||||
if state.loading:
|
||||
tdiv(class="loading")
|
||||
elif state.rendering.isSome():
|
||||
verbatim(state.rendering.get())
|
||||
else:
|
||||
textarea(class="form-input", rows="5",
|
||||
onChange=(e: Event, n: VNode) =>
|
||||
onChange(e, n, state),
|
||||
value=state.text)
|
||||
|
||||
if state.error.isSome():
|
||||
p(class="text-error",
|
||||
style=style(StyleAttr.marginTop, "0.4rem")):
|
||||
text state.error.get().message
|
||||
|
||||
if thread.isSome:
|
||||
tdiv(class="panel-footer"):
|
||||
button(class=class(
|
||||
{"loading": state.loading},
|
||||
"btn btn-primary float-right"
|
||||
),
|
||||
onClick=(e: Event, n: VNode) =>
|
||||
onReplyClick(e, n, state, thread.get(), post)):
|
||||
text "Reply"
|
||||
button(class="btn btn-link float-right",
|
||||
onClick=(e: Event, n: VNode) =>
|
||||
onCancelClick(e, n, state)):
|
||||
text "Cancel"
|
||||
|
||||
proc render*(state: ReplyBox, thread: Thread, post: Option[Post],
|
||||
hasMore: bool): VNode =
|
||||
if not state.shown:
|
||||
|
|
@ -106,44 +158,4 @@ when defined(js):
|
|||
button(class="btn"):
|
||||
italic(class="fas fa-arrow-up")
|
||||
tdiv(class="information-content"):
|
||||
tdiv(class="panel"):
|
||||
tdiv(class="panel-nav"):
|
||||
ul(class="tab tab-block"):
|
||||
li(class=class({"active": not state.preview}, "tab-item"),
|
||||
onClick=(e: Event, n: VNode) => (state.preview = false)):
|
||||
a(class="c-hand"):
|
||||
text "Message"
|
||||
li(class=class({"active": state.preview}, "tab-item"),
|
||||
onClick=(e: Event, n: VNode) =>
|
||||
onPreviewClick(e, n, state)):
|
||||
a(class="c-hand"):
|
||||
text "Preview"
|
||||
tdiv(class="panel-body"):
|
||||
if state.preview:
|
||||
if state.loading:
|
||||
tdiv(class="loading")
|
||||
elif state.rendering.isSome():
|
||||
verbatim(state.rendering.get())
|
||||
else:
|
||||
textarea(class="form-input", rows="5",
|
||||
onChange=(e: Event, n: VNode) =>
|
||||
onChange(e, n, state),
|
||||
value=state.text)
|
||||
|
||||
if state.error.isSome():
|
||||
tdiv(class="toast toast-error",
|
||||
style=style(StyleAttr.marginTop, "0.4rem")):
|
||||
text state.error.get().message
|
||||
|
||||
tdiv(class="panel-footer"):
|
||||
button(class=class(
|
||||
{"loading": state.loading},
|
||||
"btn btn-primary float-right"
|
||||
),
|
||||
onClick=(e: Event, n: VNode) =>
|
||||
onReplyClick(e, n, state, thread, post)):
|
||||
text "Reply"
|
||||
button(class="btn btn-link float-right",
|
||||
onClick=(e: Event, n: VNode) =>
|
||||
onCancelClick(e, n, state)):
|
||||
text "Cancel"
|
||||
renderContent(state, some(thread), post)
|
||||
|
|
@ -24,24 +24,30 @@ when defined(js):
|
|||
include karax/prelude
|
||||
import karax / [vstyles, kajax, kdom]
|
||||
|
||||
import karaxutils, error
|
||||
import karaxutils, error, newthread
|
||||
|
||||
type
|
||||
State = ref object
|
||||
list: Option[ThreadList]
|
||||
loading: bool
|
||||
status: HttpCode
|
||||
newThread: NewThreadModal
|
||||
|
||||
proc onNewThread(threadId, postId: int)
|
||||
proc newState(): State =
|
||||
State(
|
||||
list: none[ThreadList](),
|
||||
loading: false,
|
||||
status: Http200
|
||||
status: Http200,
|
||||
newThread: newNewThreadModal(onNewThread)
|
||||
)
|
||||
|
||||
var
|
||||
state = newState()
|
||||
|
||||
proc onNewThread(threadId, postId: int) =
|
||||
discard
|
||||
|
||||
proc genTopButtons(): VNode =
|
||||
result = buildHtml():
|
||||
section(class="navbar container grid-xl", id="main-buttons"):
|
||||
|
|
@ -57,7 +63,8 @@ when defined(js):
|
|||
button(class="btn btn-link"): text "Most Active"
|
||||
button(class="btn btn-link"): text "Categories"
|
||||
section(class="navbar-section"):
|
||||
button(class="btn btn-secondary"):
|
||||
button(class="btn btn-secondary",
|
||||
onClick=(e: Event, n: VNode) => state.newThread.show()):
|
||||
italic(class="fas fa-plus")
|
||||
text " New Thread"
|
||||
|
||||
|
|
@ -174,4 +181,5 @@ when defined(js):
|
|||
proc renderThreadList*(): VNode =
|
||||
result = buildHtml(tdiv):
|
||||
genTopButtons()
|
||||
genThreadList()
|
||||
genThreadList()
|
||||
render(state.newThread)
|
||||
Loading…
Add table
Add a link
Reference in a new issue