WIP
This commit is contained in:
parent
2386a56036
commit
7265184fc5
12 changed files with 410 additions and 584 deletions
694
assets/app.css
694
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 {
|
body {
|
||||||
|
background: #222;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
background-image: linear-gradient(
|
||||||
> footer > p {
|
175deg,
|
||||||
margin-top: var(--gap-lg);
|
#212223,
|
||||||
color: #666;
|
#222 350px,
|
||||||
font-size: 0.66em;
|
#302928 345px,
|
||||||
}
|
#282828
|
||||||
}
|
);
|
||||||
|
font-family:
|
||||||
a {
|
system-ui,
|
||||||
color: var(--a-color);
|
-apple-system,
|
||||||
}
|
BlinkMacSystemFont,
|
||||||
|
"Segoe UI",
|
||||||
input,
|
Roboto,
|
||||||
button {
|
Oxygen,
|
||||||
font-size: 1.2em;
|
Ubuntu,
|
||||||
padding: 0.25em;
|
Cantarell,
|
||||||
}
|
"Open Sans",
|
||||||
|
"Helvetica Neue",
|
||||||
h1,
|
sans-serif;
|
||||||
h2,
|
|
||||||
h3 {
|
|
||||||
font-family: var(--system-serif-fonts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin: 0.5em 0;
|
font-size: 1.75em;
|
||||||
line-height: 0.95;
|
letter-spacing: -0.066em;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: var(--section-heading-lv2-font-size);
|
font-size: 1.33em;
|
||||||
border-bottom: 3px solid var(--panel-bg-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
p,
|
||||||
font-size: var(--section-heading-lv3-font-size);
|
li {
|
||||||
|
line-height: 1.66em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h3,
|
||||||
h4 {
|
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 {
|
pre {
|
||||||
margin: 2em 0;
|
padding: 0.5em;
|
||||||
background-color: #022;
|
background-color: #1e2025;
|
||||||
color: var(--monospace-color);
|
color: #96df71;
|
||||||
|
position: relative;
|
||||||
|
margin: 1em 2em;
|
||||||
overflow-y: auto;
|
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 {
|
button {
|
||||||
font-size: 0.75em;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0.25em;
|
top: 2px;
|
||||||
right: 0.25em;
|
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 {
|
.sr-only {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -999em;
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flx {
|
.breadcrumbs {
|
||||||
display: flex;
|
border-radius: 8px 8px 0 0;
|
||||||
justify-content: space-between;
|
padding: 1em;
|
||||||
align-items: center;
|
> .trail > span::after {
|
||||||
}
|
content: "/";
|
||||||
|
}
|
||||||
|
background: #080808;
|
||||||
|
background-image: linear-gradient(
|
||||||
|
#080808 0,
|
||||||
|
#080808 50%,
|
||||||
|
#161616 50%,
|
||||||
|
#080808 100%
|
||||||
|
);
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
.sticky {
|
a {
|
||||||
position: sticky;
|
color: #fff;
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.interactive-map {
|
|
||||||
aspect-ratio: var(--map-ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-h1 {
|
|
||||||
font-size: 1.33em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-link {
|
|
||||||
&::after {
|
|
||||||
content: " →";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.feed-link {
|
.head {
|
||||||
&::after {
|
color: #fff;
|
||||||
content: " ↗";
|
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 {
|
.skiplink {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -5em;
|
top: -1.75em;
|
||||||
transition: top var(--animation-duration) ease-out;
|
left: 1em;
|
||||||
padding: 0.25em 0.5em;
|
background-color: #ff0;
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.25em;
|
||||||
|
transition: top 0.25s ease-out;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
top: 1em;
|
top: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree {
|
nav {
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
margin: 2em 0 1em;
|
||||||
gap: 0.66em;
|
|
||||||
font-size: var(--tree-font-size);
|
|
||||||
|
|
||||||
> li {
|
> ul {
|
||||||
text-align: center;
|
list-style: none;
|
||||||
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 {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 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 === */
|
.anders {
|
||||||
/* === 3. Layout === */
|
img {
|
||||||
/*
|
position: fixed;
|
||||||
Containers and wrappers for components.
|
top: 1em;
|
||||||
Only class selectors allowed, with the following element selectors as
|
left: 1em;
|
||||||
exceptions: aside, body, footer, header, main and nav.
|
aspect-ratio: 1;
|
||||||
*/
|
border-radius: 50%;
|
||||||
body {
|
width: 175px;
|
||||||
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.
|
|
||||||
|
|
||||||
This section adapts the design to the following user preferences:
|
&:hover {
|
||||||
Color theme, reduced motion
|
animation: 1s ease-out 0s infinite alternate burst;
|
||||||
*/
|
}
|
||||||
@media (prefers-color-scheme: light) {
|
}
|
||||||
:root {
|
|
||||||
--color: #000;
|
img + img {
|
||||||
--bgcolor: #fff;
|
top: 12.5em;
|
||||||
--a-color: blue;
|
left: 5em;
|
||||||
|
width: 125px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img + img + img {
|
||||||
|
top: 18.5em;
|
||||||
|
left: 0.5em;
|
||||||
|
width: 90px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion) {
|
.bookmarks {
|
||||||
:root {
|
display: flex;
|
||||||
--animation-duration: 0;
|
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 === */
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,31 @@ defmodule Mse25.Directus do
|
||||||
get("/articles?" <> params)
|
get("/articles?" <> params)
|
||||||
end
|
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
|
def get_album(externalId) do
|
||||||
case get_item(
|
case get_item(
|
||||||
:albums,
|
:albums,
|
||||||
|
|
@ -198,6 +223,13 @@ defmodule Mse25.Directus do
|
||||||
end
|
end
|
||||||
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
|
defp get_item(collection, slug, fields) do
|
||||||
case get(
|
case get(
|
||||||
"/" <> to_string(collection) <> "?fields=" <> fields <> "&filter[slug][_eq]=" <> slug
|
"/" <> to_string(collection) <> "?fields=" <> fields <> "&filter[slug][_eq]=" <> slug
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,36 @@
|
||||||
<a href="#content" class="skiplink">Hoppa till innehållet</a>
|
<a href="#content" class="skiplink">Hoppa till innehållet</a>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<span class="sr-only">Du är här:</span>
|
<ul>
|
||||||
<span class="breadcrumbs" itemscope itemtype="https://schema.org/BreadcrumbList">
|
<li><a href="/webblogg">Webblogg</a></li>
|
||||||
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
|
<li><a href="/delningar">Länkar</a></li>
|
||||||
<a href="/" rel="home">
|
<li><a href="/anteckningar">Anteckningar</a></li>
|
||||||
<span itemprop="name">madr.se</span>
|
<li><a href="/evenemang">Evenemang</a></li>
|
||||||
</a>
|
<li><a href="/om">Om</a></li>
|
||||||
<meta itemprop="position" content="1" />
|
</ul>
|
||||||
</span>
|
|
||||||
<%= for {index, {parent_slug, parent_name}} <- breadcrumbs(@breadcrumbs) do %>
|
|
||||||
<span class="sr-only">></span>
|
|
||||||
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
|
|
||||||
<a href={parent_slug}>
|
|
||||||
<span itemprop="name"><%= parent_name %></span>
|
|
||||||
</a>
|
|
||||||
<meta itemprop="position" content={index} />
|
|
||||||
</span>
|
|
||||||
<% end %>
|
|
||||||
</span>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main id="content">
|
<main id="content">
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<span class="sr-only">Du är här:</span>
|
||||||
|
<span class="trail" itemscope itemtype="https://schema.org/BreadcrumbList">
|
||||||
|
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
|
||||||
|
<a href="/" rel="home">
|
||||||
|
<span itemprop="name">madr.se</span>
|
||||||
|
</a>
|
||||||
|
<meta itemprop="position" content="1" />
|
||||||
|
</span>
|
||||||
|
<%= for {index, {parent_slug, parent_name}} <- breadcrumbs(@breadcrumbs) do %>
|
||||||
|
<span class="sr-only">></span>
|
||||||
|
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
|
||||||
|
<a href={parent_slug}>
|
||||||
|
<span itemprop="name"><%= parent_name %></span>
|
||||||
|
</a>
|
||||||
|
<meta itemprop="position" content={index} />
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<%= @inner_content %>
|
<%= @inner_content %>
|
||||||
</main>
|
</main>
|
||||||
<%= if show_footer?(assigns) do %>
|
<%= if show_footer?(assigns) do %>
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,13 @@ defmodule Mse25Web.ItemController do
|
||||||
end
|
end
|
||||||
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
|
defp fetch([year, "brutal-legend-" <> external_id]) do
|
||||||
fetch([year, external_id], :album)
|
fetch([year, external_id], :album)
|
||||||
end
|
end
|
||||||
|
|
@ -174,6 +181,21 @@ defmodule Mse25Web.ItemController do
|
||||||
]
|
]
|
||||||
end
|
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, %{
|
defp assigns(:album, %{
|
||||||
"year" => year,
|
"year" => year,
|
||||||
"album" => album,
|
"album" => album,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<article class="article" vocab="https://schema.org/" typeof="Article">
|
<article class="collapsed article card" vocab="https://schema.org/" typeof="Article">
|
||||||
<h1 property="name"><%= @heading %></h1>
|
<h1 property="name"><%= @heading %></h1>
|
||||||
|
|
||||||
<div property="articleBody">
|
<div property="articleBody">
|
||||||
|
|
|
||||||
10
lib/mse25_web/controllers/item_html/note.html.heex
Normal file
10
lib/mse25_web/controllers/item_html/note.html.heex
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<article class="collapsed article card" vocab="https://schema.org/" typeof="Article">
|
||||||
|
<h1 property="name articleBody"><%= raw(@contents) %></h1>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>
|
||||||
|
Publicerad <time property="datePublished"><%= @published_at %></time>
|
||||||
|
av <span property="publisher">Anders Englöf Ytterström</span>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<article class="article" vocab="https://schema.org/" typeof="Article">
|
<article class="card article" vocab="https://schema.org/" typeof="Article">
|
||||||
<h1 property="name"><%= @heading %></h1>
|
<h1 property="name"><%= @heading %></h1>
|
||||||
|
|
||||||
<div property="articleBody">
|
<div property="articleBody">
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,26 @@ defmodule Mse25Web.PageController do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def notes(conn, params) do
|
||||||
|
{notes, page_title} =
|
||||||
|
case params do
|
||||||
|
%{"q" => query_string} ->
|
||||||
|
{Directus.get_notes!(limit: @almost_infinity, query: query_string),
|
||||||
|
"Anteckningar: \"#{query_string}\""}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
{Directus.get_notes!(limit: @almost_infinity), "Anteckningar"}
|
||||||
|
end
|
||||||
|
|
||||||
|
render(conn, :notes,
|
||||||
|
page_title: page_title,
|
||||||
|
breadcrumbs: [],
|
||||||
|
notes: group_by_creation_date(notes),
|
||||||
|
q: params["q"],
|
||||||
|
nosearch?: params["q"] == nil or params["q"] == ""
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def events(conn, params) do
|
def events(conn, params) do
|
||||||
{_, %{"title" => title, "contents" => contents}} = Directus.get_page("evenemang")
|
{_, %{"title" => title, "contents" => contents}} = Directus.get_page("evenemang")
|
||||||
|
|
||||||
|
|
@ -93,7 +113,7 @@ defmodule Mse25Web.PageController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def links(conn, _params) do
|
def links(conn, _params) do
|
||||||
links = Directus.get_links!(limit: @almost_infinity) |> group_by_date
|
links = Directus.get_links!(limit: @almost_infinity) |> group_by_pub_date
|
||||||
|
|
||||||
render(conn, :links,
|
render(conn, :links,
|
||||||
page_title: "Delningar",
|
page_title: "Delningar",
|
||||||
|
|
@ -109,10 +129,17 @@ defmodule Mse25Web.PageController do
|
||||||
|> Enum.sort(fn {a, _a}, {b, _b} -> b < a end)
|
|> Enum.sort(fn {a, _a}, {b, _b} -> b < a end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp group_by_date(items) do
|
defp group_by_pub_date(items) do
|
||||||
items
|
items
|
||||||
|> Enum.group_by(fn %{"pubDate" => pub_date} -> pub_date end)
|
|> Enum.group_by(fn %{"pubDate" => pub_date} -> pub_date end)
|
||||||
|> Map.to_list()
|
|> Map.to_list()
|
||||||
|> Enum.sort(fn {a, _a}, {b, _b} -> b < a end)
|
|> Enum.sort(fn {a, _a}, {b, _b} -> b < a end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp group_by_creation_date(items) do
|
||||||
|
items
|
||||||
|
|> Enum.group_by(fn %{"date_created" => pub_date} -> String.slice(pub_date, 0..9) end)
|
||||||
|
|> Map.to_list()
|
||||||
|
|> Enum.sort(fn {a, _a}, {b, _b} -> b < a end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,8 @@ defmodule Mse25Web.PageHTML do
|
||||||
import Mse25.EventHelpers
|
import Mse25.EventHelpers
|
||||||
|
|
||||||
embed_templates "page_html/*"
|
embed_templates "page_html/*"
|
||||||
|
|
||||||
|
defp fancy_timestamp(datestr) do
|
||||||
|
datestr |> IO.inspect()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,45 @@
|
||||||
<h1>
|
<div class="head">
|
||||||
<%= @page_title %>
|
<h1>
|
||||||
</h1>
|
<%= @page_title %>
|
||||||
<p>
|
</h1>
|
||||||
Inlägg skrivna sedan 2006.
|
|
||||||
<%= if @nosearch? do %>
|
|
||||||
Gå direkt till:
|
|
||||||
<% end %>
|
|
||||||
</p>
|
|
||||||
<ul class="months">
|
|
||||||
<%= for {year, articles} <- @articles do %>
|
|
||||||
<li>
|
|
||||||
<a href={"#y" <> year}><%= year %></a> (<%= Enum.count(articles) %>)
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
</ul>
|
|
||||||
<form method="get" action="/webblogg">
|
|
||||||
<p>
|
<p>
|
||||||
|
Inlägg skrivna sedan 2006.
|
||||||
<%= if @nosearch? do %>
|
<%= if @nosearch? do %>
|
||||||
Eller
|
Gå direkt till:
|
||||||
<% end %>
|
<% end %>
|
||||||
<label for="q">sök innehåll</label>:
|
|
||||||
<input type="search" value={@q} name="q" id="q" size="7" />
|
|
||||||
<button>Sök</button>
|
|
||||||
</p>
|
</p>
|
||||||
</form>
|
<ul class="months">
|
||||||
<%= for {year, articles} <- @articles do %>
|
<%= for {year, articles} <- @articles do %>
|
||||||
<section id={"y" <> year}>
|
<li>
|
||||||
<h2 class="sticky"><%= year %></h2>
|
<a href={"#y" <> year}><%= year %></a> (<%= Enum.count(articles) %>)
|
||||||
<div class="articles">
|
</li>
|
||||||
<%= for article <- articles do %>
|
<% end %>
|
||||||
<article class="article" vocab="https://schema.org/" typeof="Article">
|
</ul>
|
||||||
<h2 property="name">
|
<form method="get" action="/webblogg">
|
||||||
<a href={"/" <> article["slug"]}><%= article["title"] %></a>
|
<p>
|
||||||
</h2>
|
<%= if @nosearch? do %>
|
||||||
<time><%= article["pubDate"] %></time>
|
Eller
|
||||||
</article>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
<label for="q">sök innehåll</label>:
|
||||||
</section>
|
<input type="search" value={@q} name="q" id="q" size="7" />
|
||||||
<% end %>
|
<button>Sök</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="cards">
|
||||||
|
<%= for {year, articles} <- @articles do %>
|
||||||
|
<section class="card" id={"y" <> year}>
|
||||||
|
<h2 class="sticky"><%= year %></h2>
|
||||||
|
<div class="articles">
|
||||||
|
<%= for article <- articles do %>
|
||||||
|
<article class="article" vocab="https://schema.org/" typeof="Article">
|
||||||
|
<h2 property="name">
|
||||||
|
<a href={"/" <> article["slug"]}><%= article["title"] %></a>
|
||||||
|
</h2>
|
||||||
|
<time><%= article["pubDate"] %></time>
|
||||||
|
</article>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
|
||||||
74
lib/mse25_web/controllers/page_html/notes.html.heex
Normal file
74
lib/mse25_web/controllers/page_html/notes.html.heex
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
<div class="head">
|
||||||
|
<h1>Anteckningar</h1>
|
||||||
|
<p>Blandade tankar, oftast på engelska. Replikerat på Mastodon.</p>
|
||||||
|
</div>
|
||||||
|
<div class="cards">
|
||||||
|
<%= for {date, links} <- @notes do %>
|
||||||
|
<section class="card" id={"d" <> date}>
|
||||||
|
<h2>
|
||||||
|
<%= date
|
||||||
|
|> Date.from_iso8601!()
|
||||||
|
|> Calendar.strftime(
|
||||||
|
"%A, %d %B %Y",
|
||||||
|
month_names: fn m ->
|
||||||
|
Enum.at(
|
||||||
|
[
|
||||||
|
"januari",
|
||||||
|
"februari",
|
||||||
|
"mars",
|
||||||
|
"april",
|
||||||
|
"maj",
|
||||||
|
"juni",
|
||||||
|
"juli",
|
||||||
|
"augusti",
|
||||||
|
"september",
|
||||||
|
"oktober",
|
||||||
|
"november",
|
||||||
|
"december"
|
||||||
|
],
|
||||||
|
m - 1
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
day_of_week_names: fn d ->
|
||||||
|
Enum.at(
|
||||||
|
[
|
||||||
|
"måndag",
|
||||||
|
"tisdag",
|
||||||
|
"onsdag",
|
||||||
|
"torsdag",
|
||||||
|
"fredag",
|
||||||
|
"lördag",
|
||||||
|
"söndag"
|
||||||
|
],
|
||||||
|
d - 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|> String.replace(~r/ 0/, " ") %>
|
||||||
|
</h2>
|
||||||
|
<div class="bookmarks">
|
||||||
|
<%= for link <- links do %>
|
||||||
|
<article vocab="https://schema.org/" typeof="WebContent Review" class="bookmark">
|
||||||
|
<h3>
|
||||||
|
<div property="reviewBody">
|
||||||
|
<%= link["contents"] |> Earmark.as_html!() |> raw %>
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
<footer>
|
||||||
|
<p>
|
||||||
|
Posted on
|
||||||
|
<a class="permalink" href={"/notes/" <> to_string(link["id"])} title="Permalänk">
|
||||||
|
<%= fancy_timestamp(link["date_created"]) %>
|
||||||
|
</a>
|
||||||
|
at
|
||||||
|
<a href="https://www.openstreetmap.org/#map=15/50.82806/-0.12861">
|
||||||
|
pos
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
@ -31,6 +31,7 @@ defmodule Mse25Web.Router do
|
||||||
get "/evenemang", PageController, :events
|
get "/evenemang", PageController, :events
|
||||||
get "/webblogg", PageController, :articles
|
get "/webblogg", PageController, :articles
|
||||||
get "/delningar", PageController, :links
|
get "/delningar", PageController, :links
|
||||||
|
get "/anteckningar", PageController, :notes
|
||||||
get "/sok", PageController, :search
|
get "/sok", PageController, :search
|
||||||
|
|
||||||
get "/prenumerera.xml", FeedController, :feed
|
get "/prenumerera.xml", FeedController, :feed
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue