This commit is contained in:
Inhji 2023-09-09 10:24:22 +02:00
parent dcf1cb96cf
commit c595b20668
20 changed files with 272 additions and 395 deletions

View file

@ -9,70 +9,79 @@
The base layer is for things like reset rules or default styles applied to plain HTML elements.
*/
@layer base {
:root {
--color-background: 255 255 255;
--color-foreground: 0 0 0;
--color-primary: 0 0 0;
}
:root[mode=dark] {
--color-background: 0 0 0;
--color-foreground: 255 255 255;
--color-primary: 255 255 255;
}
html {
font-family: 'Inter', sans-serif;
font-feature-settings: "case", "cpsp", "frac", "salt", "ccmp", "cv01", "cv02", "cv03", "cv04", "cv05", "cv06", "cv07", "cv09", "cv10", "cv11";
@apply text-slate-800;
}
header h1 { @apply text-xl; }
.stack > * + * {
margin-block-start: var(--flow-space, 1em);
}
/*
* ============= SITE LAYOUT =============
*/
#site-header {
@apply block px-3 py-6 bg-gradient-to-r from-slate-900 to-slate-950 text-white print:hidden;
nav ul {
@apply flex gap-3;
a { @apply p-3 rounded hover:bg-primary-500 transition; }
}
}
#primary-sidebar {
@apply col-span-1;
nav {
@apply flex flex-col md:flex-row lg:flex-col mb-6 lg:mb-0;
}
.menu {
@apply flex-1;
h2 {
@apply font-bold;
}
}
}
#site-content {
@apply grid grid-cols-1 lg:grid-cols-5 gap-0 lg:gap-12;
#secondary-sidebar {
@apply col-span-1;
}
#content-wrapper {
@apply col-span-4;
}
}
/*
* ============= PAGE LAYOUT =============
*/
header.page-header {
@apply border-b border-slate-300;
> h1 {
@apply text-3xl leading-loose font-bold text-slate-900;
}
> p {
@apply mb-3;
}
}
}
/*
The components layer is for class-based styles that you want to be able to override with utilities.
*/
@layer components {
#site-header {
@apply py-8 block px-3 bg-black text-white print:hidden;
}
#site-header nav ul {
@apply flex gap-3;
}
#site-content {
@apply grid grid-cols-1 lg:grid-cols-5 gap-12;
}
aside#primary-sidebar {
@apply col-span-1;
}
aside#primary-sidebar nav {
@apply flex flex-col md:flex-row lg:flex-col;
}
aside#primary-sidebar .menu {
@apply flex-1;
}
aside#primary-sidebar .menu h2 {
@apply font-bold;
}
aside#secondary-sidebar {
@apply col-span-1;
}
section#content-wrapper {
@apply col-span-4;
}
.divider {
@apply flex items-center my-8 before:flex-1 after:flex-1 before:content-[''] after:content-[''] before:p-[0.5px] after:p-[0.5px] w-full mx-auto last:hidden;
}

View file

@ -1,7 +0,0 @@
/*!
Theme: Gruvbox dark, hard
Author: Dawid Kurek (dawikur@gmail.com), morhetz (https://github.com/morhetz/gruvbox)
License: ~ MIT (or more permissive) [via base16-schemes-source]
Maintainer: @highlightjs/core-team
Version: 2021.09.0
*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#d5c4a1;background:#1d2021}.hljs ::selection,.hljs::selection{background-color:#504945;color:#d5c4a1}.hljs-comment{color:#665c54}.hljs-tag{color:#bdae93}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#d5c4a1}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#fb4934}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#fe8019}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#fabd2f}.hljs-strong{font-weight:700;color:#fabd2f}.hljs-addition,.hljs-code,.hljs-string,.hljs-title.class_.inherited__{color:#b8bb26}.hljs-built_in,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp{color:#8ec07c}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#83a598}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#d3869b}.hljs-emphasis{color:#d3869b;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#d65d0e}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700}

View file

@ -1,52 +0,0 @@
/*
1. Use a more-intuitive box-sizing model.
*/
*, *::before, *::after {
box-sizing: border-box;
}
/*
2. Remove default margin
*/
* {
margin: 0;
}
/*
3. Allow percentage-based heights in the application
*/
html, body {
height: 100%;
}
/*
Typographic tweaks!
4. Add accessible line-height
5. Improve text rendering
*/
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
/*
6. Improve media defaults
*/
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
/*
7. Remove built-in form typography styles
*/
input, button, textarea, select {
font: inherit;
}
/*
8. Avoid text overflows
*/
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
/*
9. Create a root stacking context
*/
#root, #__next {
isolation: isolate;
}

