Completely overhaul frontend styling for clearer usage. Add support for entering either the full link or just link key for viewing secrets without opening links anew.
This commit is contained in:
parent
785a797b7c
commit
117d8793dd
@ -1,3 +1,6 @@
|
||||
# Changelog for Purr
|
||||
0.3.0:
|
||||
- Complete overhaul of frontend styling
|
||||
- Properly support entering either the full link or link key only in the "get secret" input field
|
||||
|
||||
## Unreleased changes
|
||||
|
@ -14,7 +14,7 @@ license: ISC
|
||||
license-file: LICENSE
|
||||
build-type: Simple
|
||||
extra-source-files:
|
||||
README.md
|
||||
README
|
||||
ChangeLog.md
|
||||
|
||||
library
|
||||
@ -60,6 +60,7 @@ library
|
||||
, random >=1.2
|
||||
, scotty ==0.12
|
||||
, shakespeare >=2.0.20
|
||||
, split >=0.2.3.4
|
||||
, sqlite-simple >=0.4.18.0
|
||||
, text >=1.2.5.0
|
||||
, time >=1.9
|
||||
@ -97,6 +98,7 @@ executable Purr-exe
|
||||
, random >=1.2
|
||||
, scotty ==0.12
|
||||
, shakespeare >=2.0.20
|
||||
, split >=0.2.3.4
|
||||
, sqlite-simple >=0.4.18.0
|
||||
, text >=1.2.5.0
|
||||
, time >=1.9
|
||||
@ -135,6 +137,7 @@ test-suite Purr-test
|
||||
, random >=1.2
|
||||
, scotty ==0.12
|
||||
, shakespeare >=2.0.20
|
||||
, split >=0.2.3.4
|
||||
, sqlite-simple >=0.4.18.0
|
||||
, text >=1.2.5.0
|
||||
, time >=1.9
|
||||
|
@ -1,12 +1,12 @@
|
||||
name: Purr
|
||||
version: 0.1.0.0
|
||||
version: 0.3.0
|
||||
license: ISC
|
||||
author: "James Eversole"
|
||||
maintainer: "james@eversole.co"
|
||||
copyright: "2022 James Eversole"
|
||||
|
||||
extra-source-files:
|
||||
- README.md
|
||||
- README
|
||||
- ChangeLog.md
|
||||
|
||||
default-extensions:
|
||||
@ -42,6 +42,7 @@ dependencies:
|
||||
- scotty == 0.12
|
||||
- shakespeare >= 2.0.20
|
||||
- sqlite-simple >= 0.4.18.0
|
||||
- split >= 0.2.3.4
|
||||
- time >= 1.9
|
||||
- text >= 1.2.5.0
|
||||
- wai-extra >= 3.1.12.1
|
||||
|
@ -9,13 +9,15 @@ import Feature.Sharing.SQLite (findByLink, insertNewSecret)
|
||||
import Feature.Sharing.Templates (renderPw)
|
||||
import Feature.Sharing.Types
|
||||
|
||||
import Control.Monad.Reader (ask, lift, liftIO)
|
||||
import Data.Maybe (listToMaybe)
|
||||
import Data.List.Split (splitOn)
|
||||
import Web.Scotty.Trans
|
||||
import Prelude
|
||||
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Lazy as LT
|
||||
|
||||
import Control.Monad.Reader (ask, lift, liftIO)
|
||||
import Data.Maybe (listToMaybe)
|
||||
import Web.Scotty.Trans
|
||||
import Prelude
|
||||
|
||||
routes :: PurrApp ()
|
||||
routes = do
|
||||
@ -28,7 +30,7 @@ routes = do
|
||||
post "/pw" $ do
|
||||
reqId <- param "userLink"
|
||||
res <- findByLink reqId
|
||||
html $ renderPw reqId res
|
||||
html $ renderPw (last $ splitOn "/" reqId) res
|
||||
|
||||
post "/new" $ do
|
||||
reqSecret <- param "newSec"
|
||||
|
@ -9,6 +9,7 @@ import Control.Monad.Reader (ask, lift, liftIO)
|
||||
import Crypto.Simple.CBC (encrypt, decrypt)
|
||||
import Data.Maybe (listToMaybe)
|
||||
import Data.Time.Clock.POSIX (getPOSIXTime)
|
||||
import Data.List.Split (splitOn)
|
||||
import Database.SQLite.Simple
|
||||
|
||||
import qualified Data.ByteString.Base64 as B64
|
||||
@ -22,7 +23,7 @@ findByLink link = do
|
||||
db <- dbPath
|
||||
key <- encKey
|
||||
conn <- liftIO $ open db
|
||||
res <- liftIO $ query conn "SELECT * from pws WHERE link = ?" (Only link)
|
||||
res <- liftIO $ query conn "SELECT * from pws WHERE link = ?" (Only (last $ splitOn "/" link))
|
||||
liftIO $ close conn
|
||||
readEncryptedSecret key res
|
||||
|
||||
|
@ -38,8 +38,7 @@ packages:
|
||||
extra-deps:
|
||||
- crypto-simple-0.1.0.0@sha256:5c0e1e04a814d903743d7543245951a91a46817230fdf478fadca57116805fc1,1502
|
||||
|
||||
ghc-options:
|
||||
'$everything': -haddock
|
||||
#ghc-options:
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
@ -4,18 +4,23 @@
|
||||
@colorFour: #435F5D
|
||||
|
||||
html
|
||||
font-family: Courier
|
||||
font-family: Monospace
|
||||
background-color: #{colorTwo}
|
||||
color: #{colorOne}
|
||||
|
||||
body
|
||||
margin: 3% 10% 0 10%
|
||||
margin: 1% auto
|
||||
font-size: 20px
|
||||
font-weight: 150
|
||||
text-align: left
|
||||
|
||||
header
|
||||
margin: 0 8% 0 0
|
||||
text-align: right
|
||||
|
||||
a
|
||||
text-decoration: none
|
||||
|
||||
h2
|
||||
font-family: monaco, Consolas, monospace
|
||||
text-transform: uppercase
|
||||
@ -29,14 +34,20 @@ p
|
||||
a
|
||||
color: #{colorThree}
|
||||
|
||||
.main
|
||||
margin: 1em auto
|
||||
max-width: 50%
|
||||
|
||||
.title
|
||||
margin: 0 auto 0 auto
|
||||
text-align: center
|
||||
font-size: 2em
|
||||
margin: 0 auto 0 auto
|
||||
color: #{colorThree}
|
||||
|
||||
.titleLink
|
||||
all: unset
|
||||
font-size: unset
|
||||
cursor: pointer
|
||||
font-weight: 100
|
||||
|
||||
.title h1
|
||||
margin: 0.1em 0 0.1em 0
|
||||
@ -49,7 +60,16 @@ a
|
||||
opacity: 1
|
||||
|
||||
.generators
|
||||
margin: 0 0 0.5em 0
|
||||
padding: 1em 0.5em 0.5em 1.5em
|
||||
background-color: #{colorTwo}
|
||||
box-shadow: 8px 8px 12px #ccc
|
||||
|
||||
.generators .numberInput
|
||||
background-color: #{colorTwo}
|
||||
|
||||
.generatorRadio
|
||||
margin: 0
|
||||
|
||||
|
||||
.logo
|
||||
margin: 4% 3% 0 0
|
||||
@ -57,12 +77,6 @@ a
|
||||
color: #{colorFour}
|
||||
text-align: center
|
||||
|
||||
.content
|
||||
display: flex
|
||||
|
||||
.column
|
||||
flex: 50%
|
||||
|
||||
.emptyReq
|
||||
height: 1%
|
||||
|
||||
@ -103,7 +117,7 @@ a
|
||||
transition: all 0.1s ease-in-out
|
||||
|
||||
.mainInput:focus
|
||||
border-bottom: 0.2em solid #{colorThree};
|
||||
border-bottom: 0.2em solid #{colorThree}
|
||||
|
||||
.mainInput:focus::placeholder
|
||||
color: #{colorThree}
|
||||
@ -130,7 +144,7 @@ a
|
||||
transition: all 0.1s ease-in-out
|
||||
|
||||
.numberInput:focus
|
||||
border-bottom: 0.2em solid #{colorThree};
|
||||
border-bottom: 0.2em solid #{colorThree}
|
||||
|
||||
.numberInput:focus::placeholder
|
||||
color: #{colorThree}
|
||||
@ -142,33 +156,108 @@ a
|
||||
.genResult
|
||||
color: #{colorFour}
|
||||
|
||||
.requestedPw
|
||||
text-align: center
|
||||
background-color: #333
|
||||
color: #f0f6f0
|
||||
margin: 1.5em 0 2em 0
|
||||
padding: 0.5em 0.5em 0.5em 1.5em
|
||||
box-shadow: 8px 8px 12px #ccc
|
||||
|
||||
.pwResult
|
||||
margin: 0 0 1em 0
|
||||
font-size: 1.5em
|
||||
color: #{colorFour}
|
||||
color: #f0f6f0
|
||||
|
||||
.shareNew
|
||||
margin-bottom: 2em
|
||||
padding: 0.5em 0.5em 0.5em 1.5em
|
||||
background-color: #{colorTwo}
|
||||
box-shadow: 8px 8px 12px #ccc
|
||||
margin: 1em 0 2em 0
|
||||
|
||||
.shareNew .mainInput
|
||||
background-color: #{colorTwo}
|
||||
|
||||
.shareNew .numberInput
|
||||
background-color: #{colorTwo}
|
||||
|
||||
.requestNew
|
||||
padding: 0.5em 0.5em 0.5em 1.5em
|
||||
background-color: #{colorTwo}
|
||||
box-shadow: 8px 8px 12px #ccc
|
||||
margin-bottom: 2em
|
||||
margin-top: 1em
|
||||
|
||||
.requestedPw
|
||||
max-width: 85%
|
||||
.requestNew .mainInput
|
||||
background-color: #{colorTwo}
|
||||
|
||||
.resLink
|
||||
font-size: 0.75em
|
||||
font-size: 0.8em
|
||||
|
||||
.validForm
|
||||
margin: 0.5em 0 0 0
|
||||
margin: 0
|
||||
|
||||
.radioLabel
|
||||
display: flex
|
||||
align-items: center
|
||||
border-radius: 100px
|
||||
margin: 0.3em 0
|
||||
padding: 0.3em 0.5em
|
||||
cursor: pointer
|
||||
transition: .3s
|
||||
|
||||
.radioLabel:hover, .radioLabel:focus-within
|
||||
background: hsla(0, 0%, 80%, .14)
|
||||
|
||||
.radioInput
|
||||
position: fixed
|
||||
left: 0
|
||||
top: 0
|
||||
width: 1px
|
||||
height: 1px
|
||||
opacity: 0
|
||||
z-index: -1
|
||||
|
||||
.radioDesign
|
||||
width: 22px
|
||||
height: 22px
|
||||
border-radius: 100px
|
||||
background: linear-gradient(to right bottom, #fff, #{colorThree})
|
||||
position: relative
|
||||
|
||||
.radioDesign::before
|
||||
content: ''
|
||||
display: inline-block
|
||||
width: inherit
|
||||
height: inherit
|
||||
border-radius: inherit
|
||||
background: hsl(0, 0%, 90%)
|
||||
transform: scale(1.1)
|
||||
transition: .3s
|
||||
|
||||
.radioInput:checked+.radioDesign::before
|
||||
transform: scale(0)
|
||||
|
||||
.radioText
|
||||
margin-left: 14px
|
||||
letter-spacing: 3px
|
||||
transition: .3s
|
||||
|
||||
.radioInput:checked~.radioText
|
||||
color: hsl(0, 0%, 40%)
|
||||
|
||||
.hidden
|
||||
display: none
|
||||
|
||||
@media only screen and (max-width : 768px)
|
||||
body
|
||||
text-align: center
|
||||
font-size: 16px
|
||||
|
||||
.content
|
||||
display: block
|
||||
.header
|
||||
margin: 0 2% 0 0
|
||||
|
||||
.main
|
||||
max-width: 90%
|
||||
|
||||
.mainButton
|
||||
width: 80%
|
||||
@ -176,9 +265,6 @@ a
|
||||
.genButton
|
||||
width: 80%
|
||||
|
||||
.generators
|
||||
text-align: left
|
||||
|
||||
.mainInput
|
||||
width: 95%
|
||||
max-width: 100%
|
||||
@ -189,13 +275,16 @@ a
|
||||
|
||||
.title
|
||||
margin: 4% auto 2% auto
|
||||
font-size: 3em
|
||||
|
||||
.title h1
|
||||
font-size: 2.5em
|
||||
margin-bottom: 0
|
||||
|
||||
.requestedPw
|
||||
max-width: 100%
|
||||
|
||||
.pwResult
|
||||
font-size: 1.75em
|
||||
|
||||
.shareUtils
|
||||
width: 100%
|
||||
|
@ -1,28 +1,20 @@
|
||||
<div #generators .column>
|
||||
<h2>Generators
|
||||
<h3>Random, Classic, XKCD
|
||||
<div #generators .generators>
|
||||
<form id="genForm">
|
||||
<div .generators">
|
||||
<input type="radio" id="gibberish" name="newSec" value="#{show genGibberish}">
|
||||
<label for="gibberish" .genResult>#{show genGibberish}
|
||||
<br />
|
||||
<input type="radio" id="oldschool" name="newSec" value="#{show genOldschool}">
|
||||
<label for="oldschool" .genResult>#{show genOldschool}
|
||||
<br />
|
||||
<input type="radio" id="xkcd" name="newSec" value="#{show genXkcd}">
|
||||
<label for="xkcd" .genResult>#{show genXkcd}
|
||||
<button .genButton
|
||||
hx-get="/gen"
|
||||
hx-target="#generators"
|
||||
hx-swap="outerHTML"
|
||||
/>
|
||||
Generate New
|
||||
<br />
|
||||
<div .generatorRadio">
|
||||
<label .radioLabel for="gibberish" .genResult>
|
||||
<input .radioInput type="radio" id="gibberish" name="newSec" value="#{show genGibberish}">
|
||||
<div .radioDesign>
|
||||
<div .radioText>#{show genGibberish}
|
||||
<label .radioLabel for="oldschool" .genResult>
|
||||
<input .radioInput type="radio" id="oldschool" name="newSec" value="#{show genOldschool}">
|
||||
<div .radioDesign>
|
||||
<div .radioText>#{show genOldschool}
|
||||
<label .radioLabel for="xkcd" .genResult>
|
||||
<input .radioInput type="radio" id="xkcd" name="newSec" value="#{show genXkcd}">
|
||||
<div .radioDesign>
|
||||
<div .radioText>#{show genXkcd}
|
||||
|
||||
<div .validForm>
|
||||
<h3>Share Generated Password
|
||||
Valid for:
|
||||
<br />
|
||||
<input .numberInput
|
||||
name="newSecDuration"
|
||||
type="number"
|
||||
@ -39,12 +31,19 @@
|
||||
value="20"
|
||||
onkeyup="if (value < 1 || value > 60) { value = 0 }"
|
||||
/> views
|
||||
<button .genButton
|
||||
<button .mainButton
|
||||
hx-post="/new"
|
||||
hx-target="#requestedPw"
|
||||
hx-swap="outerHTML"
|
||||
hx-include="[name='newSec']"
|
||||
/>
|
||||
Share Password
|
||||
share selected secret
|
||||
<img class="htmx-indicator" src="/loading.svg" />
|
||||
<button .mainButton
|
||||
hx-get="/gen"
|
||||
hx-target="#generators"
|
||||
hx-swap="outerHTML"
|
||||
/>
|
||||
regenerate
|
||||
<br />
|
||||
|
||||
|
@ -11,19 +11,20 @@ $doctype 5
|
||||
|
||||
<header>
|
||||
<a href="https://git.eversole.co/purr">
|
||||
Made with ♥
|
||||
| <a href="mailto:#{email}">Contact
|
||||
made with ♥
|
||||
|
|
||||
<a href="mailto:#{email}">contact
|
||||
|
||||
<div #main .main>
|
||||
|
||||
<div #title .title>
|
||||
<h1>
|
||||
<a #titleLink .titleLink href="/">purr
|
||||
|
||||
<div #content .content>
|
||||
|
||||
<div #shareUtils .column>
|
||||
<h2>Sharing Tools
|
||||
<div #shareUtils>
|
||||
$if (link == "/")
|
||||
<div #requestedPw .requestedPw>
|
||||
<div #requestedPw .hidden>
|
||||
<p .emptyReq>
|
||||
$else
|
||||
<div #requestedPw .requestedPw
|
||||
@ -35,16 +36,31 @@ $doctype 5
|
||||
>
|
||||
Loading... <img class="htmx-indicator" src="/loading.svg" />
|
||||
|
||||
<div #requestNew .requestNew>
|
||||
<p>
|
||||
<input .mainInput
|
||||
name="userLink"
|
||||
type="text"
|
||||
placeholder="enter a link to view secret"
|
||||
/>
|
||||
<button .mainButton
|
||||
hx-post="/pw"
|
||||
hx-target="#requestedPw"
|
||||
hx-swap="outerHTML"
|
||||
hx-include="[name='userLink']"
|
||||
/>
|
||||
get secret
|
||||
<img class="htmx-indicator" src="/loading.svg" />
|
||||
|
||||
<div #shareNew .shareNew>
|
||||
<h3>Share New Secret
|
||||
<p>
|
||||
<input .mainInput
|
||||
name="newSec"
|
||||
type="text"
|
||||
placeholder="Enter a Secret to Share"
|
||||
placeholder="enter a secret to share"
|
||||
/>
|
||||
<div .validForm>
|
||||
Valid for:
|
||||
valid for:
|
||||
<br />
|
||||
<input .numberInput
|
||||
name="newSecDuration"
|
||||
@ -68,31 +84,12 @@ $doctype 5
|
||||
hx-swap="outerHTML"
|
||||
hx-include="[id='shareNew']"
|
||||
/>
|
||||
Share Secret
|
||||
share secret
|
||||
<img class="htmx-indicator" src="/loading.svg" />
|
||||
|
||||
<div #requestNew .requestNew>
|
||||
<h3>Lookup
|
||||
<p>
|
||||
<input .mainInput
|
||||
name="userLink"
|
||||
type="text"
|
||||
placeholder="Enter a Link to View Secret"
|
||||
/>
|
||||
<button .mainButton
|
||||
hx-post="/pw"
|
||||
hx-target="#requestedPw"
|
||||
hx-swap="outerHTML"
|
||||
hx-include="[name='userLink']"
|
||||
/>
|
||||
Get Secret
|
||||
<img class="htmx-indicator" src="/loading.svg" />
|
||||
|
||||
<div #generators .column>
|
||||
<h2>Generators
|
||||
<button .mainButton
|
||||
<div #generators
|
||||
hx-trigger="load"
|
||||
hx-get="/gen"
|
||||
hx-target="#generators"
|
||||
hx-swap="outerHTML"
|
||||
/>
|
||||
Load Generators
|
||||
>
|
||||
|
@ -1,7 +1,6 @@
|
||||
<div #requestedPw .requestedPw>
|
||||
$maybe pw <- password
|
||||
<p .resLink>Here's the secret found at <a href="/pw/#{link}">/pw/#{link}</a>:
|
||||
<p .resLink>secret found at <a href="/pw/#{link}">/pw/#{link}</a>:
|
||||
<h3 .pwResult>#{pw}
|
||||
<hr />
|
||||
$nothing
|
||||
<h3 .pwResult>No secret found at <a href="/pw/#{link}">/pw/#{link}</a>
|
||||
<h3 .pwResult>no secret found at <a href="/pw/#{link}">/pw/#{link}</a>
|
||||
|
Loading…
x
Reference in New Issue
Block a user