8 Commits

  1. 17
      CHANGELOG.md
  2. 22
      assets/css/_forms.scss
  3. 8
      assets/css/app.scss
  4. 8
      lib/mirage/notes.ex
  5. 4
      lib/mirage/notes/note.ex
  6. 79
      lib/mirage_web/controllers/note_controller.ex
  7. 4
      lib/mirage_web/live/goto_anything_live.ex
  8. 2
      lib/mirage_web/live/modal_component.html.leex
  9. 2
      lib/mirage_web/live/note_live/index.ex
  10. 9
      lib/mirage_web/live/note_live/show.ex
  11. 59
      lib/mirage_web/live/show_note_live.ex
  12. 67
      lib/mirage_web/live/show_note_live.html.leex
  13. 10
      lib/mirage_web/templates/user/index.html.eex
  14. 2
      mix.exs
  15. 6
      priv/repo/migrations/20210215193839_add_domain_to_link.exs
  16. 4
      priv/repo/migrations/20210219221843_add_trigram_extension.exs
  17. 10
      priv/repo/migrations/20210221112501_add_views_and_last_viewed_to_notes.exs

17
CHANGELOG.md

@ -5,6 +5,23 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
<!-- changelog -->
## [v0.49.0](https://git.inhji.de/inhji/mirage/compare/v0.48.1...v0.49.0) (2021-02-21)
### Features:
* proper styles for modals
* add views and viewed at fields to notes
### Bug Fixes:
* old link to show note
* links on user page
## [v0.48.1](https://git.inhji.de/inhji/mirage/compare/v0.48.0...v0.48.1) (2021-02-21)

22
assets/css/_forms.scss

