From 98b168ea1216b70a34d2f65132f33d7370d922fc Mon Sep 17 00:00:00 2001 From: Victor Roest Date: Mon, 18 Jan 2021 20:05:57 +0100 Subject: [PATCH] added search closes #5 --- .credo.exs | 2 +- .gitattributes | 1 + lib/dps/author.ex | 12 ++- lib/dps/cache.ex | 9 ++ lib/dps/poem.ex | 5 +- .../controllers/author_page_controller.ex | 8 +- .../controllers/poem_page_controller.ex | 8 +- lib/dps_web/telemetry.ex | 2 +- .../templates/author_page/index.html.eex | 14 +-- .../templates/author_page/new.html.eex | 2 +- lib/dps_web/templates/layout/app.html.eex | 6 +- .../templates/poem_page/index.html.eex | 6 +- lib/dps_web/templates/poem_page/new.html.eex | 2 +- priv/repo/seeds.exs | 9 +- priv/static/css/app.css | 88 ++++++++++++++----- priv/static/css/font.css | 24 ++++- priv/static/fonts/ddg-serp-icons.woff | 3 + 17 files changed, 151 insertions(+), 50 deletions(-) create mode 100644 priv/static/fonts/ddg-serp-icons.woff diff --git a/.credo.exs b/.credo.exs index d3e6ed4..aadd013 100644 --- a/.credo.exs +++ b/.credo.exs @@ -23,7 +23,7 @@ # included: [ "lib/", - "test/", + "test/" ], excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/"] }, diff --git a/.gitattributes b/.gitattributes index 9210e03..5418c37 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ *.ttf filter=lfs diff=lfs merge=lfs -text *.otf filter=lfs diff=lfs merge=lfs -text +*.woff filter=lfs diff=lfs merge=lfs -text diff --git a/lib/dps/author.ex b/lib/dps/author.ex index 29d3574..0ad42ba 100644 --- a/lib/dps/author.ex +++ b/lib/dps/author.ex @@ -31,10 +31,14 @@ defmodule Dps.Author.Query do |> Repo.insert() end - def all_authors(sort_by \\ [asc: :name]) do - Author - |> order_by(^sort_by) - |> Repo.all + def all_authors(query \\ "", sort_by \\ [asc: :name]) do + wildcard_query = "%#{query}%" + + from(a in Author, + order_by: ^sort_by, + where: ilike(a.name, ^wildcard_query) + ) + |> Repo.all() end def get_author_by_id(id) do diff --git a/lib/dps/cache.ex b/lib/dps/cache.ex index d715f17..55952a8 100644 --- a/lib/dps/cache.ex +++ b/lib/dps/cache.ex @@ -25,6 +25,10 @@ defmodule Dps.Cache do GenServer.cast(DpsCache, {:delete, key}) end + def clear do + GenServer.cast(DpsCache, :clear) + end + ### internal API def handle_call({:get, key}, _from, state) do reply = @@ -45,4 +49,9 @@ defmodule Dps.Cache do :ets.delete(@cache_table, key) {:noreply, state} end + + def handle_cast(:clear, state) do + :ets.delete_all_objects(@cache_table) + {:noreply, state} + end end diff --git a/lib/dps/poem.ex b/lib/dps/poem.ex index b4ec31f..a1fdee9 100644 --- a/lib/dps/poem.ex +++ b/lib/dps/poem.ex @@ -30,9 +30,12 @@ defmodule Dps.Poem.Query do alias Dps.{Repo, Poem, Cache} @spec get_all_poems :: nil | [%Poem{}] - def get_all_poems do + def get_all_poems(search \\ "") do + wildcard_search = "%#{search}%" + from(p in Poem, select: %Poem{id: p.id, author_id: p.author_id, title: p.title}, + where: ilike(p.title, ^wildcard_search), order_by: [desc: p.id] ) |> Repo.all() diff --git a/lib/dps_web/controllers/author_page_controller.ex b/lib/dps_web/controllers/author_page_controller.ex index 816591f..dc889bc 100644 --- a/lib/dps_web/controllers/author_page_controller.ex +++ b/lib/dps_web/controllers/author_page_controller.ex @@ -2,8 +2,10 @@ defmodule DpsWeb.AuthorPageController do use DpsWeb, :controller alias Dps.{Poem, Author} - def index(conn, _params) do - authors = Author.Query.all_authors() + def index(conn, params) do + query = get_in(params, ["query"]) + + authors = Author.Query.all_authors(query) render(conn, "index.html", authors: authors, title: "Authors") end @@ -22,7 +24,7 @@ defmodule DpsWeb.AuthorPageController do end def create(conn, params) do - %{"author" => author} = params + author = get_in(params, ["author"]) with {:ok, %Author{}} <- Author.Query.create_author(author) do redirect(conn, to: Routes.author_page_path(conn, :index)) diff --git a/lib/dps_web/controllers/poem_page_controller.ex b/lib/dps_web/controllers/poem_page_controller.ex index 71a3e1b..6efbd0b 100644 --- a/lib/dps_web/controllers/poem_page_controller.ex +++ b/lib/dps_web/controllers/poem_page_controller.ex @@ -2,8 +2,10 @@ defmodule DpsWeb.PoemPageController do use DpsWeb, :controller alias Dps.{Poem, Author} - def index(conn, _params) do - poems = Poem.Query.get_all_poems() + def index(conn, params) do + query = get_in(params, ["query"]) + + poems = Poem.Query.get_all_poems(query) render(conn, "index.html", poems: poems) end @@ -26,7 +28,7 @@ defmodule DpsWeb.PoemPageController do end def create(conn, params) do - %{"poem" => poem} = params + poem = get_in(params, ["poem"]) with {:ok, %Poem{id: id}} <- Poem.Query.create_poem(poem) do redirect(conn, to: Routes.poem_page_path(conn, :show, id)) diff --git a/lib/dps_web/telemetry.ex b/lib/dps_web/telemetry.ex index 7d95049..e086bd0 100644 --- a/lib/dps_web/telemetry.ex +++ b/lib/dps_web/telemetry.ex @@ -13,7 +13,7 @@ defmodule DpsWeb.Telemetry do # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}, # Add reporters as children of your supervision tree - {TelemetryMetricsPrometheus, [metrics: metrics()]}, + {TelemetryMetricsPrometheus, [metrics: metrics()]} # {Telemetry.Metrics.ConsoleReporter, metrics: custom_metrics()}, ] diff --git a/lib/dps_web/templates/author_page/index.html.eex b/lib/dps_web/templates/author_page/index.html.eex index 4300067..238d812 100644 --- a/lib/dps_web/templates/author_page/index.html.eex +++ b/lib/dps_web/templates/author_page/index.html.eex @@ -1,11 +1,15 @@ diff --git a/lib/dps_web/templates/author_page/new.html.eex b/lib/dps_web/templates/author_page/new.html.eex index 221c30a..a433c82 100644 --- a/lib/dps_web/templates/author_page/new.html.eex +++ b/lib/dps_web/templates/author_page/new.html.eex @@ -1,6 +1,6 @@

