A little app to serve my photography from my personal website

make posts page layout generic

+236 -226
+98
src/styles/app.css
··· 1 + :root { 2 + --foreground: black; 3 + --background: white; 4 + --half: color-mix(in srgb, var(--foreground) 50%, transparent); 5 + --light: color-mix(in srgb, var(--foreground) 10%, transparent); 6 + } 7 + 8 + * { 9 + box-sizing: border-box; 10 + } 11 + 12 + html, body { 13 + height: 100%; 14 + min-height: 100%; 15 + margin: 0; 16 + padding: 0; 17 + color: var(--foreground); 18 + background-color: var(--background); 19 + } 20 + 21 + body { 22 + display: flex; 23 + flex-direction: column; 24 + align-items: center; 25 + height: 100%; 26 + } 27 + 28 + .container { 29 + width: 100%; 30 + height: 100%; 31 + max-width: 3000px; 32 + overflow: auto; 33 + display: flex; 34 + flex-direction: column; 35 + justify-content: space-between; 36 + } 37 + 38 + header { 39 + display: flex; 40 + font-size: 16pt; 41 + width: 100%; 42 + border-bottom: solid var(--foreground) 3px; 43 + } 44 + 45 + header h1 { 46 + color: var(--foreground); 47 + text-transform: uppercase; 48 + font-weight: 900; 49 + margin: 0; 50 + letter-spacing: 3px; 51 + padding: 10px 30px; 52 + border-right: solid var(--foreground) 3px; 53 + } 54 + 55 + header nav ul { 56 + display: flex; 57 + height: 100%; 58 + list-style-type: none; 59 + margin: 0; 60 + padding: 0; 61 + } 62 + 63 + header nav ul a { 64 + display: flex; 65 + align-items: center; 66 + height: 100%; 67 + text-decoration: none; 68 + color: var(--foreground); 69 + padding: 0 30px; 70 + } 71 + 72 + header nav ul a.active, header nav ul a:hover { 73 + background-color: var(--foreground); 74 + color: var(--background); 75 + } 76 + 77 + @media (max-width: 850px) { 78 + header { 79 + flex-direction: column; 80 + } 81 + 82 + header nav ul { 83 + flex-direction: column; 84 + } 85 + } 86 + 87 + .layout { 88 + width: fit-content; 89 + margin: 0 auto; 90 + max-width: 900px; 91 + width: 100%; 92 + } 93 + 94 + footer { 95 + margin-top: 30px; 96 + padding: 30px; 97 + color: var(--half); 98 + }
+78
src/styles/posts.css
··· 1 + .posts__title { 2 + font-size: 26pt; 3 + margin: 30px 0; 4 + } 5 + 6 + .posts__tags { 7 + display: flex; 8 + align-items: center; 9 + gap: 10px; 10 + padding: 10px 0; 11 + border-bottom: solid var(--foreground) 2px; 12 + } 13 + 14 + .posts__tags-title { 15 + font-size: 10pt; 16 + text-transform: uppercase; 17 + font-weight: 600; 18 + } 19 + 20 + .posts__tag-list { 21 + display: flex; 22 + gap: 5px; 23 + margin: 0; 24 + padding: 0; 25 + list-style-type: none; 26 + } 27 + 28 + .posts__entries { 29 + display: flex; 30 + flex-direction: column; 31 + gap: 10px; 32 + padding: 0; 33 + list-style-type: none; 34 + } 35 + 36 + .posts__entries li { 37 + display: flex; 38 + justify-content: space-between; 39 + border-bottom: solid var(--light) 1px; 40 + padding-bottom: 10px; 41 + } 42 + 43 + .posts__entries li > a { 44 + color: var(--foreground); 45 + font-size: 12pt; 46 + text-decoration: none; 47 + } 48 + 49 + .posts__entries li > a:hover { 50 + text-decoration: underline; 51 + } 52 + 53 + .posts__entries li time { 54 + font-family: monospace; 55 + margin-left: 10px; 56 + } 57 + 58 + .tag { 59 + border-radius: 5px; 60 + padding: 3px 7px; 61 + background-color: var(--light); 62 + color: var(--foreground); 63 + text-decoration: none; 64 + display: inline-flex; 65 + align-items: center; 66 + gap: 5px; 67 + } 68 + 69 + .tag svg { 70 + width: 12px; 71 + height: 12px; 72 + } 73 + 74 + .tag.active { 75 + padding: 1px 5px; 76 + border: solid var(--foreground) 2px; 77 + background-color: var(--background); 78 + }
-56
src/views/blog/index/style.css
··· 1 - .blog__title { 2 - font-size: 26pt; 3 - margin: 30px 0; 4 - } 5 - 6 - .blog__tags { 7 - display: flex; 8 - align-items: center; 9 - gap: 10px; 10 - padding: 10px 0; 11 - border-bottom: solid var(--foreground) 2px; 12 - } 13 - 14 - .blog__tags-title { 15 - font-size: 10pt; 16 - text-transform: uppercase; 17 - font-weight: 600; 18 - } 19 - 20 - .blog__tag-list { 21 - display: flex; 22 - gap: 5px; 23 - margin: 0; 24 - padding: 0; 25 - list-style-type: none; 26 - } 27 - 28 - .blog__entries { 29 - display: flex; 30 - flex-direction: column; 31 - gap: 10px; 32 - padding: 0; 33 - list-style-type: none; 34 - } 35 - 36 - .blog__entries li { 37 - display: flex; 38 - justify-content: space-between; 39 - border-bottom: solid var(--light) 1px; 40 - padding-bottom: 10px; 41 - } 42 - 43 - .blog__entries li > a { 44 - color: var(--foreground); 45 - font-size: 12pt; 46 - text-decoration: none; 47 - } 48 - 49 - .blog__entries li > a:hover { 50 - text-decoration: underline; 51 - } 52 - 53 - .blog__entries li time { 54 - font-family: monospace; 55 - margin-left: 10px; 56 - }
+5 -43
src/views/blog/index/template.jinja
··· 2 2 {% set active_page = 'blog' %} 3 3 {% block title %}Blog{% endblock %} 4 4 {% block head %} 5 - {{ inline_style("src/views/blog/shared.css") }} 6 5 {{ inline_style("src/views/blog/index/style.css") }} 6 + {{ inline_style("src/styles/posts.css") }} 7 7 {% endblock %} 8 + {% import "posts" as posts_macro %} 8 9 9 10 {% block body %} 10 - <div class="blog__layout"> 11 - <h2 class="blog__title"> 12 - → Blog 13 - {% if tag %} 14 - / {{ tag }} 15 - {% endif %} 16 - </h2> 17 - <div class="blog__tags"> 18 - <span class="blog__tags-title">Categories</span> 19 - <ul class="blog__tag-list"> 20 - {% if tag %} 21 - <li> 22 - <a href="/blog" class="tag active"> 23 - {{ tag }} 24 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> 25 - <use xlink:href="#close-icon" /> 26 - </svg> 27 - </a> 28 - </li> 29 - {% endif %} 30 - {% for t in tags %} 31 - {% if t[0] != tag %} 32 - <li> 33 - <a class="tag" href="/blog?tag={{ url_escape(t[0]) }}">{{ t[0] }}</a> 34 - </li> 35 - {% endif %} 36 - {% endfor %} 37 - </ul> 38 - </div> 39 - <ul class="blog__entries"> 40 - {% for post in posts %} 41 - <li> 42 - <a href="/blog/{{ post.slug }}">{{ post.title }}</a> 43 - <span> 44 - {% for t in post.tags %} 45 - <a class="tag" href="/blog?tag={{ url_escape(t) }}">{{ t }}</a> 46 - {% endfor %} 47 - <time datetime="{{ post.published_at }}" data-short="true">{{ post.published_at }}</time> 48 - </span> 49 - </li> 50 - {% endfor %} 51 - </ul> 11 + <div class="layout"> 12 + {{ posts_macro.header("Blog", tag=tag) }} 13 + {{ posts_macro.table(posts, root_path="/blog", tag=tag) }} 52 14 </div> 53 15 <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="display: none"> 54 16 <defs>
-34
src/views/blog/shared.css
··· 1 - .blog__layout { 2 - width: fit-content; 3 - margin: 0 auto; 4 - max-width: 900px; 5 - width: 100%; 6 - } 7 - 8 - .blog__container { 9 - display: flex; 10 - gap: 60px; 11 - position: relative; 12 - } 13 - 14 - .tag { 15 - border-radius: 5px; 16 - padding: 3px 7px; 17 - background-color: var(--light); 18 - color: var(--foreground); 19 - text-decoration: none; 20 - display: inline-flex; 21 - align-items: center; 22 - gap: 5px; 23 - } 24 - 25 - .tag svg { 26 - width: 12px; 27 - height: 12px; 28 - } 29 - 30 - .tag.active { 31 - padding: 1px 5px; 32 - border: solid var(--foreground) 2px; 33 - background-color: var(--background); 34 - }
+6
src/views/blog/show/style.css
··· 1 + .blog__container { 2 + display: flex; 3 + gap: 60px; 4 + position: relative; 5 + } 6 + 1 7 .blog__header { 2 8 border-bottom: solid var(--foreground) 2px; 3 9 }
-1
src/views/blog/show/template.jinja
··· 2 2 {% set active_page = 'blog' %} 3 3 {% block title %}Blog{% endblock %} 4 4 {% block head %} 5 - {{ inline_style("src/views/blog/shared.css") }} 6 5 {{ inline_style("src/views/blog/show/style.css") }} 7 6 {% if has_code %} 8 7 {{ inline_style("src/views/blog/show/syntax.css") }}
+1 -92
templates/layout.jinja
··· 22 22 :root { font-family: 'InterVariable', serif; } 23 23 } 24 24 </style> 25 - <style type="text/css"> 26 - :root { 27 - --foreground: black; 28 - --background: white; 29 - --half: color-mix(in srgb, var(--foreground) 50%, transparent); 30 - --light: color-mix(in srgb, var(--foreground) 10%, transparent); 31 - } 32 25 33 - * { 34 - box-sizing: border-box; 35 - } 36 - 37 - html, body { 38 - height: 100%; 39 - min-height: 100%; 40 - margin: 0; 41 - padding: 0; 42 - color: var(--foreground); 43 - background-color: var(--background); 44 - } 45 - 46 - body { 47 - display: flex; 48 - flex-direction: column; 49 - align-items: center; 50 - height: 100%; 51 - } 52 - 53 - .container { 54 - width: 100%; 55 - height: 100%; 56 - max-width: 3000px; 57 - overflow: auto; 58 - display: flex; 59 - flex-direction: column; 60 - justify-content: space-between; 61 - } 62 - 63 - header { 64 - display: flex; 65 - font-size: 16pt; 66 - width: 100%; 67 - border-bottom: solid var(--foreground) 3px; 68 - } 69 - 70 - header h1 { 71 - color: var(--foreground); 72 - text-transform: uppercase; 73 - font-weight: 900; 74 - margin: 0; 75 - letter-spacing: 3px; 76 - padding: 10px 30px; 77 - border-right: solid var(--foreground) 3px; 78 - } 79 - 80 - header nav ul { 81 - display: flex; 82 - height: 100%; 83 - list-style-type: none; 84 - margin: 0; 85 - padding: 0; 86 - } 87 - 88 - header nav ul a { 89 - display: flex; 90 - align-items: center; 91 - height: 100%; 92 - text-decoration: none; 93 - color: var(--foreground); 94 - padding: 0 30px; 95 - } 96 - 97 - header nav ul a.active, header nav ul a:hover { 98 - background-color: var(--foreground); 99 - color: var(--background); 100 - } 101 - 102 - @media (max-width: 850px) { 103 - header { 104 - flex-direction: column; 105 - } 106 - 107 - header nav ul { 108 - flex-direction: column; 109 - } 110 - } 111 - 112 - footer { 113 - margin-top: 30px; 114 - padding: 30px; 115 - color: var(--half); 116 - } 117 - </style> 26 + {{ inline_style("src/styles/app.css") }} 118 27 <title>{% block title %}{% endblock %}</title> 119 28 {% block head %}{% endblock %} 120 29 </head>
+48
templates/posts.jinja
··· 1 + {% macro header(title, tag=None) %} 2 + <h2 class="posts__title"> 3 + → {{ title }} 4 + {% if tag %} 5 + / {{ tag }} 6 + {% endif %} 7 + </h2> 8 + {% endmacro %} 9 + 10 + {% macro table(posts, show_tags=true, root_path="", tag=None) %} 11 + {% if show_tags %} 12 + <div class="posts__tags"> 13 + <span class="posts__tags-title">Categories</span> 14 + <ul class="posts__tag-list"> 15 + {% if tag %} 16 + <li> 17 + <a href="{{ root_path }}" class="tag active"> 18 + {{ tag }} 19 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> 20 + <use xlink:href="#close-icon" /> 21 + </svg> 22 + </a> 23 + </li> 24 + {% endif %} 25 + {% for t in tags %} 26 + {% if t[0] != tag %} 27 + <li> 28 + <a class="tag" href="{{ root_path }}?tag={{ url_escape(t[0]) }}">{{ t[0] }}</a> 29 + </li> 30 + {% endif %} 31 + {% endfor %} 32 + </ul> 33 + </div> 34 + {% endif %} 35 + <ul class="posts__entries"> 36 + {% for post in posts %} 37 + <li> 38 + <a href="{{ root_path }}/{{ post.slug }}">{{ post.title }}</a> 39 + <span> 40 + {% for t in post.tags %} 41 + <a class="tag" href="{{ root_path }}?tag={{ url_escape(t) }}">{{ t }}</a> 42 + {% endfor %} 43 + <time datetime="{{ post.published_at }}" data-short="true">{{ post.published_at }}</time> 44 + </span> 45 + </li> 46 + {% endfor %} 47 + </ul> 48 + {% endmacro %}