@ -1,8 +1,20 @@
#modal {
padding: 2rem;
padding: 0.5rem;
margin-left: -2rem;
margin-right: -2rem;
@include color-assign(background-color, surface);
position: absolute;
width: 60%;
position: relative;
z-index: 10;
box-shadow: $shadow;
.modal-close {
float: right;
font-size: 2rem;
}
form {
clear: both;
}
}
form {
@ -22,7 +34,9 @@ form {
input[type=password] {
@include color-assign(background-color, surface);
@include color-assign(color, on-surface);
border: 1px solid $border-base;
border: none;
border-bottom: 1px solid $border-base;
@include color-assign(border-color, on-surface);
margin-bottom: 1rem;

8
assets/css/app.scss

@ -50,6 +50,8 @@ $color-danger: #f2dede;
$border-base: #666;
$shadow: 1px 1px 3px 0px rgba(50, 50, 50, 0.75);
/* === Fonts ===*/
@font-face {
@ -293,7 +295,7 @@ kbd {
left: 15rem;
width: 30rem;
border: 1px solid white;
box-shadow: 1px 1px 3px 0px rgba(50, 50, 50, 0.75);
box-shadow: $shadow;
@include color-assign(background-color, surface);
@include color-assign(border-color, surface);
@ -326,10 +328,6 @@ kbd {
}
}
#modal {
z-index: 10;
}
/* === Content === */
article {

8
lib/mirage/notes.ex

@ -154,6 +154,13 @@ defmodule Mirage.Notes do
def preload_note(note), do: Repo.preload(note, @note_preloads)
def view_note!(note),
do:
update_note!(note, %{
views: note.views + 1,
viewed_at: DateTime.utc_now()
})
@doc """
Creates a note.
@ -194,7 +201,6 @@ defmodule Mirage.Notes do
note
|> Note.changeset(attrs)
|> Repo.update!()
|> preload_note()
end
@doc """

4
lib/mirage/notes/note.ex

@ -9,6 +9,8 @@ defmodule Mirage.Notes.Note do
field :title, :string
field :content, :string
field :content_html, :string
field :views, :integer
field :viewed_at, :naive_datetime
many_to_many :links, Link, join_through: "notes_links"
many_to_many :topics, Topic, join_through: "notes_topics"
@ -27,7 +29,7 @@ defmodule Mirage.Notes.Note do
@doc false
def changeset(note, attrs) do
note
|> cast(attrs, [:content, :title])
|> cast(attrs, [:content, :title, :views, :viewed_at])
|> validate_required([:content, :title])
|> Mirage.Markdown.maybe_render_markdown(:content, :content_html)
|> maybe_load_tag_string()

79
lib/mirage_web/controllers/note_controller.ex

@ -1,79 +0,0 @@
defmodule MirageWeb.NoteController do
use MirageWeb, :controller
alias Mirage.Notes
alias Mirage.Notes.Note
plug :require_authenticated_user when action in [:new, :edit, :update, :delete]
def index(conn, _params) do
notes = Notes.list_notes()
render(conn, "index.html", notes: notes)
end
def new(conn, _params) do
changeset = Notes.change_note(%Note{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"note" => note_params}) do
case Notes.create_note(note_params) do
{:ok, note} ->
note
|> Notes.preload_note()
|> Notes.Tags.update_tags(note_params["topic_string"])
|> Notes.link_note()
conn
|> put_flash(:info, "Note created successfully.")
|> redirect(to: Routes.live_path(conn, MirageWeb.ShowNoteLive, note))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
def edit(conn, %{"id" => id}) do
note =
id
|> Notes.get_note!()
|> Notes.preload_note()
changeset = Notes.change_note(note)
render(conn, "edit.html", note: note, changeset: changeset)
end
def update(conn, %{"id" => id, "note" => note_params}) do
note =
id
|> Notes.get_note!()
|> Notes.preload_note()
case Notes.update_note(note, note_params) do
{:ok, note} ->
note
|> Notes.Tags.update_tags(note_params["topic_string"])
|> Notes.link_note()
conn
|> put_flash(:info, "Note updated successfully.")
|> redirect(to: Routes.live_path(conn, MirageWeb.ShowNoteLive, note))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", note: note, changeset: changeset)
end
end
def delete(conn, %{"id" => id}) do
note =
id
|> Notes.get_note!()
|> Notes.preload_note()
{:ok, _note} = Notes.delete_note(note)
conn
|> put_flash(:info, "Note deleted successfully.")
|> redirect(to: Routes.note_path(conn, :index))
end
end

4
lib/mirage_web/live/goto_anything_live.ex

@ -33,9 +33,7 @@ defmodule MirageWeb.GotoAnythingLive do
IO.inspect("Redirecting to #{note.title}")
push_redirect(socket,
to: Routes.live_path(MirageWeb.Endpoint, MirageWeb.ShowNoteLive, note.id)
)
push_redirect(socket, to: Routes.show_note_path(@socket, :show, note))
else
socket
end

2
lib/mirage_web/live/modal_component.html.leex

@ -6,7 +6,7 @@
phx-page-loading>
<div class="phx-modal-content">
<%= live_patch raw("&times;"), to: @return_to, class: "phx-modal-close" %>
<%= live_patch raw("&times;"), to: @return_to, class: "phx-modal-close modal-close button" %>
<%= live_component @socket, @component, @opts %>
</div>
</div>

2
lib/mirage_web/live/note_live/index.ex

@ -8,7 +8,7 @@ defmodule MirageWeb.NoteLive.Index do
def mount(_params, %{"user_id" => user_id}, socket) do
{:ok,
socket
|> assign(:notes, Notes.list_notes())
|> assign(:notes, list_notes())
|> assign(:current_user, Mirage.Accounts.get_user!(user_id))}
end

9
lib/mirage_web/live/note_live/show.ex

@ -5,6 +5,9 @@ defmodule MirageWeb.NoteLive.Show do
alias Mirage.Links
alias Mirage.Links.Link
defp page_title(:show), do: "Show Note"
defp page_title(:edit), do: "Edit Note"
@impl true
def mount(_params, %{"user_id" => user_id}, socket) do
{:ok, socket |> assign(:current_user, Mirage.Accounts.get_user!(user_id))}
@ -18,6 +21,7 @@ defmodule MirageWeb.NoteLive.Show do
|> assign(
:note,
Notes.get_note!(id)
|> Notes.view_note!()
|> Notes.preload_note()
)
|> assign(:link_changeset, Link.changeset(%Link{}, %{note_id: id}))}
@ -31,9 +35,6 @@ defmodule MirageWeb.NoteLive.Show do
{:noreply, push_redirect(socket, to: Routes.note_index_path(socket, :index))}
end
defp page_title(:show), do: "Show Note"
defp page_title(:edit), do: "Edit Note"
def handle_event("delete_link", %{"link-id" => link_id}, socket) do
link = Links.get_link!(link_id)
{:ok, _} = Links.delete_link(link)
@ -41,6 +42,7 @@ defmodule MirageWeb.NoteLive.Show do
note =
socket.assigns.note.id
|> Notes.get_note!()
|> Notes.view_note!()
|> Notes.preload_note()
{:noreply, socket |> assign(%{note: note})}
@ -55,6 +57,7 @@ defmodule MirageWeb.NoteLive.Show do
note =
note_id
|> Notes.get_note!()
|> Notes.view_note!()
|> Notes.preload_note()
{:noreply,

59
lib/mirage_web/live/show_note_live.ex

@ -1,59 +0,0 @@
defmodule MirageWeb.ShowNoteLive do
use MirageWeb, :live_view
alias Mirage.Notes
alias Mirage.Links
alias Mirage.Links.Link
@impl true
def mount(_params, %{"user_id" => user_id}, socket) do
current_user = user_id && Mirage.Accounts.get_user!(user_id)
{:ok, socket |> assign(%{current_user: current_user})}
end
@impl true
def handle_params(%{"id" => note_id}, _uri, socket) do
note =
note_id
|> Notes.get_note!()
|> Notes.preload_note()
link_changeset = Link.changeset(%Link{}, %{note_id: note_id})
{:noreply, socket |> assign(%{note: note, link_changeset: link_changeset})}
end
def handle_event("delete_link", %{"link-id" => link_id}, socket) do
link = Links.get_link!(link_id)
{:ok, _} = Links.delete_link(link)
note =
socket.assigns.note.id
|> Notes.get_note!()
|> Notes.preload_note()
{:noreply, socket |> assign(%{note: note})}
end
@impl true
def handle_event("save_link", %{"link" => link}, socket) do
note_id = socket.assigns.note.id
with {:ok, link} <- Links.create_link(link),
{:ok, _note_link} <- Notes.create_note_link(%{link_id: link.id, note_id: note_id}) do
note =
note_id
|> Notes.get_note!()
|> Notes.preload_note()
{:noreply,
socket
|> assign(%{
note: note,
link_changeset: Link.changeset(%Link{}, %{note_id: note_id})
})}
else
_ ->
{:noreply, socket}
end
end
end

67
lib/mirage_web/live/show_note_live.html.leex

@ -1,67 +0,0 @@
<%= if @current_user do %>
<%= live_render @socket, MirageWeb.GotoAnythingLive, id: "goto-anything-wrapper" %>
<% end %>
<header class="hero">
<h1><span class="id"><%= "##{@note.id}" %></span> <%= @note.title %></h1>
<p><time datetime="<%= @note.inserted_at %>"><%= Timex.from_now(@note.inserted_at) %></time> / <time datetime="<%= @note.updated_at %>"><%= Timex.from_now(@note.updated_at) %></time></p>
<p class="tags">
<%= for topic <- @note.topics do %>
<span class="tag"><%= topic.text %></span>
<% end %>
</p>
</header>
<div class="width-full bg-content" phx-update="ignore" id="note-<%= @note.id %>">
<div class="content html">
<%= raw @note.content_html %>
</div>
</div>
<%= if not Enum.empty?(@note.backlinks) do %>
<section class="backlinks">
<h4>Backlinks</h4>
<%= for backlink <- @note.backlinks do %>
<div class="link-wrapper">
<%= live_patch backlink.title, to: Routes.live_path(@socket, MirageWeb.ShowNoteLive, backlink), class: "link" %>
</div>
<% end %>
</section>
<% end %>
<%= if not Enum.empty?(@note.links) do %>
<section class="sources">
<h4>Sources</h4>
<%= for link <- @note.links do %>
<div class="link-wrapper">
<%= link to: link.url, class: "link" do %>
<span class="flex"><%= link.title || link.url %></span>
<span class="flex"><%= link.domain %></span>
<% end %>
<%= if @current_user do %>
<%= link "🗑️ DELETE", to: "#", phx_click: "delete_link", phx_value_link_id: link.id, data: [confirm: "Are you sure?"] %>
<% end %>
</div>
<% end %>
</section>
<% end %>
<%= if @current_user do %>
<%= f = form_for @link_changeset, "#", [phx_submit: :save_link] %>
<fieldset>
<%= hidden_input f, :note_id %>
<%= url_input f, :url, placeholder: "Add new link and press ENTER" %>
</fieldset>
</form>
<% end %>
<%= if @current_user do %>
<div class="buttons">
<span><%= link "Edit", to: Routes.note_path(MirageWeb.Endpoint, :edit, @note), class: "button" %></span>
<span><%= link "Back", to: Routes.note_path(MirageWeb.Endpoint, :index), class: "button" %></span>
<span><%= link "Delete", to: Routes.note_path(MirageWeb.Endpoint, :delete, @note), method: :delete, data: [confirm: "Are you sure?"], class: "button" %></span>
</div>
<% end %>

10
lib/mirage_web/templates/user/index.html.eex

@ -9,7 +9,7 @@
<div class="cards">
<%= for note <- @notes.today do %>
<%= link to: Routes.live_path(@conn, MirageWeb.ShowNoteLive, note), class: "col card" do %>
<%= link to: Routes.note_show_path(@conn, :show, note), class: "col card" do %>
<strong><%= note.title %></strong>
<p><%= note.content |> String.slice(0..50) %></p>
<% end %>
@ -22,7 +22,7 @@
<div class="grid cards">
<%= for note <- @notes.last_edited do %>
<%= link to: Routes.live_path(@conn, MirageWeb.ShowNoteLive, note), class: "col card" do %>
<%= link to: Routes.note_show_path(@conn, :show, note), class: "col card" do %>
<strong><%= note.title %></strong>
<p><%= note.content |> String.slice(0..50) %></p>
<% end %>
@ -35,7 +35,7 @@
<div class="grid cards">
<%= for note <- @notes.unlinked do %>
<%= link to: Routes.live_path(@conn, MirageWeb.ShowNoteLive, note), class: "col card" do %>
<%= link to: Routes.note_show_path(@conn, :show, note), class: "col card" do %>
<strong><%= note.title %></strong>
<p><%= note.content |> String.slice(0..50) %></p>
<% end %>
@ -48,7 +48,7 @@
<div class="grid cards">
<%= for note <- @notes.untagged do %>
<%= link to: Routes.live_path(@conn, MirageWeb.ShowNoteLive, note), class: "col card" do %>
<%= link to: Routes.note_show_path(@conn, :show, note), class: "col card" do %>
<strong><%= note.title %></strong>
<p><%= note.content |> String.slice(0..50) %></p>
<% end %>
@ -61,7 +61,7 @@
<div class="grid cards">
<%= for note <- @notes.at do %>
<%= link to: Routes.live_path(@conn, MirageWeb.ShowNoteLive, note), class: "col card" do %>
<%= link to: Routes.note_show_path(@conn, :show, note), class: "col card" do %>
<strong><%= note.title %></strong>
<p><%= note.content |> String.slice(0..50) %></p>
<% end %>

2
mix.exs

@ -1,7 +1,7 @@
defmodule Mirage.MixProject do
use Mix.Project
@version "0.48.1"
@version "0.49.0"
def project do
[

6
priv/repo/migrations/20210215193839_add_domain_to_link.exs

@ -2,8 +2,8 @@ defmodule Mirage.Repo.Migrations.AddDomainToLink do
use Ecto.Migration
def change do
alter table(:links) do
add :domain, :string
end
alter table(:links) do
add :domain, :string
end
end
end

4
priv/repo/migrations/20210219221843_add_trigram_extension.exs

@ -2,10 +2,10 @@ defmodule Mirage.Repo.Migrations.AddTrigramExtension do
use Ecto.Migration
def up do
repo().query!("CREATE EXTENSION IF NOT EXISTS pg_trgm;")
repo().query!("CREATE EXTENSION IF NOT EXISTS pg_trgm;")
end
def down do
repo().query!("DROP EXTENSION IF EXISTS pg_trgm;")
repo().query!("DROP EXTENSION IF EXISTS pg_trgm;")
end
end

10
priv/repo/migrations/20210221112501_add_views_and_last_viewed_to_notes.exs

@ -0,0 +1,10 @@
defmodule Mirage.Repo.Migrations.AddViewsAndLastViewedToNotes do
use Ecto.Migration
def change do
alter table(:notes) do
add :views, :integer, default: 0
add :viewed_at, :naive_datetime
end
end
end
Loading…
Cancel
Save