Add Author

-<%= form_for @changeset, Routes.author_page_path(@conn, :create), fn f -> %> +<%= form_for @changeset, Routes.author_page_path(@conn, :create), [class: "new"], fn f -> %> <%= text_input f, :name %> diff --git a/lib/dps_web/templates/layout/app.html.eex b/lib/dps_web/templates/layout/app.html.eex index 1cbfeb6..f196072 100644 --- a/lib/dps_web/templates/layout/app.html.eex +++ b/lib/dps_web/templates/layout/app.html.eex @@ -4,8 +4,12 @@ - <%= if assigns[:title] do @title else "Poems" end %> + <%= assigns[:title] || "Poems" %> + " as="font" crossorigin> + " as="font" crossorigin> + " as="font" crossorigin> + "/> "/> diff --git a/lib/dps_web/templates/poem_page/index.html.eex b/lib/dps_web/templates/poem_page/index.html.eex index ceb6dfd..eccc977 100644 --- a/lib/dps_web/templates/poem_page/index.html.eex +++ b/lib/dps_web/templates/poem_page/index.html.eex @@ -1,6 +1,10 @@
diff --git a/lib/dps_web/templates/poem_page/new.html.eex b/lib/dps_web/templates/poem_page/new.html.eex index 6eb9057..62fb434 100644 --- a/lib/dps_web/templates/poem_page/new.html.eex +++ b/lib/dps_web/templates/poem_page/new.html.eex @@ -1,6 +1,6 @@

