commit 117d8793dd18968b4c78501224f0ff067458287f
parent 785a797b7c8083ec7f743555d4e23ae2bc71f443
Author: James Eversole <james@eversole.co>
Date: Mon, 26 Dec 2022 21:49:21 -0600
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.
Diffstat:
10 files changed, 204 insertions(+), 111 deletions(-)
diff --git a/ChangeLog.md b/ChangeLog.md
@@ -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
diff --git a/Purr.cabal b/Purr.cabal
@@ -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
diff --git a/package.yaml b/package.yaml
@@ -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
diff --git a/src/Feature/Sharing/HTTP.hs b/src/Feature/Sharing/HTTP.hs
@@ -9,14 +9,16 @@ import Feature.Sharing.SQLite (findByLink, insertNewSecret)
import Feature.Sharing.Templates (renderPw)
import Feature.Sharing.Types
-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 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
+
+
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"
diff --git a/src/Feature/Sharing/SQLite.hs b/src/Feature/Sharing/SQLite.hs
@@ -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
diff --git a/stack.yaml b/stack.yaml
@@ -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: {}
diff --git a/views/cassius/style.cassius b/views/cassius/style.cassius
@@ -4,18 +4,23 @@
@colorFour: #435F5D
html
- font-family: Courier
+ font-family: Monospace
background-color: #{colorTwo}
color: #{colorOne}
body
- margin: 3% 10% 0 10%
- font-size: 20px
- text-align: left
+ 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
- font-size: 2em
- color: #{colorThree}
+ text-align: center
+ font-size: 2em
+ margin: 0 auto 0 auto
+ color: #{colorThree}
.titleLink
- all: unset
- cursor: pointer
+ font-size: unset
+ cursor: pointer
+ font-weight: 100
.title h1
margin: 0.1em 0 0.1em 0
@@ -49,19 +60,22 @@ 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
-.logo
- margin: 4% 3% 0 0
- font-size: 1.2vw
- color: #{colorFour}
- text-align: center
+.generators .numberInput
+ background-color: #{colorTwo}
+
+.generatorRadio
+ margin: 0
-.content
- display: flex
-.column
- flex: 50%
+.logo
+ margin: 4% 3% 0 0
+ font-size: 1.2vw
+ color: #{colorFour}
+ text-align: center
.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
- margin-top: 1em
+ 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%
@@ -188,14 +274,17 @@ a
width: 25%
.title
- margin: 4% auto 2% auto
- font-size: 3em
+ margin: 4% auto 2% auto
.title h1
+ font-size: 2.5em
margin-bottom: 0
.requestedPw
max-width: 100%
+ .pwResult
+ font-size: 1.75em
+
.shareUtils
width: 100%
diff --git a/views/gen.hamlet b/views/gen.hamlet
@@ -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 />
diff --git a/views/index.hamlet b/views/index.hamlet
@@ -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 #title .title>
- <h1>
- <a #titleLink .titleLink href="/">purr
+ <div #main .main>
- <div #content .content>
+ <div #title .title>
+ <h1>
+ <a #titleLink .titleLink href="/">purr
- <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"
+ <div #generators
+ hx-trigger="load"
+ hx-get="/gen"
+ hx-target="#generators"
hx-swap="outerHTML"
- hx-include="[name='userLink']"
- />
- Get Secret
- <img class="htmx-indicator" src="/loading.svg" />
-
- <div #generators .column>
- <h2>Generators
- <button .mainButton
- hx-get="/gen"
- hx-target="#generators"
- hx-swap="outerHTML"
- />
- Load Generators
+ >
diff --git a/views/pw.hamlet b/views/pw.hamlet
@@ -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>