View file

@ -14,7 +14,12 @@ module.exports = {
],
darkMode: ['class', '[data-mode="dark"]'],
theme: {
container: { center: true }
container: { center: true },
extend: {
colors: {
primary: colors.pink
}
}
},
plugins: [
require("@tailwindcss/forms"),

View file

@ -8,7 +8,7 @@ defmodule Chiya.Tags do
alias Chiya.Tags.Tag
@preloads [notes: [:tags]]
@preloads [notes: [tags: [:notes]]]
defp with_preloads(query), do: preload(query, ^@preloads)
@doc """

View file

@ -74,20 +74,26 @@
<aside id="primary-sidebar">
<nav>
<div class="menu">
<h2>Info</h2>
<ul>
<li>Served by Chiya v<%= Application.spec(:chiya, :vsn) %></li>
<li>Made by Inhji</li>
</ul>
</div>
<div class="menu">
<h2>Links</h2>
<h2>Pages</h2>
<ul>
<li><a href={~p"/wiki"}>Wiki</a></li>
<li><a href={~p"/about"}>About</a></li>
<li><a href={~p"/bookmarks"}>Bookmarks</a></li>
</ul>
</div>
<div class="menu">
<h2>Channels</h2>
<ul>
<%= for channel <- @channels do %>
<li>
<a href={~p"/channel/#{channel.slug}"}>
<%= channel.name %>
</a>
</li>
<% end %>
</ul>
</div>
@ -99,20 +105,6 @@
<li><a href={identity.url}><%= identity.name %></a></li>
<% end %>
</ul>
</div>
<div class="menu">
<h2>Elsewhere</h2>
<ul>
<%= for channel <- @channels do %>
<li>
<a href={~p"/channel/#{channel.slug}"}>
<%= channel.name %>
</a>
</li>
<% end %>
</ul>
</div>
</nav>
</aside>
@ -139,13 +131,5 @@
<span class="p-note"><%= @profile.bio %></span>
</section>
<% end %>
<section class="flex h-1 w-full flex-row">
<div class="bg-rose-500 w-full"></div>
<div class="bg-violet-500 w-full"></div>
<div class="bg-blue-500 w-full"></div>
<div class="bg-cyan-500 w-full"></div>
<div class="bg-emerald-500 w-full"></div>
</section>
</body>
</html>

View file

@ -76,7 +76,7 @@ defmodule ChiyaWeb.PublicComponents do
<%= tag.name %>
</span>
<% end %>
<.dot class="text-theme-base/50 last:hidden" />
<.dot class="last:hidden" />
<% end %>
</span>
"""

View file

@ -1,5 +1,6 @@
defmodule ChiyaWeb.PageController do
use ChiyaWeb, :controller
alias Chiya.Channels
plug :put_layout, html: {ChiyaWeb.Layouts, :public}
@ -9,7 +10,7 @@ defmodule ChiyaWeb.PageController do
channel =
case settings.home_channel_id do
nil -> nil
id -> Chiya.Channels.get_channel!(id) |> Chiya.Channels.preload_channel_public()
id -> Channels.get_channel!(id) |> Channels.preload_channel_public()
end
render(conn, :home,
@ -20,8 +21,8 @@ defmodule ChiyaWeb.PageController do
def channel(conn, %{"slug" => channel_slug}) do
channel =
Chiya.Channels.get_channel_by_slug!(channel_slug)
|> Chiya.Channels.preload_channel_public()
Channels.get_channel_by_slug!(channel_slug)
|> Channels.preload_channel_public()
render(conn, :channel,
channel: channel,
@ -42,14 +43,14 @@ defmodule ChiyaWeb.PageController do
note = Chiya.Notes.get_note_by_slug_preloaded!(note_slug)
changeset = Chiya.Notes.change_note_comment(%Chiya.Notes.NoteComment{}, %{note_id: note.id})
if is_nil(note.published_at) and is_nil(conn.assigns.current_user) do
render_error(conn, :not_found)
else
if note.published_at || conn.assigns.current_user do
render(conn, :note,
note: note,
page_title: note.name,
changeset: changeset
)
else
render_error(conn, :not_found)
end
end
@ -57,66 +58,44 @@ defmodule ChiyaWeb.PageController do
note = Chiya.Notes.get_note_by_slug_preloaded("about")
user = Chiya.Accounts.get_user!(1)
render(conn, :about,
note: note,
user: user,
page_title: "About"
)
if note && user do
render(conn, :about,
note: note,
user: user,
page_title: "About"
)
else
render_error(conn, :not_found)
end
end
def wiki(conn, _params) do
[channel, notes_updated, notes_published] =
case conn.assigns.settings.wiki_channel_id do
nil ->
[nil, nil, nil]
if id = conn.assigns.settings.wiki_channel_id do
channel = Chiya.Channels.get_channel!(id)
notes = Chiya.Notes.list_notes_by_channel_updated(channel, 999)
id ->
channel = Chiya.Channels.get_channel!(id)
updated = Chiya.Notes.list_notes_by_channel_updated(channel, 5)
published = Chiya.Notes.list_notes_by_channel_published(channel, 5)
[channel, updated, published]
end
render(conn, :wiki,
channel: channel,
notes_updated: notes_updated,
notes_published: notes_published,
page_title: "Wiki"
)
render(conn, :wiki,
channel: channel,
notes: notes,
page_title: "Wiki"
)
else
render_error(conn, :not_found)
end
end
def bookmarks(conn, _params) do
[channel, notes, tags] =
case conn.assigns.settings.bookmark_channel_id do
nil ->
[nil, nil]
if id = conn.assigns.settings.bookmark_channel_id do
channel = Chiya.Channels.get_channel!(id)
notes = Chiya.Notes.list_notes_by_channel_published(channel, 999)
id ->
channel = Chiya.Channels.get_channel!(id)
notes = Chiya.Notes.list_notes_by_channel_published(channel, 999)
tags = group_tags(notes)
[channel, notes, tags]
end
render(conn, :bookmarks,
channel: channel,
notes: notes,
tags: tags,
page_title: "Bookmarks"
)
end
defp group_tags(notes) do
Enum.reduce(notes, [], fn n, acc ->
acc ++ n.tags
end)
|> Enum.uniq_by(fn t -> t.id end)
|> Enum.sort_by(fn t -> t.slug end, :asc)
|> Enum.group_by(
fn n -> String.first(n.name) end,
fn n -> n end
)
|> IO.inspect()
render(conn, :bookmarks,
channel: channel,
notes: notes,
page_title: "Bookmarks"
)
else
render_error(conn, :not_found)
end
end
end

View file

@ -5,7 +5,11 @@ defmodule ChiyaWeb.PageHTML do
embed_templates "page_html/*"
attr :notes, :list, required: true
attr :layout, :atom, default: :default
attr :show_content, :boolean, default: true
def note_list(assigns)
attr :notes, :list, required: true
attr :show_content, :boolean, default: true
def note_list_default(assigns)
@ -47,4 +51,16 @@ defmodule ChiyaWeb.PageHTML do
]
)
end
def group_tags(notes) do
Enum.reduce(notes, [], fn n, acc ->
acc ++ n.tags
end)
|> Enum.uniq_by(fn t -> t.id end)
|> Enum.sort_by(fn t -> t.slug end, :asc)
|> Enum.group_by(
fn n -> String.first(n.name) end,
fn n -> n end
)
end
end

View file

@ -1,20 +1,18 @@
<section class="max-w-2xl mx-auto">
<article class="h-card hcard">
<section class="flex gap-3">
<img
class="rounded-lg block text-center w-28 h-28 | u-photo"
src={ChiyaWeb.Uploaders.UserImage.url({@user.user_image, @current_user}, :thumb)}
/>
<.header class="flex-1">
<span class="p-name"><%= @user.name %></span>
<:subtitle><%= @user.bio %></:subtitle>
</.header>
</section>
<article class="h-card hcard | stack">
<section class="flex gap-3">
<img
class="rounded-lg block text-center w-28 h-28 | u-photo"
src={ChiyaWeb.Uploaders.UserImage.url({@user.user_image, @current_user}, :thumb)}
/>
<header class="page-header | flex-1">
<h1 class="p-name"><%= @user.name %></h1>
<p><%= @user.bio %></p>
</header>
</section>
<%= if @note do %>
<section class="mx-auto mt-8 prose prose-gruvbox md:prose-lg lg:prose-xl | p-summary e-content">
<%= Markdown.render(@note.content) |> raw %>
</section>
<% end %>
</article>
</section>
<%= if @note do %>
<section class="prose max-w-none | p-summary e-content">
<%= Markdown.render(@note.content) |> raw %>
</section>
<% end %>
</article>

View file

@ -1,40 +1,14 @@
<%= if @channel do %>
<header>
<h1><%= Enum.count(@notes) %> Bookmarks</h1>
</header>
<header class="page-header">
<h1><%= Enum.count(@notes) %> Bookmarks</h1>
</header>
<section class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-3">
<section class="col-span-1 md:col-span-2">
<%= if @channel.layout == :default do %>
<.note_list_default notes={@notes}/>
<% end %>
<%= if @channel.layout == :gallery do %>
<.note_list_gallery notes={@notes}/>
<% end %>
<%= if @channel.layout == :microblog do %>
<.note_list_microblog notes={@notes}/>
<% end %>
</section>
<section>
<ul>
<%= for {letter, tag_group} <- @tags do %>
<li class="mb-2">
<span class="capitalize text-theme-primary border border-theme-background1 rounded font-sm px-2 py-1 inline-block mb-2">
<%= letter %>
</span>
<%= for tag <- tag_group do %>
<a
href={~p"/tagged-with/#{tag.slug}"}
class="border border-theme-background1 rounded font-sm px-2 py-1 inline-block mb-2 hover:bg-theme-background1 transition"
>
<%= tag.name %> <span class="text-theme-base text-xs font-mono bg-theme-primary/25 rounded-full py-0.5 px-1 align-middle"><%= Enum.count(tag.notes) %></span>
</a>
<% end %>
</li>
<% end %>
</ul>
</section>
<section class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-3">
<section class="col-span-1 md:col-span-2">
<.note_list notes={@notes} layout={@channel.layout} />
</section>
<% end %>
<section>
<.tag_list notes={@notes} />
</section>
</section>

View file

@ -1,18 +1,8 @@
<section class="max-w-2xl mx-auto">
<.header>
<%= @channel.name %>
<:subtitle><%= Markdown.render(@channel.content) |> raw %></:subtitle>
</.header>
<header class="page-header">
<h1><%= @channel.name %></h1>
<p><%= Markdown.render(@channel.content) |> raw %></p>
</header>
<div class="w-full mt-6 sm:w-auto flex flex-col gap-1.5">
<%= if @channel.layout == :default do %>
<.note_list_default notes={@channel.notes}/>
<% end %>
<%= if @channel.layout == :gallery do %>
<.note_list_gallery notes={@channel.notes}/>
<% end %>
<%= if @channel.layout == :microblog do %>
<.note_list_microblog notes={@channel.notes}/>
<% end %>
</div>
</section>
<div class="w-full mt-6 sm:w-auto flex flex-col gap-1.5">
<.note_list notes={@channel.notes}/>
</div>

View file

@ -1,3 +1,3 @@
<%= if @channel do %>
<.note_list notes={@channel.notes} channel={@channel} />
<.note_list notes={@channel.notes} layout={@channel.layout} />
<% end %>

View file

@ -9,10 +9,14 @@
<ul class="flex gap-3">
<li>
<a href={~p"/admin/notes/#{@note}/edit"} class="button">
<.icon name="hero-pencil-square" /> Edit
Edit
</a>
</li>
<li>
<a href={~p"/admin/notes/#{@note}"} class="button">
Show in Admin
</a>
</li>
<li><a href={~p"/admin/notes/#{@note}"} class="button">Show in Admin</a></li>
</ul>
</section>
@ -50,25 +54,24 @@
<% end %>
<footer>
<%= if @note.published_at do %>
<span>Published</span>
<% else %>
<span>Unpublished</span>
<% end %>
<time class="font-semibold | dt-published"><%= pretty_date(@note.published_at) %></time>
<.dot />
<span>Last Updated</span>
<time class="font-semibold" datetime={datetime(@note.updated_at)}>
<%= pretty_date(@note.updated_at) %>
</time>
<%= if not Enum.empty?(@note.tags) do %>
<.dot />
<.tags note={@note} />
<% end %>
<%= if @note.kind != :post do %>
<.dot />
<span><%= @note.kind %></span>
<% end %>
<dl>
<dt>
<%= if @note.published_at do %>
<span>Published</span>
<% else %>
<span>Unpublished</span>
<% end %>
</dt>
<dd><time class="dt-published"><%= pretty_date(@note.published_at) %></time></dd>
<dt>Last updated</dt>
<dd>
<time class="dt-published"><%= pretty_date(@note.published_at) %></time>
</dd>
<dt>Tags</dt>
<dd><.tags note={@note} /></dd>
<dt>Kind</dt>
<dd><%= @note.kind %></dd>
</dl>
<a href={~p"/"} class="hidden | h-card u-author">Inhji</a>
<a href={~p"/note/#{@note.slug}"} class="hidden | u-url u-uid"><%= @note.name %></a>

View file

@ -1,9 +1,9 @@
<%= if @channel.layout == :default do %>
<.note_list_default notes={@notes_updated}/>
<%= if @layout == :default do %>
<.note_list_default notes={@notes} show_content={@show_content}/>
<% end %>
<%= if @channel.layout == :gallery do %>
<.note_list_gallery notes={@notes_updated}/>
<%= if @layout == :gallery do %>
<.note_list_gallery notes={@notes} show_content={@show_content}/>
<% end %>
<%= if @channel.layout == :microblog do %>
<.note_list_microblog notes={@notes_updated}/>
<%= if @layout == :microblog do %>
<.note_list_microblog notes={@notes} show_content={@show_content}/>
<% end %>

View file

@ -1,29 +1,31 @@
<section class="note-list default">
<section class="note-list default stack">
<%= for note <- assigns.notes do %>
<a
href={~p"/note/#{note.slug}"}
class="block rounded-lg px-6 py-4 border border-theme-background1 hover:bg-theme-background1 transition"
>
<header class="flex flex-row items-center gap-1">
<span class="text-theme-primary text-lg font-semibold leading-8 flex-1">
<%= note.name %>
</span>
<span class="text-theme-base/75 text-sm">
<%= pretty_date(note.published_at) %>
</span>
</header>
<article>
<a
href={~p"/note/#{note.slug}"}
class="block"
>
<header class="flex flex-row items-center gap-1">
<span class="text-theme-primary text-lg font-semibold leading-8 flex-1">
<%= note.name %>
</span>
<span class="text-theme-base/75 text-sm">
<%= pretty_date(note.published_at) %>
</span>
</header>
<%= if assigns.show_content do %>
<p class="text-theme-base">
<%= String.slice(note.content, 0..150) %>
</p>
<% end %>
<%= if assigns.show_content do %>
<p class="text-theme-base">
<%= String.slice(note.content, 0..150) %>
</p>
<% end %>
<%= if not Enum.empty?(note.tags) do %>
<span class="inline-block">
<.tags note={note} linked={false} />
</span>
<% end %>
</a>
<%= if not Enum.empty?(note.tags) do %>
<span class="inline-block">
<.tags note={note} linked={false} />
</span>
<% end %>
</a>
</article>
<% end %>
</section>

View file

@ -1,4 +1,3 @@
<section class="note-list gallery | stack">
<%= for note <- assigns.notes do %>
<article>

View file

@ -1,18 +1,14 @@
<section class="max-w-2xl mx-auto">
<.header>
Tagged with &ldquo;<%= @tag.name %>&rdquo;
<:subtitle><%= @tag.content %></:subtitle>
</.header>
<header class="page-header">
<h1><%= Enum.count(@tag.notes) %> Tagged with &ldquo;<%= @tag.name %>&rdquo;</h1>
<p><%= @tag.content %></p>
</header>
<div class="w-full mt-6 sm:w-auto flex flex-col gap-1.5">
<%= if @channel.layout == :default do %>
<.note_list_default note={@channel.notes}/>
<% end %>
<%= if @channel.layout == :gallery do %>
<.note_list_gallery note={@channel.notes}/>
<% end %>
<%= if @channel.layout == :microblog do %>
<.note_list_microblog note={@channel.notes}/>
<% end %>
</div>
</section>
<section class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-3">
<section class="col-span-1 md:col-span-2">
<.note_list notes={@tag.notes} />
</section>
<section>
<.tag_list notes={@tag.notes} />
</section>
</section>

View file

@ -0,0 +1,18 @@
<ul>
<%= for {letter, tag_group} <- group_tags(@notes) do %>
<li class="mb-2">
<span class="capitalize text-theme-primary border border-theme-background1 rounded font-sm px-2 py-1 inline-block mb-2">
<%= letter %>
</span>
<%= for tag <- tag_group do %>
<a
href={~p"/tagged-with/#{tag.slug}"}
class="border border-theme-background1 rounded font-sm px-2 py-1 inline-block mb-2 hover:bg-theme-background1 transition"
>
<%= tag.name %> <span class="text-theme-base text-xs font-mono bg-theme-primary/25 rounded-full py-0.5 px-1 align-middle"><%= Enum.count(tag.notes) %></span>
</a>
<% end %>
</li>
<% end %>
</ul>

View file

@ -1,51 +1,14 @@
<%= if @channel do %>
<header>
<h1><%= @channel.name %></h1>
</header>
<header class="page-header">
<h1><%= @channel.name %></h1>
<p><%= Markdown.render(@channel.content) |> raw %></p>
</header>
<section class="mt-6 flex flex-col">
<section class="prose prose-gruvbox md:prose-lg lg:prose-xl max-w-none">
<%= Markdown.render(@channel.content) |> raw %>
</section>
<aside class="flex flex-col md:flex-row gap-3 mt-6">
<div class="mt-6 flex flex-1 flex-col gap-1.5">
<h2 class="text-xl text-theme-base">Recently Updated</h2>
<%= if @channel.layout == :default do %>
<.note_list_default notes={@notes_updated}/>
<% end %>
<%= if @channel.layout == :gallery do %>
<.note_list_gallery notes={@notes_updated}/>
<% end %>
<%= if @channel.layout == :microblog do %>
<.note_list_microblog notes={@notes_updated}/>
<% end %>
</div>
<div class="mt-6 flex flex-1 flex-col gap-1.5">
<h2 class="text-xl text-theme-base">Recently Published</h2>
<%= if @channel.layout == :default do %>
<.note_list_default notes={@notes_published}/>
<% end %>
<%= if @channel.layout == :gallery do %>
<.note_list_gallery notes={@notes_published}/>
<% end %>
<%= if @channel.layout == :microblog do %>
<.note_list_microblog notes={@notes_published}/>
<% end %>
</div>
</aside>
<section class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-3">
<section class="col-span-1 md:col-span-2">
<.note_list notes={@notes} />
</section>
<% else %>
<section>
<.header>
Wiki
</.header>
<section class="prose">
Wiki is not set up.
</section>
<.tag_list notes={@notes} />
</section>
<% end %>
</section>