Add Poem

-<%= form_for @changeset, Routes.poem_page_path(@conn, :create), fn f -> %> +<%= form_for @changeset, Routes.poem_page_path(@conn, :create), [class: "new"], fn f -> %>
diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index a8c3fd8..337d989 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -99,9 +99,9 @@ And that has made all the difference." }) Repo.insert!(%Poem{ - author_id: edgar_allan_poe, - title: "The Raven", - content: "Once upon a midnight dreary, while I pondered, weak and weary, + author_id: edgar_allan_poe, + title: "The Raven", + content: "Once upon a midnight dreary, while I pondered, weak and weary, Over many a quaint and curious volume of forgotten lore— While I nodded, nearly napping, suddenly there came a tapping, As of some one gently rapping, rapping at my chamber door. @@ -225,4 +225,5 @@ On the pallid bust of Pallas just above my chamber door; And his eyes have all the seeming of a demon’s that is dreaming, And the lamp-light o’er him streaming throws his shadow on the floor; And my soul from out that shadow that lies floating on the floor - Shall be lifted—nevermore!"}) + Shall be lifted—nevermore!" +}) diff --git a/priv/static/css/app.css b/priv/static/css/app.css index 0f495b9..5dbb3a3 100644 --- a/priv/static/css/app.css +++ b/priv/static/css/app.css @@ -1,14 +1,14 @@ -/* Defines 'Fira Sans' and 'Droid Serif' */ -@import "font.css"; - /* Variables */ :root { --text: black; --text-inverted: white; --bg: #fdfdfd; - --secondary: #444; - --border: #ccc; - --accent: darkslateblue; + --secondary: darkslategray; + --secondary-light: lightgray; + --secondary-text: #2d2d2d; + --accent: #483d8b; + --accent-dark: #342c66; + --rad: .3rem; } /* Main Content */ @@ -16,6 +16,11 @@ body { background-color: var(--bg); } +hr { + padding: 0; + margin: 0.3rem 0; +} + main.container { display: flex; flex-direction: column; @@ -68,7 +73,7 @@ dd { margin-bottom: 1em; } -ul { +dl, ul { padding: 0; margin: 0; } @@ -103,50 +108,93 @@ blockquote { pre { white-space: pre; - font-family: 'Droid Serif'; + font-family: 'Droid Serif', serif; line-height: 1.4; margin: 1em 0; font-size-adjust: inherit; } -/* Forms */ -form { +/* New Poem/Author Form */ +form.new { width: 50rem; max-width: 90%; } -form label { +form.new label { font-size: 1.2rem; } -form span.deemphasize { +form.new span.deemphasize { color: var(--secondary); opacity: 0.9; font-size: 1rem; } -form input[type=text], -form select, -form textarea { +form.new select, +form.new input[type=text], +form.new textarea { width: 100%; padding: 1.2em 2em; margin: 0.5em 0; - border: 1px solid var(--border); - border-radius: 4px; + border: 1px solid #ccc; + border-radius: var(--rad); box-sizing: border-box; } -form textarea { +form.new textarea { height: 35vh; } -form button[type="submit"] { +form.new button[type="submit"] { width: 100%; background-color: var(--accent); color: var(--text-inverted); padding: 1.2em 2em; margin: 0.5em 0; border: none; - border-radius: 4px; + border-radius: var(--rad); cursor: pointer; } + +/* Search form */ +form.search { + position: relative; + margin: 0 0 .3rem 0; + padding: 0; +} + +form.search input, form.search button { + height: 2rem; + border: 0; + font-size: 1rem; +} + +form.search input[type=search] { + appearance: none; + outline-width: thin; + width: calc(100% - 3rem); + background: var(--secondary-light); + padding: 0 0.5rem; + border-radius: var(--rad) 0 0 var(--rad); + position: relative; + + color: var(--secondary-text); +} + +form.search button[type="submit"] { + position: absolute; + bottom: 0; + right: 0; + font-family: ddg-serp-icons; + background: var(--accent); + width: 3rem; + border-radius: 0 var(--rad) var(--rad) 0; + cursor: pointer; + color: var(--text-inverted); + transition: all .15s ease-in; + transition-property: background; +} + +form.search button[type="submit"]:hover { + background: var(--accent-dark); +} diff --git a/priv/static/css/font.css b/priv/static/css/font.css index 95e032c..a25e880 100644 --- a/priv/static/css/font.css +++ b/priv/static/css/font.css @@ -3,27 +3,31 @@ font-family: 'Droid Serif'; font-style: normal; font-weight: normal; - src: url("../fonts/DroidSerif/DroidSerif-Regular.ttf") + src: local('Droid Serif Regular'), local("DroidSerif-Regular"), url("../fonts/DroidSerif/DroidSerif-Regular.ttf"); + font-display: swap; } @font-face { font-family: 'Droid Serif'; font-style: normal; font-weight: bold; - src: url("../fonts/DroidSerif/DroidSerif-Bold.ttf") + src: url("../fonts/DroidSerif/DroidSerif-Bold.ttf"); + font-display: swap; } @font-face { font-family: 'Droid Serif'; font-style: italic; font-weight: normal; - src: url("../fonts/DroidSerif/DroidSerif-Italic.ttf") + font-display: swap; + src: url("../fonts/DroidSerif/DroidSerif-Italic.ttf"); } @font-face { font-family: 'Droid Serif'; font-style: italic; font-weight: bold; + font-display: swap; src: url("../fonts/DroidSerif/DroidSerif-BoldItalic.ttf") } @@ -31,6 +35,7 @@ @font-face { font-family: 'Fira Sans'; font-weight: bold; + font-display: swap; font-style: normal; src: url("../fonts/FiraSans/FiraSans-Bold.otf") } @@ -38,6 +43,7 @@ @font-face { font-family: 'Fira Sans'; font-weight: bold; + font-display: swap; font-style: italic; src: url("../fonts/FiraSans/FiraSans-BoldItalic.otf") } @@ -45,6 +51,7 @@ @font-face { font-family: 'Fira Sans'; font-weight: normal; + font-display: swap; font-style: italic; src: url("../fonts/FiraSans/FiraSans-Italic.otf") } @@ -52,6 +59,7 @@ @font-face { font-family: 'Fira Sans'; font-weight: 200; + font-display: swap; font-style: normal; src: url("../fonts/FiraSans/FiraSans-Light.otf") } @@ -59,13 +67,21 @@ @font-face { font-family: 'Fira Sans'; font-weight: 200; + font-display: swap; font-style: italic; src: url("../fonts/FiraSans/FiraSans-LightItalic.otf") } @font-face { font-family: 'Fira Sans'; + font-display: swap; font-weight: normal; font-style: normal; - src: url("../fonts/FiraSans/FiraSans-Regular.otf") + src: local("Fira Sans"), local("FiraSans-Regular"), local("Fira Sans Regular"), url("../fonts/FiraSans/FiraSans-Regular.otf") +} + +@font-face { + font-family: ddg-serp-icons; + font-display: swap; + src: url("../fonts/ddg-serp-icons.woff") } diff --git a/priv/static/fonts/ddg-serp-icons.woff b/priv/static/fonts/ddg-serp-icons.woff new file mode 100644 index 0000000..bb1c7e3 --- /dev/null +++ b/priv/static/fonts/ddg-serp-icons.woff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:05ea6357028f2a0cbb71d3b59e64bb54ccd3b87f01e548b8146448422eb98080 +size 11288