Compare commits

..

1 Commits

Author SHA1 Message Date
c976e8d3a8 Set title in archives. 2020-01-29 18:45:35 +05:30
13 changed files with 56 additions and 3222 deletions

View File

@@ -2,6 +2,6 @@
{% block left_content %} {% block left_content %}
<ul class="archives"> <ul class="archives">
{% for episode in episodes %} {% for episode in episodes %}
<li><a href="../{{ episode.slug }}">{{ episode.title }}</a></li> <li><a href="{{ episode.slug }}">{{ episode.title }}</a></li>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 470 KiB

View File

@@ -5,18 +5,15 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}{{ title }} | Redacted Life{% endblock %}</title> <title>{{ title }} | Redacted Life</title>
<link href="{{ relative }}/assets/css/index.css" rel="stylesheet" type="text/css"> <link href="assets/css/index.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="{{ relative }}/assets/plyr/plyr.css" /> <link rel="stylesheet" href="assets/plyr/plyr.css" />
<!-- Metadata --> <!-- Metadata -->
<meta name="description" content="An audiocast on Linux and libre software with a hard spin on personal privacy and security"> <meta name="description" content="An audiocast on Linux and libre software with a hard spin on personal privacy and security">
<meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett, Lloyd Barlowe" />
<link rel="canonical" href="https://redacted.life/"> <link rel="canonical" href="https://redacted.life/">
<link rel="me" href="https://masto.nixnet.xyz/@amolith"> <link rel="me" href="https://masto.nixnet.xyz/@amolith">
<link rel="me" href="https://masto.nixnet.xyz/@RedactedLife"> <link rel="me" href="https://masto.nixnet.xyz/@RedactedLife">
<link rel="me" href="https://social.nixnet.services/@RedactedLife">
{% block stylesheets %}{% endblock %}
<!-- Social: Twitter --> <!-- Social: Twitter -->
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
@@ -34,26 +31,26 @@
<meta property="og:image" content="/assets/media/cover-site.png" /> <meta property="og:image" content="/assets/media/cover-site.png" />
<!-- Favicons --> <!-- Favicons -->
<link rel="apple-touch-icon" sizes="180x180" href="{{ relative }}/assets/favicons/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="{{ relative }}/assets/favicons/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="{{ relative }}/assets/favicons/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
<link rel="manifest" href="{{ relative }}/assets/favicons/site.webmanifest"> <link rel="manifest" href="/assets/favicons/site.webmanifest">
<link rel="mask-icon" href="{{ relative }}/assets/favicons/safari-pinned-tab.svg" color="#46ad83"> <link rel="mask-icon" href="/assets/favicons/safari-pinned-tab.svg" color="#46ad83">
<link rel="shortcut icon" href="{{ relative }}/assets/favicons/favicon.ico"> <link rel="shortcut icon" href="/assets/favicons/favicon.ico">
<meta name="msapplication-TileColor" content="#2b5797"> <meta name="msapplication-TileColor" content="#2b5797">
<meta name="msapplication-config" content="{{ relative }}/assets/favicons/browserconfig.xml"> <meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
</head> </head>
<body> <body>
<img src="{{ relative }}/assets/images/cloud.svg" class="clouds" id="cloud1" /> <img src="assets/images/cloud.svg" class="clouds" id="cloud1" />
<img src="{{ relative }}/assets/images/cloud.svg" class="clouds" id="cloud2" /> <img src="assets/images/cloud.svg" class="clouds" id="cloud2" />
<div class="top_bg"></div> <div class="top_bg"></div>
<div class="bottom_bg"></div> <div class="bottom_bg"></div>
<div class="top"> <div class="top">
<div class="wrapper"> <div class="wrapper">
<div class="content"> <div class="content">
<h1><a href="{{relative}}">Redacted Life</a></h1> <h1><a href=".">Redacted Life</a></h1>
{% block left_content %} {% block left_content %}
{% endblock %} {% endblock %}
</div> </div>
@@ -62,11 +59,10 @@
<div class="bottom"> <div class="bottom">
<div class="wrapper"> <div class="wrapper">
<div class="content"> <div class="content">
<a class="button" href="{{relative}}/subscribe/">Subscribe</a> <a class="button" href="feed.xml">Subscribe</a>
<a class="button" href="mailto:hello@redacted.life">Contact</a> <a class="button" href="mailto:hello@redacted.life">Contact</a>
<a class="button" href="{{relative}}/archives/">Archives</a> <a class="button" href="archives.html">Archives</a>
</div> </div>
<a class="donate-link" href="{{relative}}/donate/">Consider supporting these individuals and organisations</a>
<footer> <footer>
Designed by <a href="https://webionite.com">Ceda EI</a><br /> Designed by <a href="https://webionite.com">Ceda EI</a><br />
Source available on <a href="https://git.webionite.com/ceda_ei/redacted.life">Webionite</a><br /> Source available on <a href="https://git.webionite.com/ceda_ei/redacted.life">Webionite</a><br />
@@ -74,10 +70,10 @@
</footer> </footer>
</div> </div>
</div> </div>
<script src="{{ relative }}/assets/plyr/plyr.js"></script> <script src="assets/plyr/plyr.js"></script>
<script> <script>
const player = new Plyr("#player", { const player = new Plyr("#player", {
iconUrl: "{{ relative }}/assets/plyr/plyr.svg", iconUrl: "assets/plyr/plyr.svg",
}); });
</script> </script>
</body> </body>

View File

@@ -1,9 +0,0 @@
{% extends "base.html" %}
{% block title %}Donate | Redacted Life{% endblock %}
{% block left_content %}
<ul class="donate">
{% for donate in donations %}
<li><a href="{{ donate.link }}">{{ donate.text }}</a></li>
{% endfor %}
</ul>
{% endblock %}

266
nova.py
View File

@@ -1,14 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# pylint: disable=logging-format-interpolation
"Creates a static site for redacted.life" "Creates a static site for redacted.life"
import argparse import argparse
from collections import UserList from collections import UserList
from datetime import datetime from datetime import datetime
import json
import os import os
import os.path as path import os.path as path
import logging
import re import re
import subprocess import subprocess
import shutil import shutil
@@ -16,7 +13,6 @@ import sys
import jinja2 import jinja2
import markdown import markdown
from mutagen.mp3 import MP3
def gen_name(date, slug): def gen_name(date, slug):
@@ -24,29 +20,20 @@ def gen_name(date, slug):
return date.strftime("%Y-%m-%d-") + slug return date.strftime("%Y-%m-%d-") + slug
def seconds_to_str(seconds):
"Convert seconds to a string of hh:mm:ss"
seconds = int(seconds)
return f"{seconds // 3600:02}:{(seconds % 3600) // 60:02}:{seconds % 60:02}"
class EpisodeList(UserList): class EpisodeList(UserList):
"Represents list of episodes" "Represents list of episodes"
def __init__(self, url, data, output, template, archives): def __init__(self, data, output, template, archives):
super().__init__(data) super().__init__(data)
self.url = url
self.output = output self.output = output
self.template = template self.template = template
self.archives = archives self.archives = archives
logging.info(f"New EpisodeList: {url=} {output=} {template=} {archives=}")
def sort(self, *_args, **_kwargs): def sort(self, *_args, **_kwargs):
"Sorts the EpisodeList" "Sorts the EpisodeList"
super().sort(key=lambda x: x.date, reverse=False) super().sort(key=lambda x: x.date, reverse=True)
def generate_thumbnails(self): def generate_thumbnails(self):
"Generates thumbnails for all the videos" "Generates thumbnails for all the videos"
logging.info(f"Creating missing directories")
if not path.isdir(self.output + "assets"): if not path.isdir(self.output + "assets"):
os.mkdir(self.output + "assets") os.mkdir(self.output + "assets")
if not path.isdir(self.output + "assets/thumbnails"): if not path.isdir(self.output + "assets/thumbnails"):
@@ -54,125 +41,41 @@ class EpisodeList(UserList):
for episode in self.data: for episode in self.data:
location = (self.output + "assets/thumbnails/" + location = (self.output + "assets/thumbnails/" +
gen_name(episode.date, episode.slug) + ".jpg") gen_name(episode.date, episode.slug) + ".jpg")
logging.info(f"Creating thumbnail for {episode=} at {location}")
episode.store_thumbnail(location) episode.store_thumbnail(location)
def generate_rss(self, header): def generate_atom(self):
"Generates the RSS Feed" "Generates the Atom feed"
with open(self.output + "feed_mp3.rss", "w") as mp3, \
open(self.output + "feed_ogg.rss", "w") as ogg:
# pylint: disable = invalid-name
for s, ext in ((mp3, "mp3"), (ogg, "ogg")):
logging.info(f"Writing header for {ext}")
s.write(header)
for ep in self.data:
logging.info(f"Writing item for episode {ep} with {ext=}")
s.write("<item>")
s.write("\n")
# Title
s.write(f"<title><![CDATA[{ep.title}]]></title>")
s.write("\n")
# Description
s.write("<description><![CDATA["
f"{ep.config['description']}]]></description>")
s.write("\n")
# Date
datestring = ep.date.strftime(
'%a, %d %b, %Y %H:%M:%Sz GMT'
)
s.write(f"<pubDate>{datestring}</pubDate>")
s.write("\n")
# iTunes: explicit, author, subtitle, keywords
s.write(f"<itunes:explicit>{ep.config['explicit']}"
"</itunes:explicit>")
s.write("\n")
s.write(
f"<itunes:author><![CDATA[{ep.config['author']}]]>"
"</itunes:author>"
)
s.write("\n")
s.write(
"<itunes:subtitle><![CDATA["
f"{ep.config['subtitle']}]]></itunes:subtitle>"
)
s.write("\n")
s.write(
f"<itunes:keywords>{','.join(ep.config['tags'])}"
"</itunes:keywords>"
)
s.write("\n")
s.write(f"<itunes:duration>{seconds_to_str(len(ep))}"
"</itunes:duration>")
s.write("\n")
# Content (show_notes)
s.write(
f"<content:encoded><![CDATA[{ep.show_notes}]]>"
"</content:encoded>"
)
s.write("\n")
# GUID
s.write(
f"<guid isPermaLink=\"true\">{self.url}{ep.slug}"
".html</guid>"
)
s.write("\n")
# Enclosure
audio = f'{self.url}assets/audio/{ep.slug}.{ext}'
size = path.getsize(f"{ep.audio}.{ext}")
s.write(
f'<enclosure url="{audio}" type="audio/{ext}" '
f'length="{size}" />'
)
s.write("\n")
# Categories
for tag in ep.config["tags"]:
s.write(f"<category><![CDATA[{tag}]]></category>")
s.write("\n")
s.write("</item>")
s.write("\n")
logging.info(f"Writing end for {ext}")
s.write("</channel>")
s.write("\n")
s.write("</rss>")
def generate_archives(self): def generate_archives(self):
"Generates archives page" "Generates archives page"
if not path.isdir(self.output + "archives"): with open(self.output + "archives.html", "w") as file:
logging.info("Creating directory archives")
os.mkdir(self.output + "archives")
with open(self.output + "archives/index.html", "w") as file:
episodes = [{ episodes = [{
"slug": gen_name(i.date, i.slug) + ".html", "slug": gen_name(i.date, i.slug) + ".html",
"title": i.title "title": i.title
} for i in self.data[::-1]] } for i in self.data]
file.write(self.archives.render(episodes=episodes, file.write(self.archives.render(episodes=episodes,
title="Archives", title="Archives"))
relative=".."
))
def generate_site(self, root): def generate_site(self, root):
"Generates the entire site" "Generates the entire site"
logging.info("Generating CSS from SCSS") # Generate CSS from SCSS
subprocess.run(["sass", "--update", f"{root}scss:{root}assets/css"], subprocess.run(["sass", "--update", f"{root}scss:{root}assets/css"],
check=True) check=True)
logging.info("Copy the existing assets") # Copy the existing assets
shutil.copytree(root + "assets", self.output + "assets", shutil.copytree(root + "assets", self.output + "assets",
dirs_exist_ok=True) dirs_exist_ok=True)
logging.info("Create the required directories") # Create the required directories
paths = [ paths = [
"assets", "assets",
"assets/audio", "assets/audio",
"assets/videos", "assets/videos",
] ]
logging.info("Creating missing directories")
for directory in paths: for directory in paths:
if not path.isdir(self.output + directory): if not path.isdir(self.output + directory):
logging.info(f"Creating directory {directory}")
os.mkdir(self.output + directory) os.mkdir(self.output + directory)
logging.info("Render episodes and copy data") # Render episodes and copy data
for episode in self.data: for episode in self.data:
logging.info(f"Rendering episode {episode}")
html = f"{self.output}{gen_name(episode.date, episode.slug)}.html" html = f"{self.output}{gen_name(episode.date, episode.slug)}.html"
thumbnail = ("assets/thumbnails/" + thumbnail = ("assets/thumbnails/" +
gen_name(episode.date, episode.slug) + ".jpg") gen_name(episode.date, episode.slug) + ".jpg")
@@ -180,43 +83,32 @@ class EpisodeList(UserList):
gen_name(episode.date, episode.slug) + ".mp4") gen_name(episode.date, episode.slug) + ".mp4")
audio = (self.output + "assets/audio/" + audio = (self.output + "assets/audio/" +
gen_name(episode.date, episode.slug) + ".mp3") gen_name(episode.date, episode.slug) + ".mp3")
logging.info(f"Copying {episode.video} to {video}")
shutil.copy2(episode.video, video) shutil.copy2(episode.video, video)
logging.info(f"Copying {episode.audio}.mp3 to {audio}") shutil.copy2(episode.audio, audio)
shutil.copy2(episode.audio + ".mp3", audio)
logging.info(f"Copying {episode.audio}.ogg to {audio}")
shutil.copy2(episode.audio + ".ogg", audio)
logging.info(f"Writing to {html}")
with open(html, "w") as file: with open(html, "w") as file:
file.write(episode.render(self.template, thumbnail)) file.write(episode.render(self.template, thumbnail))
last = self.data[-1] last = self.data[-1]
last_name = f"{self.output}{gen_name(last.date, last.slug)}.html" last_name = self.output + gen_name(last.date, last.slug) + ".html"
logging.info(f"Copying last one ({last}) to index.html") shutil.copy2(last_name, self.output + "index.html")
shutil.copy2(last_name, self.output + "index.html")
class Episode: class Episode:
"Represents one episode of podcast" "Represents one episode of podcast"
def __init__(self, date, slug, title, show_notes, video_src, audio_src, config): def __init__(self, date, slug, title, show_notes, video_src, audio_src):
self.date = date self.date = date
self.slug = slug self.slug = slug
self.title = title self.title = title.strip()
self.show_notes = markdown.markdown(show_notes) self.show_notes = markdown.markdown(show_notes)
self.video = video_src self.video = video_src
self.audio = audio_src self.audio = audio_src
self.config = config
self.length = MP3(audio_src + ".mp3").info.length
logging.info(f"New episode: {date=} {slug=} {title=} {self.video=} "
f"{self.audio=} {config=} {self.length=} {self.show_notes=}")
def render(self, template, thumbnail_src, relative="."): def render(self, template, thumbnail_src):
"Renders the Episode with the given template" "Renders the Episode with the given template"
return template.render( return template.render(
title=self.title, title=self.title,
show_notes=jinja2.Markup(self.show_notes), show_notes=jinja2.Markup(self.show_notes),
thumbnail_src=thumbnail_src, thumbnail_src=thumbnail_src,
relative=relative,
video_src=f"assets/videos/{path.basename(self.video)}" video_src=f"assets/videos/{path.basename(self.video)}"
) )
@@ -224,68 +116,24 @@ class Episode:
"Stores the thumbnail for given image at path" "Stores the thumbnail for given image at path"
args = ["ffmpeg", "-i", self.video, "-ss", "00:00:01.000", "-vframes", args = ["ffmpeg", "-i", self.video, "-ss", "00:00:01.000", "-vframes",
"1", location] "1", location]
logging.info(f"Running {' '.join(args)}")
subprocess.run(args, check=False) subprocess.run(args, check=False)
def __len__(self):
return int(self.length)
def __str__(self):
return f"{self.slug}: {self.title}"
def __repr__(self):
return str(self)
def parse_args(): def parse_args():
"Parses arguments" "Parses arguments"
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("input_dir", help="Input directory") parser.add_argument("input_dir", help="Input directory")
parser.add_argument("output_dir", help="Output directory") parser.add_argument("output_dir", help="Output directory")
parser.add_argument("url", help="Base URL of website")
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose Logging")
args = parser.parse_args() args = parser.parse_args()
input_dir = path.abspath(args.input_dir.rstrip("/")) + "/" input_dir = args.input_dir.rstrip("/") + "/"
output_dir = path.abspath(args.output_dir.rstrip("/")) + "/" output_dir = args.output_dir.rstrip("/") + "/"
if args.verbose: return input_dir, output_dir
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig()
url = args.url.rstrip("/") + "/"
return input_dir, output_dir, url
class ParseError(ValueError): def main():
"Error raised while parsing a file"
def parse_file(file, array_keys=("tags")):
"Parses a file"
config = {}
kv_re = re.compile(r"(?P<key>\w+):\s*(?P<value>.*)")
while line := file.readline():
if line.rstrip("\n") == "---":
break
if line.strip() == "":
continue
if match := kv_re.match(line):
if match.group("key").strip().lower() in array_keys:
config[match.group("key")] = [i.strip() for i in
match.group("value").split(",")]
else:
config[match.group("key")] = match.group("value").strip()
else:
raise ParseError(f"Invalid line {line}")
return (config, file.read())
def main(args):
"Main method" "Main method"
root = path.dirname(sys.argv[0]).rstrip("/") + "/" root = path.dirname(sys.argv[0]).rstrip("/") + "/"
input_dir, output_dir, url = args input_dir, output_dir = parse_args()
logging.info(f"Input directory: {input_dir}")
logging.info(f"Output directory: {output_dir}")
logging.info(f"URL: {url}")
# Input validation # Input validation
paths = [ paths = [
@@ -294,12 +142,10 @@ def main(args):
input_dir + "videos", input_dir + "videos",
input_dir + "audio", input_dir + "audio",
] ]
logging.info("Checking if all paths exist.") if not all(path.isdir(i) for i in paths):
if not all(path.isdir((fail := i)) for i in paths): print("Invalid Input", file=sys.stderr)
logging.error(f"Invalid Input. {fail} is not a directory.") return
return 1
logging.info("Creating output directory if it doesn't exist")
if not path.isdir(output_dir): if not path.isdir(output_dir):
os.mkdir(output_dir) os.mkdir(output_dir)
@@ -308,9 +154,7 @@ def main(args):
autoescape=jinja2.select_autoescape("html") autoescape=jinja2.select_autoescape("html")
) )
logging.info("Creating EpisodeList")
podcast = EpisodeList( podcast = EpisodeList(
url,
[], [],
output_dir, output_dir,
env.get_template("index.html"), env.get_template("index.html"),
@@ -318,76 +162,34 @@ def main(args):
) )
split = re.compile(r"((?P<date>\d{4}-[01]?\d-[0123]?\d)-(?P<slug>.*).md)") split = re.compile(r"((?P<date>\d{4}-[01]?\d-[0123]?\d)-(?P<slug>.*).md)")
logging.info(f"Parsing all files in {input_dir}md")
for file in os.listdir(input_dir + "md"): for file in os.listdir(input_dir + "md"):
logging.info(f"File: {file}")
match = split.match(file) match = split.match(file)
logging.info(f"Match: {match}")
if not match: if not match:
logging.error(f"Invalid filename: {file}") print(f"Invalid filename: {file}", file=sys.stderr)
continue continue
date = datetime.strptime(match.group("date"), "%Y-%m-%d") date = datetime.strptime(match.group("date"), "%Y-%M-%d")
logging.info(f"Date: {date}")
slug = match.group("slug") slug = match.group("slug")
logging.info(f"Slug: {slug}")
with open(input_dir + "md/" + file) as episode: with open(input_dir + "md/" + file) as episode:
try: title = episode.readline()
config, show_notes = parse_file(episode) show_notes = episode.read()
logging.info(f"Config: {config}")
logging.info(f"Show Notes: {show_notes}")
except ParseError as err:
logging.error(f"Error while parsing file: {file}")
logging.error(err)
return 2
logging.info("Appending to EpisodeList")
podcast.append( podcast.append(
Episode( Episode(
date, date,
slug, slug,
config["title"], title,
show_notes, show_notes,
input_dir + "videos/" + gen_name(date, slug) + ".mp4", input_dir + "videos/" + gen_name(date, slug) + ".mp4",
input_dir + "audio/" + gen_name(date, slug), input_dir + "audio/" + gen_name(date, slug) + ".mp3"
config
) )
) )
if not path.isdir(output_dir + "subscribe"):
os.mkdir(output_dir + "subscribe")
logging.info("Generating subscribe page")
with open(input_dir + "subscribe.json") as subscribe, \
open(output_dir + "subscribe/index.html", "w") as html:
html.write(env.get_template("subscribe.html").render(
relative="..",
subscriptions=json.load(subscribe)
))
if not path.isdir(output_dir + "donate"):
os.mkdir(output_dir + "donate")
logging.info("Generating donate page")
with open(input_dir + "donate.json") as donate, \
open(output_dir + "donate/index.html", "w") as html:
html.write(env.get_template("donate.html").render(
relative="..",
donations=json.load(donate)
))
logging.info("Sorting podcasts")
podcast.sort() podcast.sort()
logging.info("Generating thumbnails")
podcast.generate_thumbnails() podcast.generate_thumbnails()
logging.info("Generating archives pages")
podcast.generate_archives() podcast.generate_archives()
logging.info("Generating RSS feeds") podcast.generate_atom()
with open(input_dir + "header.rss") as header:
podcast.generate_rss(header.read())
logging.info("Generating Site")
podcast.generate_site(root) podcast.generate_site(root)
logging.info("Copying Overrides")
shutil.copytree(input_dir + "overrides", output_dir, dirs_exist_ok=True) shutil.copytree(input_dir + "overrides", output_dir, dirs_exist_ok=True)
logging.info("Done")
return 0
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main(parse_args())) main()

View File

@@ -1,3 +1,2 @@
jinja2 jinja2
markdown markdown
mutagen

View File

@@ -56,7 +56,7 @@ body {
.wrapper { .wrapper {
min-height: $top-height; min-height: $top-height;
align-items: flex-end; align-items: flex-end;
padding-bottom: 1em; padding-bottom: 2em;
.player { .player {
margin: auto; margin: auto;
width: 80%; width: 80%;
@@ -69,23 +69,11 @@ body {
} }
} }
.shownotes { .shownotes {
padding: 2em 1em 0; padding: 2em 1em 1em 1em;
margin: auto; margin: auto;
width: 80%; width: 80%;
a {
color: #292929;
padding: 0.3em;
border-radius: 1.6em;
transition-duration: 0.2s;
}
a:hover {
color: #FFF;
background-color: #000;
text-decoration: none;
transition-duration: 0.2s;
}
} }
ul.archives, ul.donate { ul.archives {
list-style-type: none; list-style-type: none;
width: 100%; width: 100%;
padding: 0; padding: 0;
@@ -106,37 +94,6 @@ body {
margin: 0.5em 1em; margin: 0.5em 1em;
} }
} }
.subscribe {
display: flex;
width: 600px;
justify-content: space-between;
flex-wrap: wrap;
margin: auto;
.subscription {
width: 200px;
color: #000;
text-align: center;
transition-duration: 0.2em;
padding: 1rem 0;
span {
color: inherit;
font-size: 100px;
text-decoration: none;
}
p {
@include title-font;
width: 100%;
font-size: 1rem;
}
}
.subscription:hover, .subscription:active {
text-decoration: none;
transition-duration: 0.2em;
background-color: #000;
color: #FFF;
border-radius: 30px;
}
}
} }
} }
@@ -148,7 +105,7 @@ body {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
flex-direction: column; flex-direction: column;
padding-top: 1em; padding-top: 2em;
height: 100%; height: 100%;
.content { .content {
display: flex; display: flex;
@@ -171,19 +128,6 @@ body {
color: #FFF; color: #FFF;
} }
} }
a.donate-link {
margin: 1em 0;
color: #292929;
padding: 0.3em;
border-radius: 1.6em;
transition-duration: 0.2s;
}
a:hover {
color: #FFF;
background-color: #000;
text-decoration: none;
transition-duration: 0.2s;
}
footer { footer {
margin-top: 1em; margin-top: 1em;
padding: 0 1em; padding: 0 1em;
@@ -229,17 +173,6 @@ h1 {
} }
} }
@media (max-width: 800px) {
body {
.top {
.wrapper {
.subscribe {
width: 400px;
}
}
}
}
}
@media (max-width: 600px) { @media (max-width: 600px) {
body { body {
.top_bg { .top_bg {
@@ -280,17 +213,6 @@ h1 {
} }
} }
@media (max-width: 480px) {
body {
.top {
.wrapper {
.subscribe {
width: 200px;
}
}
}
}
}
@keyframes move_right { @keyframes move_right {
from {left: 0} from {left: 0}

View File

@@ -1,15 +0,0 @@
{% extends "base.html" %}
{% block title %}Subscribe | Redacted Life{% endblock %}
{% block stylesheets %}
<link href="{{relative}}/assets/fork-awesome/css/fork-awesome.min.css" rel="stylesheet" type="text/css">
{% endblock %}
{% block left_content %}
<div class="subscribe">
{% for subscription in subscriptions %}
<a href={{subscription.link}} class="subscription">
<span class="fa fa-{{subscription.icon}}">
<p>{{subscription.text}}</p>
</a>
{% endfor %}
</div>
{% endblock %}