diff --git a/assets/app.css b/assets/app.css index 56fff6e..875ef8e 100644 --- a/assets/app.css +++ b/assets/app.css @@ -1,580 +1,222 @@ -/* -Main CSS file for madr.se -If you have any questions regarding the CSS, feel free -to contact me: yttan at madr dot se - -Table of contents, 7-1 inspired - -1. Base -2. Components -3. Layout -4. Pages -5. Themes -6. Vendors -7. Shame -*/ - -/* === 1. Base === */ - -/* -Normalize and resets. -Only properties, element and attribute selectors are allowed in this -section. - -All dynamic values that should change according to user preferences -(dark or light color mode, reduced motion etc) and agent abilities -(small handheld screen, big desktop screen) are handled by properties -when appliable. - -This is to avoid redeclarating CSS rules. -*/ - -:root { - /* colors, dark mode default */ - --color: hsl(0 0 90%); - --bgcolor: hsl(180 75% 6%); - --tree-item-accent-color: dimgrey; - --panel-bg-color: hsla(0 0 50% / 0.16); - --monospace-color: springgreen; - --monospace-color-inline: seagreen; - --a-color: gold; - - /* typography, mobile first */ - --base-font-size: 1.33em; - --page-title-font-size: 2em; - --tree-font-size: 0.85em; - --section-heading-lv2-font-size: 1.5em; - --section-heading-lv3-font-size: 1.2em; - --section-heading-lv4-font-size: 1em; - --system-serif-fonts: Cambria, Cochin, Georgia, Times, "Times New Roman", - serif; - --system-sansserif-fonts: apple-system, system-ui, BlinkMacSystemFont, - Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; - --monospace-fonts: "JetBrains mono", monaco, menlo, meslo, "Courier New", - Courier, monospace; - - /* whitespace */ - --gap-sm: 0.5em; - --gap-md: 1em; - --gap-lg: 3em; - - /* transitions */ - --animation-duration: 0.5s; - - /* dimensions and aspect ratios */ - --map-ratio: 1; - - @media (min-width: 666px) { - --base-font-size: 1.66em; - --tree-font-size: 0.67em; - } -} - -html { - color: var(--color); - background-color: var(--bgcolor); - font: normal var(--base-font-size) / 1.5 var(--system-sansserif-fonts); -} - body { + background: #222; margin: 0; - - > footer > p { - margin-top: var(--gap-lg); - color: #666; - font-size: 0.66em; - } -} - -a { - color: var(--a-color); -} - -input, -button { - font-size: 1.2em; - padding: 0.25em; -} - -h1, -h2, -h3 { - font-family: var(--system-serif-fonts); + background-image: linear-gradient( + 175deg, + #212223, + #222 350px, + #302928 345px, + #282828 + ); + font-family: + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + Oxygen, + Ubuntu, + Cantarell, + "Open Sans", + "Helvetica Neue", + sans-serif; } h1 { - margin: 0.5em 0; - line-height: 0.95; - font-size: var(--page-title-font-size); - - @media (min-width: 666px) { - text-transform: lowercase; - margin-top: 0.5em; - margin-bottom: 0.5em; - text-align: right; - line-height: 0.9; - color: var(--tree-item-accent-color); - font-weight: normal; - } -} - -h2, -h3 { - margin-top: 2em; - line-height: 1.1; + font-size: 1.75em; + letter-spacing: -0.066em; } h2 { - font-size: var(--section-heading-lv2-font-size); - border-bottom: 3px solid var(--panel-bg-color); + font-size: 1.33em; } -h3 { - font-size: var(--section-heading-lv3-font-size); +p, +li { + line-height: 1.66em; } +h3, h4 { - font-size: var(--section-heading-lv4-font-size); + font-size: 1em; +} + +main { + margin: 0 0 0 13em; + max-width: 37em; +} + +.cards { + display: flex; + flex-direction: column; + gap: 1.33em; +} + +.card { + background-color: #fff; + border: 2px solid #444; + padding: 3em; + border-radius: 9px; + box-shadow: 0 0 5px #000; + + :first-child { + margin-top: 0; + } + + :last-child { + margin-bottom: 0; + } + + &.collapsed { + border-top-left-radius: 0; + border-top-right-radius: 0; + } } pre { - margin: 2em 0; - background-color: #022; - color: var(--monospace-color); + padding: 0.5em; + background-color: #1e2025; + color: #96df71; + position: relative; + margin: 1em 2em; overflow-y: auto; - padding: 0.66em; - box-shadow: 4px 4px 0 var(--panel-bg-color); - position: relative; - line-height: 1.2; - font-size: 0.8em; - > button { - font-size: 0.75em; + button { position: absolute; - top: 0.25em; - right: 0.25em; + top: 2px; + right: 2px; } } -code { - font-family: var(--monospace-fonts); - - &.inline { - color: var(--monospace-color-inline); - background: #f3f3f3; - font-size: 0.9em; - } -} - -section { - position: relative; - - & > h2 { - background: var(--bgcolor); - color: var(--color); - padding: 0.5em 0.25em; - border-bottom: 0; - } -} - -img { - max-width: 100%; - display: block; - height: auto; -} - -ul, -ol { - clear: left; -} - -p { - margin: 1em 0; -} - -article { - line-height: 1.33; -} - -figure { - margin: 0; -} - -figcaption { - text-align: center; - margin-top: 0.5em; -} - -table { - width: 100%; -} - -td, -th { - background-color: var(--background-color-l); - padding: 0.25em; - font-size: 0.8em; - border: 1px solid rgb(128, 128, 128, 0.5); -} - -th { - background-color: var(--background-color-ll); - text-transform: uppercase; - color: var(--em-color); - font-weight: normal; -} - -li { - color: var(--em-color); - margin: 0.25em 0; -} - -li:first-child { - margin-top: 0; -} - -li:last-child { - margin-bottom: 0; -} - -li::marker { - color: var(--link-color); -} - -blockquote { - color: var(--em-color); - font-size: 1.2em; - line-height: 1.2; - font-style: italic; - border-left: 5px solid var(--background-color-l); - margin: 1em 1em 1em 0; - padding-left: 1em; -} - -blockquote p::after, -blockquote p::before { - content: '"'; -} - -/* === /Base === */ -/* === 2. Components === */ - -/* -Use kebab case named classes to identify components, and nesting -to group subcomponents. - -Element selectors are preferred as subcomponents, due to the simple -nature of this site. As a general rule though, classes are the most -versatile. -*/ - -.home-search, -.profiles { - font-size: var(--tree-font-size); -} - .sr-only { position: absolute; - left: -999em; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; } -.flx { - display: flex; - justify-content: space-between; - align-items: center; -} +.breadcrumbs { + border-radius: 8px 8px 0 0; + padding: 1em; + > .trail > span::after { + content: "/"; + } + background: #080808; + background-image: linear-gradient( + #080808 0, + #080808 50%, + #161616 50%, + #080808 100% + ); + color: #fff; -.sticky { - position: sticky; - top: 0; -} - -.interactive-map { - aspect-ratio: var(--map-ratio); -} - -.home-h1 { - font-size: 1.33em; -} - -.list-link { - &::after { - content: " →"; + a { + color: #fff; } } -.feed-link { - &::after { - content: " ↗"; +.head { + color: #fff; + background-color: #345; + + padding: 1em 2em; + border-radius: 0 0 8px 8px; + margin-bottom: 1.5em; + + :first-child { + margin-top: 0; + } + + a { + color: #fff; } } .skiplink { position: absolute; - top: -5em; - transition: top var(--animation-duration) ease-out; - padding: 0.25em 0.5em; + top: -1.75em; + left: 1em; + background-color: #ff0; + color: #000; + text-decoration: none; + padding: 0.25em; + transition: top 0.25s ease-out; &:focus { top: 1em; } } -.tree { - list-style: none; - margin: 0; - padding: 0; +nav { display: flex; - flex-direction: column; - gap: 0.66em; - font-size: var(--tree-font-size); + margin: 2em 0 1em; - > li { - text-align: center; - display: grid; - grid-template-columns: 50px 1fr auto; - align-items: center; - margin: 0; - gap: 0.5em; - padding: 0.75em; - min-height: 50px; - background-color: rgba(128, 128, 128, 0.1); - border: 1px solid rgba(192, 192, 192, 0.1); - - &:focus-within { - background-color: rgba(128, 128, 128, 0.25); - } - - > small { - opacity: 0.66; - font-family: var(--monospace-fonts); - font-size: 0.66em; - } - } - - > .article { - --tree-item-accent-color: rebeccapurple; - } - - > .album { - --tree-item-accent-color: goldenrod; - } - - > .link { - --tree-item-accent-color: honeydew; - } - - > .events { - --tree-item-accent-color: firebrick; - } - - a { - color: var(--color); - text-decoration: none; - flex: 1; - - &:hover, - &:focus { - text-decoration: underline; - } - } -} - -.landing { - display: flex; - flex-direction: column; - align-items: center; - padding: 2em 0; - box-sizing: border-box; - gap: 1.66em; -} - -.breadcrumbs { - display: block; - margin: var(--gap-sm) 0; - padding: var(--gap-sm); - border: 1px solid rgb(128, 128, 128, 0.25); - background-color: var(--panel-bg-color); - border-radius: 0; - - > span { - display: inline; - - &:after { - content: " /"; - } - } - - a { - color: var(--color); - } -} - -.months { - grid-auto-flow: rows; - display: grid; - list-style: none; - grid-template-columns: repeat(3, 1fr); - gap: 0.5em; - padding-left: 0; - margin: 2.75em 0; - - > li { - margin: 0; - } -} - -.article { - > div > p:first-child::first-letter { - @media (min-width: 500px) { - float: left; - font-size: 7em; - border: 8px double hsl(0 0 50%); - padding: 0.1em; - margin-right: 0.066em; - font-style: normal; - font-family: var(--system-serif-fonts); - } - } - - > footer { - font-style: italic; - font-size: 0.8em; - text-align: right; - - > p { - margin-top: 2.75em; - margin-bottom: 0; - } - } -} - -.articles { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 3em; - grid-auto-rows: 1fr; - - > * { - display: flex; - flex-direction: column; - justify-content: flex-end; - border-top: 6px solid red; - - &:focus-within { - background-color: #333; - } - } - - time { - border-top: 1px solid crimson; - padding: 0.25em 0.5em; - } -} - -.links { - > :is(h2, h3) { - margin-top: 3em; - } -} - -.brutal-legend { - display: flex; - gap: 1em; - flex-direction: row-reverse; - - > p { - flex: 1; - margin: 0; - } - - > img { - aspect-ratio: 1; - } -} - -.profiles { - display: flex; - gap: 1.66em; - list-style: none; - margin: 0; - - > li { + > ul { + list-style: none; margin: 0; padding: 0; + display: flex; + gap: 1.5em; + background: #111; + padding: 0.33em 1.5em 0.25em; + border-radius: 0 1.33em 1.33em 0; + border: 2px solid #333; + border-left-width: 0; + padding-left: 13em; + } + + a { + text-decoration: none; + color: #fff; + line-height: 1; } } -/* === /Components === */ -/* === 3. Layout === */ -/* -Containers and wrappers for components. -Only class selectors allowed, with the following element selectors as -exceptions: aside, body, footer, header, main and nav. -*/ -body { - margin: 0 auto; - max-width: 33em; - box-sizing: border-box; - min-height: 100vh; - padding: 0 0.5em; -} -/* === /Layout === */ -/* === 4. Pages === */ -/* -Styles that should only apply to certain pages. -*/ -/* === /Pages === */ -/* === 5. Themes === */ -/* -Styles to create user-customized themes. +.anders { + img { + position: fixed; + top: 1em; + left: 1em; + aspect-ratio: 1; + border-radius: 50%; + width: 175px; -This section adapts the design to the following user preferences: -Color theme, reduced motion -*/ -@media (prefers-color-scheme: light) { - :root { - --color: #000; - --bgcolor: #fff; - --a-color: blue; + &:hover { + animation: 1s ease-out 0s infinite alternate burst; + } + } + + img + img { + top: 12.5em; + left: 5em; + width: 125px; + } + + img + img + img { + top: 18.5em; + left: 0.5em; + width: 90px; } } -@media (prefers-reduced-motion) { - :root { - --animation-duration: 0; +.bookmarks { + display: flex; + flex-direction: column; + gap: 2em; +} + +@keyframes burst { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.2); + } + 100% { + transform: scale(0.8); } } - -@media (min-width: 800px) { - :root { - --map-ratio: 3 / 2; - } -} - -@media (min-width: 1000px) { - :root { - --page-title-font-size: 4em; - } -} -/* === /Themes === */ -/* === 6. Vendors === */ -/* -Styles belonging to third-party components. -*/ - -.footnotes-list { - color: var(--aside-color); - font-size: 80%; -} -/* === /Vendors === */ - -/* === 7. Shame === */ -/* -Styles necessary for specifity issues and for cutting corners -(breaking the rules in short terms in waiting for an opportunity -to rewrite or fix a problem for good). - -madr.se has no reason to feel ashamed. Yet. -*/ -/* === /Shame === */ diff --git a/lib/mse25/directus.ex b/lib/mse25/directus.ex index de29435..8a6255a 100644 --- a/lib/mse25/directus.ex +++ b/lib/mse25/directus.ex @@ -42,6 +42,31 @@ defmodule Mse25.Directus do get("/articles?" <> params) end + def get_note(slug) do + get_item(:notes, slug) + end + + def get_notes!(options \\ []) do + params = + [ + "fields=" <> + Enum.join( + [ + "id", + "contents", + "images", + "date_created", + "location" + ], + "," + ) + ] + |> annual?(:notes, options) + |> query_params_string(options, :notes) + + get("/notes?" <> params) + end + def get_album(externalId) do case get_item( :albums, @@ -198,6 +223,13 @@ defmodule Mse25.Directus do end end + defp get_item(:notes, externalId, fields) do + case get("/notes?fields=" <> fields <> "&filter[id][_eq]=" <> externalId) do + [] -> {:not_found, externalId} + [item | _] -> {:ok, item} + end + end + defp get_item(collection, slug, fields) do case get( "/" <> to_string(collection) <> "?fields=" <> fields <> "&filter[slug][_eq]=" <> slug diff --git a/lib/mse25_web/components/layouts/app.html.heex b/lib/mse25_web/components/layouts/app.html.heex index d038bff..a463244 100644 --- a/lib/mse25_web/components/layouts/app.html.heex +++ b/lib/mse25_web/components/layouts/app.html.heex @@ -1,26 +1,36 @@ +
+ <%= @inner_content %>
<%= if show_footer?(assigns) do %> diff --git a/lib/mse25_web/controllers/item_controller.ex b/lib/mse25_web/controllers/item_controller.ex index b9ed537..655544e 100644 --- a/lib/mse25_web/controllers/item_controller.ex +++ b/lib/mse25_web/controllers/item_controller.ex @@ -41,6 +41,13 @@ defmodule Mse25Web.ItemController do end end + defp fetch([_year, album_id], :note) do + case Directus.get_note(album_id) do + {:ok, response} -> {:ok, :note, response} + not_found -> not_found + end + end + defp fetch([year, "brutal-legend-" <> external_id]) do fetch([year, external_id], :album) end @@ -174,6 +181,21 @@ defmodule Mse25Web.ItemController do ] end + defp assigns(:note, %{ + "contents" => text, + "images" => images, + "date_created" => published_at + }) do + year = String.slice(published_at, 0..3) + + [ + text: Earmark.as_html!(text), + breadcrumbs: [{"anteckningar", "Anteckningar"}, {year, year, ""}], + date_created: String.slice(published_at, 0..9), + images: images + ] + end + defp assigns(:album, %{ "year" => year, "album" => album, diff --git a/lib/mse25_web/controllers/item_html/article.html.heex b/lib/mse25_web/controllers/item_html/article.html.heex index 7c53f8f..628d39e 100644 --- a/lib/mse25_web/controllers/item_html/article.html.heex +++ b/lib/mse25_web/controllers/item_html/article.html.heex @@ -1,4 +1,4 @@ -
+