Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Vlad Dumitru
konditorei
Commits
a2d32cda
Commit
a2d32cda
authored
Mar 04, 2021
by
Vlad Dumitru
Browse files
First commit
parents
Pipeline
#4792
failed with stages
in 0 seconds
Changes
33
Pipelines
1
Show whitespace changes
Inline
Side-by-side
resources/stylus/style.stylus
0 → 100644
View file @
a2d32cda
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,400;0,700;1,400&display=swap')
base-font-stack = 'Source Code Pro', monospace
base-font-weight = 400
bold-font-weight = 700
base-font-size = 18px
base-line-height = 1
base-fg = #333
base-bg = #fff
accent = #2274a5
accent-l = alpha(accent, 75%)
accent-ll = alpha(accent, 50%)
accent-d = darken(accent, 25%)
accent-dd = darken(accent, 50%)
*
box-sizing border-box
html
font-family base-font-stack
font-size base-font-size
font-weight base-font-weight
line-height base-line-height
color base-fg
background-color base-bg
width 100%
height 100%
main
height 100%
body
margin 2.5%
overflow hidden
width 95%
height 75%
.columns
display flex
flex-flow row nowrap
& > .column
flex-basis 50%
padding-left 12.5%
.sides
display flex
flex-flow row nowrap
height 100%
& > .side
flex-basis 50%
height 100%
& > .content
height 100%
overflow-y auto
scrollbar-color accent white
scrollbar-width thin
&.text-content
padding-left 25%
&.rhs
opacity 0.25
&.rhs:hover
opacity 1
hr
margin 0 0 0 25%
border none
height 1px
background-color accent
h1, h2, h3, h4
font-weight base-font-weight
margin 0
a
font-weight base-font-weight
text-decoration none
color accent
transition all 0.05s ease-in-out
&:hover
color accent-dd
&:active
color base-bg
background-color accent-l
a.ext::after
content 'ext'
position relative
font-size 0.66em
top -0.5rem
color base-fg
header
max-height 15%
display flex
flex-flow column nowrap
justify-content space-between
footer
opacity 0.25
padding 0
transform rotate(180deg)
.files
display flex
flex-flow column nowrap
& > .file:not(:last-child)
border-bottom 0.125rem dashed alpha(accent, 12.5%)
& > .file
display flex
flex-flow row nowrap
align-items baseline
justify-content space-between
padding 1rem 0
& > .name
font-size 1.25rem
& > .tags > span
font-size 0.75rem
border 0.125rem solid accent
color accent
padding 0.125rem
cursor pointer
nav
position relative
margin 0.5rem 0 1rem 12.5%
color alpha(base-fg, 25%)
&::before
position absolute
left -2ch
content '>'
& > .active
color base-fg
.layers > span
font-size 0.75rem
border 0.125rem solid alpha(accent, 12.5%)
color accent
padding 0.125rem
cursor pointer
& > sup
color alpha(accent, 50%)
.dim
color alpha(base-fg, 50%)
.fragments
margin-top 1.5rem
& > .fragment
display flex
flex-flow row nowrap
& > .id
flex-basis 15%
color accent-ll
text-align right
margin-right 1rem
& > .author
flex-basis 25%
& > .name
flex-basis 60%
h1.field > .name
flex-basis 12.5%
.field
display flex
flex-flow row nowrap
margin 0.5rem 0
& > .name
flex-basis 25%
padding-right 1rem
text-align right
& > .value
flex-basis 75%
.history
& > .header
display inline-block
margin-bottom 0.25rem
padding-bottom 0.25rem
border-bottom solid 1px accent-ll
& > .date-time
font-size 0.75em
& > .author
font-size 0.75em
& > .message
font-size 0.75rem
margin-bottom 0.5rem
.text-content
font-size 0.75rem
line-height 1.5
& > h1, h2, h3
position relative
& > h1
left -1ch
& > h2
left -2ch
& > h1
font-size 1.5rem
margin-top 3rem
& > h2
font-size 1rem
& > h1::before
content '#'
left -1ch
& > h2::before
content '##'
left -2ch
& > h1::before, h2::before, h3::before
font-weight bold-font-weight
color accent
position relative
& ul
list-style-type none
list-style-position outside
padding 0
position relative
& > li
margin 0 0 0.5rem 0
& > ul
margin-left 2ch
margin-bottom 1rem
& > li::before
position absolute
left -2ch
content '-'
src/clj/konditorei/config.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.config
(
:require
[
cprop.core
:refer
[
load-config
]]
[
cprop.source
:as
source
]
[
mount.core
:refer
[
args
defstate
]]))
(
defstate
env
:start
(
load-config
:merge
[(
args
)
(
source/from-system-props
)
(
source/from-env
)]))
src/clj/konditorei/core.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.core
(
:require
[
konditorei.handler
:as
handler
]
[
konditorei.nrepl
:as
nrepl
]
[
luminus.http-server
:as
http
]
[
konditorei.config
:refer
[
env
]]
[
clojure.tools.cli
:refer
[
parse-opts
]]
[
clojure.tools.logging
:as
log
]
[
mount.core
:as
mount
])
(
:gen-class
))
;; log uncaught exceptions in threads
(
Thread/setDefaultUncaughtExceptionHandler
(
reify
Thread$UncaughtExceptionHandler
(
uncaughtException
[
_
thread
ex
]
(
log/error
{
:what
:uncaught-exception
:exception
ex
:where
(
str
"Uncaught exception on"
(
.getName
thread
))}))))
(
def
cli-options
[[
"-p"
"--port PORT"
"Port number"
:parse-fn
#
(
Integer/parseInt
%
)]])
(
mount/defstate
^
{
:on-reload
:noop
}
http-server
:start
(
http/start
(
->
env
(
update
:io-threads
#
(
or
%
(
*
2
(
.availableProcessors
(
Runtime/getRuntime
)))))
(
assoc
:handler
(
handler/app
))
(
update
:port
#
(
or
(
->
env
:options
:port
)
%
))
(
select-keys
[
:handler
:host
:port
])))
:stop
(
http/stop
http-server
))
(
mount/defstate
^
{
:on-reload
:noop
}
repl-server
:start
(
when
(
env
:nrepl-port
)
(
nrepl/start
{
:bind
(
env
:nrepl-bind
)
:port
(
env
:nrepl-port
)}))
:stop
(
when
repl-server
(
nrepl/stop
repl-server
)))
(
defn
stop-app
[]
(
doseq
[
component
(
:stopped
(
mount/stop
))]
(
log/info
component
"stopped"
))
(
shutdown-agents
))
(
defn
start-app
[
args
]
(
doseq
[
component
(
->
args
(
parse-opts
cli-options
)
mount/start-with-args
:started
)]
(
log/info
component
"started"
))
(
.addShutdownHook
(
Runtime/getRuntime
)
(
Thread.
stop-app
)))
(
defn
-main
[
&
args
]
(
start-app
args
))
src/clj/konditorei/handler.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.handler
(
:require
[
konditorei.middleware
:as
middleware
]
[
konditorei.layout
:refer
[
error-page
]]
[
konditorei.routes.bundle
:refer
[
bundle-routes
]]
[
konditorei.routes.tree
:refer
[
tree-routes
]]
[
reitit.ring
:as
ring
]
[
ring.middleware.content-type
:refer
[
wrap-content-type
]]
[
ring.middleware.webjars
:refer
[
wrap-webjars
]]
[
konditorei.env
:refer
[
defaults
]]
[
mount.core
:as
mount
]))
(
mount/defstate
init-app
:start
((
or
(
:init
defaults
)
(
fn
[])))
:stop
((
or
(
:stop
defaults
)
(
fn
[]))))
(
mount/defstate
app-routes
:start
(
ring/ring-handler
(
ring/router
[(
bundle-routes
)
(
tree-routes
)])
(
ring/routes
(
ring/create-resource-handler
{
:path
"/"
})
(
wrap-content-type
(
wrap-webjars
(
constantly
nil
)))
(
ring/create-default-handler
{
:not-found
(
constantly
(
error-page
{
:status
404
,
:title
"404 - Page not found"
}))
:method-not-allowed
(
constantly
(
error-page
{
:status
405
,
:title
"405 - Not allowed"
}))
:not-acceptable
(
constantly
(
error-page
{
:status
406
,
:title
"406 - Not acceptable"
}))}))))
(
defn
app
[]
(
middleware/wrap-base
#
'app-routes
))
src/clj/konditorei/layout.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.layout
(
:require
[
clojure.java.io
]
[
selmer.parser
:as
parser
]
[
selmer.filters
:as
filters
]
[
markdown.core
:refer
[
md-to-html-string
]]
[
ring.util.http-response
:refer
[
content-type
ok
]]
[
ring.util.anti-forgery
:refer
[
anti-forgery-field
]]
[
ring.middleware.anti-forgery
:refer
[
*anti-forgery-token*
]]
[
ring.util.response
]))
(
parser/set-resource-path!
(
clojure.java.io/resource
"html"
))
(
parser/add-tag!
:csrf-field
(
fn
[
_
_
]
(
anti-forgery-field
)))
(
filters/add-filter!
:markdown
(
fn
[
content
]
[
:safe
(
md-to-html-string
content
)]))
(
defn
render
"renders the HTML template located relative to resources/html"
[
request
template
&
[
params
]]
(
content-type
(
ok
(
parser/render-file
template
(
assoc
params
:page
template
:csrf-token
*anti-forgery-token*
)))
"text/html; charset=utf-8"
))
(
defn
error-page
"error-details should be a map containing the following keys:
:status - error status
:title - error title (optional)
:message - detailed error message (optional)
returns a response map with the error page as the body
and the status specified by the status key"
[
error-details
]
{
:status
(
:status
error-details
)
:headers
{
"Content-Type"
"text/html; charset=utf-8"
}
:body
(
parser/render-file
"error.html"
error-details
)})
src/clj/konditorei/middleware.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.middleware
(
:require
[
konditorei.env
:refer
[
defaults
]]
[
clojure.tools.logging
:as
log
]
[
konditorei.layout
:refer
[
error-page
]]
[
ring.middleware.anti-forgery
:refer
[
wrap-anti-forgery
]]
[
konditorei.middleware.formats
:as
formats
]
[
muuntaja.middleware
:refer
[
wrap-format
wrap-params
]]
[
konditorei.config
:refer
[
env
]]
[
ring.middleware.flash
:refer
[
wrap-flash
]]
[
ring.adapter.undertow.middleware.session
:refer
[
wrap-session
]]
[
ring.middleware.defaults
:refer
[
site-defaults
wrap-defaults
]])
)
(
defn
wrap-internal-error
[
handler
]
(
fn
[
req
]
(
try
(
handler
req
)
(
catch
Throwable
t
(
log/error
t
(
.getMessage
t
))
(
error-page
{
:status
500
:title
"Something very bad has happened!"
:message
"We've dispatched a team of highly trained gnomes to take care of the problem."
})))))
(
defn
wrap-csrf
[
handler
]
(
wrap-anti-forgery
handler
{
:error-response
(
error-page
{
:status
403
:title
"Invalid anti-forgery token"
})}))
(
defn
wrap-formats
[
handler
]
(
let
[
wrapped
(
->
handler
wrap-params
(
wrap-format
formats/instance
))]
(
fn
[
request
]
;; disable wrap-formats for websockets
;; since they're not compatible with this middleware
((
if
(
:websocket?
request
)
handler
wrapped
)
request
))))
(
defn
wrap-base
[
handler
]
(
->
((
:middleware
defaults
)
handler
)
wrap-flash
(
wrap-session
{
:cookie-attrs
{
:http-only
true
}})
(
wrap-defaults
(
->
site-defaults
(
assoc-in
[
:security
:anti-forgery
]
false
)
(
dissoc
:session
)))
wrap-internal-error
))
src/clj/konditorei/middleware/formats.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.middleware.formats
(
:require
[
luminus-transit.time
:as
time
]
[
muuntaja.core
:as
m
]))
(
def
instance
(
m/create
(
->
m/default-options
(
update-in
[
:formats
"application/transit+json"
:decoder-opts
]
(
partial
merge
time/time-deserialization-handlers
))
(
update-in
[
:formats
"application/transit+json"
:encoder-opts
]
(
partial
merge
time/time-serialization-handlers
)))))
src/clj/konditorei/nrepl.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.nrepl
(
:require
[
nrepl.server
:as
nrepl
]
[
clojure.tools.logging
:as
log
]))
(
defn
start
"Start a network repl for debugging on specified port followed by
an optional parameters map. The :bind, :transport-fn, :handler,
:ack-port and :greeting-fn will be forwarded to
clojure.tools.nrepl.server/start-server as they are."
[{
:keys
[
port
bind
transport-fn
handler
ack-port
greeting-fn
]}]
(
try
(
log/info
"starting nREPL server on port"
port
)
(
nrepl/start-server
:port
port
:bind
bind
:transport-fn
transport-fn
:handler
handler
:ack-port
ack-port
:greeting-fn
greeting-fn
)
(
catch
Throwable
t
(
log/error
t
"failed to start nREPL"
)
(
throw
t
))))
(
defn
stop
[
server
]
(
nrepl/stop-server
server
)
(
log/info
"nREPL server stopped"
))
src/clj/konditorei/routes/bundle.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.routes.bundle
(
:require
[
konditorei.layout
:as
layout
]
[
clojure.tools.logging
:as
log
]
[
konditorei.middleware
:as
middleware
]
[
konditorei.speechcake
:as
speechcake
]
[
konditorei.util
:as
util
]))
(
defn-
parse-history
[
h
]
(
let
[[
d
a
m
]
h
]
{
:date
(
java.util.Date.
(
*
1000
(
Long/parseLong
d
)))
:author
a
:message
m
}))
(
defn
render-bundle
[
request
]
(
let
[
key
(
->
request
:path-params
:key
)
bundle
(
speechcake/bundle
key
)
layers
(
:layers
bundle
)
frags
(
:fragments
bundle
)
history
(
map
parse-history
(
:history
bundle
))]
(
log/debug
key
bundle
(
util/breadcrumbs-to
key
))
(
layout/render
request
"bundle.html"
{
:breadcrumbs
(
util/breadcrumbs-to
key
)
:name
(
:name
bundle
)
:layers
layers
:fragments
frags
:history
history
:key
key
})))
(
defn
bundle-routes
[]
[
"/bundle"
{
:middleware
[
middleware/wrap-csrf
middleware/wrap-formats
]}
[
"*key"
{
:get
render-bundle
}]])
src/clj/konditorei/routes/tree.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.routes.tree
(
:require
[
konditorei.layout
:as
layout
]
[
clojure.tools.logging
:as
log
]
[
konditorei.middleware
:as
middleware
]
[
konditorei.speechcake
:as
speechcake
]
[
konditorei.util
:as
util
]))
(
defn
render-tree
[
request
]
(
let
[
key
(
->
request
:path-params
:key
)
tree
(
speechcake/tree
key
)
readme
(
speechcake/readme
)]
(
log/debug
key
tree
(
util/breadcrumbs-to
key
))
(
layout/render
request
"tree.html"
{
:breadcrumbs
(
util/breadcrumbs-to
key
)
:tree
tree
:key
key
:readme
readme
})))
(
defn
tree-routes
[]
[
"/tree"
{
:middleware
[
middleware/wrap-csrf
middleware/wrap-formats
]}
[
"*key"
{
:get
render-tree
}]])
src/clj/konditorei/speechcake.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.speechcake
(
:require
[
clj-http.client
:as
client
]
[
clojure.string
:as
str
]
[
clojure.data.json
:as
json
]))
(
def
SPEECHCAKE_URL
"http://localhost:8080/"
)
(
defn
url
[
path
]
(
str
SPEECHCAKE_URL
(
str/join
"/"
path
)))
(
defn-
decode
[
req
]
(
json/read-str
(
:body
req
)
:key-fn
keyword
))
(
defn
tree
[
key
]
(
->
(
url
[
"tree"
key
])
client/get
decode
))
(
defn
bundle
[
key
]
(
->
(
url
[
"bundle"
key
])
client/get
decode
))
(
defn
readme
[]
(
->
(
url
[
"readme"
])
client/get
:body
))
(
defn
update-object
[
key
data
]
(
->
(
url
[
"update"
key
])
(
client/post
data
)
decode
))
src/clj/konditorei/util.clj
0 → 100644
View file @
a2d32cda
(
ns
konditorei.util
(
:require
[
clojure.string
:as
str
]))
(
defn
breadcrumbs-to
[
key
]
(
loop
[
xs
(
->>
(
str/split