...
 
Commits (7)
  • Oliver Smith's avatar
    encode-video.sh: move to utils · aaccf308
    Oliver Smith authored
    aaccf308
  • Oliver Smith's avatar
    January 2019 redesign · e8d3de67
    Oliver Smith authored
    Create a new design based on the Nexus 5 photos from pparent. With two
    featured devices, a nice quote from KDE's twitter and new about and
    architecture texts on the front page. Use a few numix icons (like the
    wiki main page). Increase the font size.
    
    Categorize the blog posts by year in /blog. Remove TOC from all blog
    posts, instead add links to all headlines.
    
    Make everything responsive by replacing the box model based layout with
    a new grid layout. Rewrite all CSS files from scratch, throw out (box
    model related) tachyons.css and main.less. The new CSS files don't need
    to be generated with less anymore.
    
    Invent a new syntax to use the grid layout in the markdown blog posts
    by using new [#grid side#], [#grid text#], [#grid bottom#] and
    [#grid end#] tags. Describe it in README.md, adjust all existing posts
    to use grid layout. Fix a few minor mistakes in the existing posts
    along the way.
    
    Update requirements.txt and document how they can be updated in
    README.md.
    e8d3de67
  • Oliver Smith's avatar
    Qemu => QEMU · 70d95098
    Oliver Smith authored
    70d95098
  • Oliver Smith's avatar
    Change font size from 15pt to 13pt · 93ed049c
    Oliver Smith authored
    93ed049c
  • Oliver Smith's avatar
    adjust image positioning to new font size · 71b65809
    Oliver Smith authored
    71b65809
  • Oliver Smith's avatar
    CSS: update based on feedback · 709cd2f2
    Oliver Smith authored
    * remove white background from logo, use white font with shadow instead
    * add background color
    * only display slogan in mobile view on the main page, to make the
      header smaller
    * simplify some grid code
    * make the blog post titles (on single blog post pages) smaller in
      mobile view, so even long words fit the screen
    709cd2f2
  • Oliver Smith's avatar
    use grid in bottom buttons to fix display issues · 851953a7
    Oliver Smith authored
    It was reported in the chat with a screenshot, that the bottom buttons
    don't look right. Fix it with more grid.
    851953a7
......@@ -6,7 +6,7 @@
Python 3.4+ is supported. Install all requirements, preferably within a virtualenv:
```bash
```shell
$ python -m venv .venv
$ source .venv/bin/activate
(venv)$ pip install -r requirements.txt
......@@ -16,7 +16,7 @@ $ source .venv/bin/activate
Blog content is written in markdown format with metadata in the file header. Filename syntax is `yyyy-mm-dd-slug.md`.
```bash
```shell
$ cat >content/blog/2017-12-31-happy-new-year.md << EOF
> ---
> title: Happy New Year!
......@@ -26,33 +26,53 @@ $ cat >content/blog/2017-12-31-happy-new-year.md << EOF
> EOF
```
### Dev Server
### Writing responsive content
Run the dev server during local development, changes are auto reloaded:
Use the following custom tags to create responsive sections in the blog posts:
* `[#grid side#]`
* `[#grid text#]`
* `[#grid bottom#]`
* `[#grid end#]`
```bash
(venv)$ FLASK_DEBUG=1 FLASK_APP=app.py flask run
```
Using any tag except for "end" will encapsulate the following markdown code in the grid area of the same name. If the grid was not opened yet, it will be opened with the first tag. The "end" tag closes the grid.
### CSS
The grid layout looks like this, in desktop mode:
Not much CSS is used due to heavy usage of [Tachyons](http://tachyons.io/) toolkit classes. Please use CSS judiciously only when needed.
|text|(20px free space)|side|
|bottom|(20px free space)|side|
Any CSS used should be compiled via `lessc`:
...and with a lower screen width (mobile phones etc.):
|side|
|text|
|bottom|
Use the responsive mode tools of your browser to check if it works as expected. For usage examples, look at the existing blog posts and the grid-related code in `static/css/page.css`. This feature is implemented in `page.py`.
### Dev Server
```bash
$ npm install -g less
$ lessc static/css/main.less static/css/main.css
Run the dev server during local development, changes are auto reloaded:
```shell
(venv)$ FLASK_DEBUG=1 FLASK_APP=app.py flask run
```
### Build
To run a static site build, run:
```bash
```shell
(venv)$ python freeze.py
```
This will generate a static version in `docs/`. Any manual changes to the `docs/` directory will be overridden in the next build.
Note that the `docs/` directory is ignored and not versioned.
### Upgrading requirements.txt
```shell
(venv)$ pip install pip-upgrader
(venv)$ pip-upgrade
```
import collections
import logo
import markdown
import os
......@@ -9,6 +10,9 @@ from flask import Flask, render_template, url_for, Response, request, send_file
from werkzeug.contrib.atom import AtomFeed
from os import listdir
# current dir
import page
app = Flask(__name__)
......@@ -66,6 +70,11 @@ def logo_svg():
return Response(response=logo.create(phone=False), mimetype="image/svg+xml")
def parse_post(post, external_links=False, create_html=True):
""" :returns: a parsed post, something like this:
{"html": "<parsedhtmlcode...",
"url": "url/to/the/post",
"reading_time": "10 min",
"year": 2019} """
with open(os.path.join(BLOG_CONTENT_DIR, post), encoding="utf-8") as handle:
raw = handle.read()
frontmatter, content = REGEX_SPLIT_FRONTMATTER.split(raw, 2)
......@@ -79,21 +88,35 @@ def parse_post(post, external_links=False, create_html=True):
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc'
])
], extension_configs={"markdown.extensions.toc": {"anchorlink": True}})
data['html'] = page.replace(data['html'])
data['url'] = url_for('blog_post', y=y, m=m, d=d, slug=slug,
_external=external_links)
data['reading_time'] = reading_time(content)
data['year'] = y
return data
def get_posts(**kwargs):
""" :returns: posts categorized by year, looks like:
{2019: [post1, post2, ...], 2018: [...], ...}
post1, post2 are the posts as returned by parse_post() above.
"""
posts = sorted(listdir(BLOG_CONTENT_DIR), reverse=True)
return (parse_post(post, **kwargs) for post in posts)
ret = collections.OrderedDict()
for post in posts:
parsed = parse_post(post, **kwargs)
year = parsed['year']
if not year in ret:
ret[year] = []
ret[year].append(parsed)
return ret
@app.route('/blog/')
def blog():
return render_template('blog.html', posts=get_posts(create_html=False))
return render_template('blog.html',
year_posts=get_posts(create_html=False))
@app.route('/blog/feed.atom')
def atom():
......@@ -103,13 +126,15 @@ def atom():
title='postmarketOS Blog',
url=url_for('blog', _external=True))
for post in get_posts(external_links=True):
feed.add(content=post['html'],
content_type='html',
title=post['title'],
url=post['url'],
# midnight
updated=datetime.combine(post['date'], datetime.min.time()))
for year, posts in get_posts(external_links=True).items():
for post in posts:
feed.add(content=post['html'],
content_type='html',
title=post['title'],
url=post['url'],
# midnight
updated=datetime.combine(post['date'],
datetime.min.time()))
return feed.get_response()
@app.route('/blog/<y>/<m>/<d>/<slug>/')
......@@ -128,7 +153,7 @@ def static_page(page):
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc'
])
], extension_configs={"markdown.extensions.toc": {"anchorlink": True}})
return render_template('page.html', **data)
......
......@@ -2,16 +2,11 @@ title: "Aiming for a 10 year life-cycle for smartphones"
date: 2017-05-26
---
[![Samsung Galaxy SII (i9100) running postmarketOS](/static/img/2017-05-26/i9100-filled-thumb.jpg)](/static/img/2017-05-26/i9100-filled.jpg)
[![Samsung Galaxy SII (i9100) running postmarketOS](/static/img/2017-05-26/i9100-filled-thumb.jpg){: class="border"}](/static/img/2017-05-26/i9100-filled.jpg)
_Introduction post to [postmarketOS](https://github.com/postmarketOS/), a touch-optimized, pre-configured [Alpine Linux](https://alpinelinux.org/) with own packages, that can be installed on smartphones. (Not usable for most people yet!)_
## Index
[TOC]
## Minimalistic Linux distributions run fine on ten year old PCs.
It is 2017\. Pick an average PC from 2007 and install a minimal Linux based operating system. You will be able to do basic computing tasks (eg. surfing the web, reading E-Mails, listening to music, chatting) just like on an _expensive_ modern PC. You will even get security updates, so your old computer is protected, just like as a new one.
## Why are Android/Linux phones different?
......@@ -30,13 +25,13 @@ Here is the solution: Bend an existing Linux distribution to run on smartphones.
Of course we are not the only ones, that came to this conclusion - especially in the last few weeks with the [Halium](https://halium.org/) project rising _(greetings!)_. We are all-in for working together — sharing udev rules, merging Android kernels together, whatever makes sense!
[![Unlocking encrypted rootfs via telnet](https://ollieparanoid.github.io/img/2017-05-26/i9100/telnet-thumb.jpg "Unlocking encrypted rootfs via telnet")](https://ollieparanoid.github.io/img/2017-05-26/i9100/telnet.jpg)
[![Unlocking encrypted rootfs via telnet](https://ollieparanoid.github.io/img/2017-05-26/i9100/telnet-thumb.jpg "Unlocking encrypted rootfs via telnet"){: class="border"}](https://ollieparanoid.github.io/img/2017-05-26/i9100/telnet.jpg)
## postmarketOS architecture
We're working on an Alpine Linux based distribution called postmarketOS where each phone will have **only one [unique](https://github.com/postmarketOS/pmbootstrap/tree/master/aports/device/device-samsung-i9100/) [package](https://github.com/postmarketOS/pmbootstrap/tree/master/aports/device/device-lg-mako)** — all other packages are shared among all devices.
These `device-$vendor-$name` packages contain a so-called `/etc/deviceinfo` file, which [describes](https://github.com/postmarketOS/pmbootstrap/blob/master/aports/device/device-samsung-i9100/deviceinfo) [what](https://github.com/postmarketOS/pmbootstrap/blob/master/aports/device/device-lg-mako/deviceinfo) makes the device special: SD card availability, which flash software to use and other information. The file format is not stable yet, and once we have common kernels for multiple devices, I'd like to include the required modules and `dtb` name.
These `device-$vendor-$name` packages contain a so-called `/etc/deviceinfo` file, which [describes](https://github.com/postmarketOS/pmbootstrap/blob/master/aports/device/device-samsung-i9100/deviceinfo) [what](https://github.com/postmarketOS/pmbootstrap/blob/master/aports/device/device-lg-mako/deviceinfo) makes the device special: SD card availability, which flash software to use and other information. The file format is not stable yet, and once we have common kernels for multiple devices, We'd like to include the required modules and `dtb` name.
And just to make it clear, postmarketOS does not fit the Halium model, as it avoids the Android build system entirely and does _not_ run any part of the Android userspace next to its more or less typical Linux userspace. _(At least not in the regular install, but it could come at some point in the future as optional compatibility layer for Android applications if someone wants to work on it.)_
......@@ -125,12 +120,11 @@ Great care has been taken to make pmbootstrap safe, as it will run on productive
### Photos
[![postmarketOS demos menu](/static/img/2017-05-26/i9100-demos-thumb.jpg){: class="cl fl mr3 mb3" }](/static/img/2017-05-26/i9100-demos.jpg)
[![Firefox running in XWayland](/static/img/2017-05-26/i9100-firefox-thumb.jpg){: class="fl mr3 mb3" }](/static/img/2017-05-26/i9100-firefox.jpg)
[![htop in two weston-terminals](/static/img/2017-05-26/i9100-htop-thumb.jpg){: class="fl mr3 mb3" }](/static/img/2017-05-26/i9100-htop.jpg)
[![Weston smoke demo](/static/img/2017-05-26/i9100-smoke-thumb.jpg){: class="fl mr3 mb3" }](/static/img/2017-05-26/i9100-smoke.jpg)
[![lg-mako: colors are red, but weston-editor works due to the bigger screen size](/static/img/2017-05-26/mako-editor-thumb.jpg){: class="fl mr3 mb3" }](/static/img/2017-05-26/mako-editor.jpg)
[#grid bottom#]
[![postmarketOS demos menu](/static/img/2017-05-26/i9100-demos-thumb.jpg)](/static/img/2017-05-26/i9100-demos.jpg)
[![Firefox running in XWayland](/static/img/2017-05-26/i9100-firefox-thumb.jpg)](/static/img/2017-05-26/i9100-firefox.jpg)
[![htop in two weston-terminals](/static/img/2017-05-26/i9100-htop-thumb.jpg)](/static/img/2017-05-26/i9100-htop.jpg)
[![Weston smoke demo](/static/img/2017-05-26/i9100-smoke-thumb.jpg)](/static/img/2017-05-26/i9100-smoke.jpg)
[![lg-mako: colors are red, but weston-editor works due to the bigger screen size](/static/img/2017-05-26/mako-editor-thumb.jpg)](/static/img/2017-05-26/mako-editor.jpg)
[#grid end#]
......@@ -2,8 +2,6 @@ title: Why supporting the Librem Phone crowdfunding campaign helps postmarketOS
date: 2017-09-24
---
[TOC]
## Proprietary components make smartphones insecure for the masses
Whenever you buy *any* smartphone, you get a device full of proprietary components. These are integrated so deeply with each other that they can access everything on your phone, such as the camera, microphone, browser history and chat messages. Since these components are proprietary, they've been designed to make it **impossible for anyone but the vendor to modify**, and they can only be **understood by others through immense efforts**.
......
This diff is collapsed.
This diff is collapsed.
......@@ -2,7 +2,7 @@ title: "postmarketOS is #movingtogitlab"
date: 2018-06-27
---
[![Broken Sony Xperia Z2 Tablet](/static/img/2018-06/broken-castor-thumb.jpg)](/static/img/2018-06/broken-castor.jpg)
[![Broken Sony Xperia Z2 Tablet](/static/img/2018-06/broken-castor-thumb.jpg){: class="wfull border" }](/static/img/2018-06/broken-castor.jpg)
For a lot of people, learning that [Microsoft will buy GitHub at the end of 2018](https://www.bloomberg.com/news/articles/2018-06-04/microsoft-agrees-to-buy-coding-site-github-for-7-5-billion) [shattered trust in GitHub](https://jacquesmattheij.com/what-is-wrong-with-microsoft-buying-github) like the glass of [@opendata26](https://gitlab.com/opendata26)'s [Sony Xperia Z2 Tablet](https://wiki.postmarketos.org/wiki/Sony_Xperia_Z2_Tablet_(sony-castor-windy)). Beyond that, GitHub has always employed vendor lock-in: the user's issues and pull requests are hidden behind a rate limited API instead of being available through a proper export feature. And even if you managed to export it through that API, you cannot host your own GitHub instance and modify it as you like because, there is not even a partially open source version of it.
......
......@@ -12,7 +12,7 @@ Read the [Plasma Mobile's blog post](https://www.plasma-mobile.org/2018/08/23/Pl
### UPDATE: The [video recordings](https://cdn.files.kde.org/akademy/2018/videos/) of the talks are online!
[![](/static/img/2018-08/pmos-plamo-akademy2018.jpg)](/static/img/2018-08/pmos-plamo-akademy2018.jpg)
[![](/static/img/2018-08/pmos-plamo-akademy2018.jpg){: class="wfull border" }](/static/img/2018-08/pmos-plamo-akademy2018.jpg)
From left to right:
[@ata2001](https://gitlab.com/ata2001),
......
# Copyright 2018 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
def grid(html):
""" Replace the following markers with appropriate <div class="..."> and
</div> tags. See README.md and static/code/blog-post.css for more
information.
- "[#grid side#]"
- "[#grid text#]"
- "[#grid bottom#]"
- "[#grid end#]"
:param html: blog post code (already converted from markdown to HTML)
:returns: html with all markers replaced """
sections = ["side", "text", "bottom"]
ret = ""
in_grid = False
for word in html.split("[#grid "):
# Continue or start grid
if in_grid:
# Avoid "<p></div>"
if ret[-3:] == "<p>":
ret = ret[:-3]
ret += "</div>"
# New grid section
tag_found = ''
for section in sections:
tag = section + "#]"
if word.startswith(tag):
tag_found = tag
if not in_grid:
ret += '<div class="grid">'
in_grid = True
ret += '<div class="grid-' + section + '">'
break
# End grid
tag = "end#]"
if word.startswith(tag):
if not in_grid:
raise ValueError("[#grid end#] found before it was opened!")
tag_found = tag
ret += "</div>"
in_grid = False
# Remove tag from word
word = word[len(tag_found):]
# Avoid "<div class=...></p>"
if word[:4] == "</p>":
word = word[4:]
ret += word
# Check for grids without end tag
if in_grid:
raise ValueError("Missing [#grid end#]!")
return ret
def replace(html):
""" Various replacements for blog posts, to make them responsive etc.
:param html: blog post code (already converted from markdown to HTML)
:returns: html with replacements made """
ret = grid(html)
return ret
click==6.7
Flask==0.12.2
click==7.0
Flask==1.0.2
Frozen-Flask==0.15
itsdangerous==0.24
Jinja2==2.9.6
Markdown==2.6.8
MarkupSafe==1.0
Pygments==2.2.0
PyYAML==3.12
Werkzeug==0.12.2
itsdangerous==1.1.0
Jinja2==2.10
Markdown==3.0.1
MarkupSafe==1.1.0
Pygments==2.3.1
PyYAML==3.13
Werkzeug==0.14.1
/* Copyright 2018 Oliver Smith
SPDX-License-Identifier: GPL-3.0-or-later */
/* LINKS */
a {
color: black;
}
a:hover {
color: #0d8000;
}
/* GRID: OUTER */
body {
display: grid;
grid-template-areas: ". header ."
". main ."
". footer .";
grid-template-columns: auto minmax(360px, 1024px) auto;
margin: 0px;
background: #f5f5f5;
font-family: sans-serif;
line-height: 2;
font-size: 13pt;
}
/* MAIN */
main {
grid-area: main;
background: white;
}
h1 {
font-size: 25pt;
}
.content {
padding: 10px 30px 40px;
}
.content.alt {
background: #eee;
}
.codehilite pre {
font-size: 10pt;
overflow: hidden;
text-overflow: ellipsis;
}
.separator {
background-image: url(/static/img/nexus5-bg-bottom.jpg);
height: 10px;
}
/* GRID: HEADER */
.header {
grid-area: header;
display: grid;
grid-template-areas: "logo . nav"
". . nav"
"slogan . ."
"slogan . disclaimer";
grid-template-columns: auto 1fr auto;
background-image: url(/static/img/nexus5-bg.jpg);
background-repeat: no-repeat;
background-position: left bottom;
}
/* SLOGAN AND DISCLAIMER */
.slogan {
grid-area: slogan;
padding: 30px;
color: white;
font-size: 25pt;
font-weight: bold;
line-height: 35pt;
}
.slogan small {
font-size: 15pt;
line-height: 1;
}
.disclaimer {
grid-area: disclaimer;
margin: 15px 30px;
padding: 3px 7px;
background: black;
color: white;
font-weight: bold;
font-size: 10pt;
}
/* GRID: LOGO */
.logo {
grid-area: logo;
display: grid;
align-items: center;
grid-template-areas: "logo-img logo-span";
grid-template-columns: 90px 1fr;
padding: 10px 0px 0px;
margin-left: 30px;
min-height: 90px;
text-decoration: none;
}
.logo img {
grid-area: logo-img;
width: 75px;
height: 75px;
filter: drop-shadow(0 0 7px rgba(0,0,0,0.3));
}
.logo span {
grid-area: logo-span;
font-size: 25pt;
text-shadow: 0px 0px 8px rgba(0, 0, 0, 0.5);
color: white;
}
/* GRID: NAVIGATION */
.nav {
grid-area: nav;
display: grid;
grid-template-areas: "nav-row1"
"."
"nav-row2"
"."
"nav-row3";
grid-template-rows: auto
6px
auto
6px
1fr;
text-align: right;
margin: 15px 30px;
}
.nav-row1 {
grid-area: nav-row1;
}
.nav-row2 {
grid-area: nav-row2;
}
.nav-row3 {
grid-area: nav-row3;
}
.nav a {
font-size: 10pt;
background: white;
padding: 5px 4px;
margin-left: 2px;
font-weight: bold;
}
.nav-row1 a {
font-size: 15pt;
}
/* GRID: FOOTER */
footer {
grid-area: footer;
display: grid;
grid-template-areas: "contribute . nav-bottom"
"contribute . copyright";
grid-template-columns: auto 1fr auto;
align-items: center;
background-image: url(/static/img/nexus5-bg-bottom.jpg);
}
.nav-bottom {
grid-area: nav-bottom;
margin: 15px 30px 0px;
text-align: right;
}
/* GRID: ICON BUTTON */
.icon-button {
display: inline-grid;
grid-template-areas: "icon-button-icon icon-button-label";
grid-template-columns: auto auto;
padding: 0px 10px;
align-items: center;
background: white;
text-decoration: none;
margin-left: 2px;
}
.icon-button img {
grid-area: icon-button-icon;
width: 16px;
height: 16px;
margin-right: 5px;
}
.icon-button span {
grid-area: icon-button-label;
text-decoration: underline;
}
.icon-button:hover img {
/* Obviously this changes the color to green */
filter: sepia(1) saturate(5) hue-rotate(80deg);
}
.contribute {
grid-area: contribute;
font-size: 20pt;
padding: 10px 20px;
margin: 0px 30px;
}
.contribute span {
text-decoration: none;
}
.contribute img {
width: 48px;
height: 48px;
margin-right: 10px;
}
.copyright {
grid-area: copyright;
color: white;
margin: 5px 30px 15px;
font-size: 11pt;
text-align: right;
}
/* RESPONSIVENESS */
@media screen and (max-width: 800px) {
/* HEADER */
.header {
grid-template-areas: "logo nav nav"
". nav nav"
"slogan slogan slogan"
"disclaimer disclaimer disclaimer";
}
.logo span {
font-size: 20pt;
}
.slogan {
/* Hide the slogan in mobile view everywhere, except on the main page.
We override this in index.css. */
display: none;
}
/* MAIN */
.codehilite pre {
font-size: 8pt;
}
/* FOOTER */
footer {
grid-template-areas: "contribute"
"nav-bottom"
"copyright";
grid-template-columns: 100%;
}
.nav-bottom {
text-align: center;
}
.nav-bottom .icon-button {
margin: 0px 2px 10px;
}
.nav-bottom .icon-button img {
margin-right: 10px;
}
.contribute {
margin: 15px auto 0px;
}
.copyright {
text-align: center;
}
}
@media screen and (max-width: 600px) {
/* HEADER */
.header {
grid-template-areas: "logo"
"nav"
"slogan"
"disclaimer";
grid-template-columns: 100%;
}
.logo {
margin-left: 0px;
padding-left: 30px;
}
.nav {
text-align: left;
margin-left: 30px;
}
.nav a {
margin-left: 0px;
margin-right: 5px;
}
.disclaimer {
margin: 10px 30px 15px;
font-size: 8pt;
}
}
/* Copyright 2018 Oliver Smith
SPDX-License-Identifier: GPL-3.0-or-later
This file is used for the listing of all blog posts (/blog).
See page.css for the file used in single blog posts. */
.post {
display: grid;
grid-template-areas: ". . title"
"date . title"
"reading_time . title"
". . title";
grid-template-columns: min-content 20px 1fr;
grid-template-rows: 1fr
auto
auto
1fr;
margin: 10px 0px;
}
.title {
grid-area: title;
font-size: 14pt;
}
.date {
grid-area: date;
white-space: nowrap;
font-size: 12pt;
}
.reading_time {
grid-area: reading_time;
color: gray;
font-size: 9pt;
}
/* RESPONSIVENESS */
@media screen and (max-width: 600px) {
.post {
grid-template-areas: "date . reading_time"
"title title title";
grid-template-columns: min-content 10px 1fr;
grid-template-rows: auto
auto;
margin-bottom: 20px;
}
.reading_time {
font-size: 12pt;
}
}
/* Copyright 2018 Oliver Smith
SPDX-License-Identifier: GPL-3.0-or-later */
h2, h3 {
text-transform: uppercase;
}
.more-link {
display: block;
margin-top: 20px;
}
.more-link:after {
content: " >";
}
/* DEVICES */
.devices {
display: grid;
grid-template-areas: ". device1 . device2 .";
grid-template-columns: "1fr auto 1fr auto 1fr";
}
.device1 {
grid-area: device1;
}
.device2 {
grid-area: device2;
}
.devices div {
padding: 20px;
width: 340px;
border: 1px solid lightgrey;
background: white;
margin-left: auto;
margin-right: auto;
}
.devices img{
height: 250px;
border: 1px solid lightgrey;
}
/* WHAT OTHERS SAY */
.quote {
font-style: italic;
font-size: 20pt;
margin-bottom: 20px;
}
/* RESPONSIVENESS */
@media screen and (max-width: 900px) {
.devices {
grid-template-areas: "device1"
"."
"device2";
grid-template-rows: auto
20px
auto;
grid-template-columns: 100%;
}
.devices div {
width: auto;
padding: 10px;
}
.devices img {
height: auto;
width: 100%;
}
}
@media screen and (max-width: 800px) {
/* Have a bigger header on the mobile main page: display the slogan, and
make the disclaimer bigger (so it does not look ridiculously small
compared to the slogan). */
.slogan {
display: block;
}
.disclaimer {
font-size: 10pt;
}
}
@media screen and (max-width: 600px) {
.more-link {
font-size: 10pt;
}
}
main {
background: #eee;
}
a {
color: #0d8000;
}
.light-headline {
font-size: 2.4em;
font-weight: 200;
}
.below-banner {
line-height: 1.5;
}
/* color #20c216 is from the fp2 mainlining photo */
.inverted {
color: white;
background: #333;
border-top: 4px solid #20c216;
border-bottom: 4px solid #20c216;
}
.inverted a {
color: #20c216;
}
/* color #8a4621 is from the background of the N9 photo */
.sustainable {
border-top: 4px solid #8a4621;
border-bottom: 4px solid #8a4621;
}
@branding-color: #0d8000;
main {
background: #eee;
}
a {
color: @branding-color;
}
.inverted {
color: white;
background: #333;
border-top: 4px solid @branding-color;
border-bottom: 4px solid @branding-color;
}
/* Copyright 2018 Oliver Smith
SPDX-License-Identifier: GPL-3.0-or-later
This file is used for single blog posts and for pages (e.g. FAQ). */
/* HEADLINES WITH TOC-LINKS */
.toclink {
text-decoration: none;
}
.toclink:hover {
text-decoration: underline;
}
/* TITLE RELATED */
.title {
display: grid;
grid-template-areas: "title title"
"date reading_time";
margin: 20px 30px 0px;
}
.title h1 {
grid-area: title;
margin: 60px 0px;
font-size: 30pt;
text-align: center;
line-height: 50pt;
display: block;
/* treat \n like <br> (we replace ":" with ":\n" in post titles) */
white-space: pre-line;
}
.date {
grid-area: date;
}
.reading_time {
grid-area: reading_time;
text-align: right;
}
/* IMAGES */
img.w200 {
width: 200px;
}
img.wfull {
width: 100%;
}
img.border {
border: 1px solid lightgrey;
}
/* GRID */
.grid {
display: grid;
grid-template-areas: "text . side"
"bottom . side";
grid-template-columns: auto 20px auto;
}
.grid-text {
grid-area: text;
}
.grid-side {
grid-area: side;
text-align: right;
}
.grid-side img,
.grid-side video {
max-width: 100%;
}
.grid-bottom {
grid-area: bottom:
}
.grid-bottom img,
.grid-bottom video {
border: 1px solid lightgrey;
}
/* RESPONSIVENESS */
@media screen and (max-width: 800px) {
.grid {
grid-template-areas: "side"
"text"
"bottom";
grid-template-columns: 100%;
}
.grid-side {
text-align: center;
}
.grid-bottom {
text-align: center;
}
}
@media screen and (max-width: 500px) {
.title h1 {
font-size: 22pt;
}
}
@media screen and (max-width: 400px) {
.date,
.reading_time {
font-size: 12pt;
}
}
This diff is collapsed.
* Sources: https://github.com/numixproject/numix-icon-theme
* License: GNU GPLv3
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path style="visibility:visible;shape-rendering:auto;color-interpolation-filters:linearRGB;fill:#353535;opacity:1;image-rendering:auto;fill-opacity:1;text-rendering:auto;stroke:none;display:inline;color:#000;fill-rule:nonzero;color-rendering:auto;color-interpolation:sRGB" d="m 1 3.07 1.035 0 c 6.03 0 10.895 4.865 10.895 10.895 l 0 1.035 2.07 0 0 -1.035 c 0 -7.148 -5.817 -12.965 -12.965 -12.965 l -1.035 0 0 2.07 z"/>
<path style="visibility:visible;shape-rendering:auto;color-interpolation-filters:linearRGB;fill:#353535;opacity:1;image-rendering:auto;fill-opacity:1;text-rendering:auto;stroke:none;display:inline;color:#000;fill-rule:nonzero;color-rendering:auto;color-interpolation:sRGB" d="m 1 8.07 1.035 0 c 3.268 0 5.895 2.627 5.895 5.895 l 0 1.035 2.07 0 0 -1.035 c 0 -4.387 -3.578 -7.965 -7.965 -7.965 l -1.035 0 0 2.07 z"/>
<circle r="2" style="fill:#353535;opacity:1;fill-opacity:1;stroke:none;fill-rule:nonzero" cy="13" cx="3"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<rect width="14" height="10" x="1" y="6" rx="2" style="fill:#353535;opacity:1;fill-opacity:1;stroke:none;fill-rule:nonzero"/>
<path d="m 8 0 c -0.82 0 -1.64 0.164 -2.396 0.49 c -1.512 0.653 -2.604 1.965 -2.604 3.51 l 0 3 l 2 0 l 0 -3 c 0 -0.594 0.433 -1.258 1.396 -1.674 c 0.963 -0.416 2.244 -0.416 3.207 0 c 0.963 0.416 1.396 1.08 1.396 1.674 l 0 3 l 2 0 l 0 -3 c 0 -1.545 -1.091 -2.857 -2.604 -3.51 c -0.756 -0.327 -1.576 -0.49 -2.396 -0.49 z" mix-blend-mode="normal" isolation="auto" white-space="normal" solid-opacity="1" solid-color="#000000" style="visibility:visible;shape-rendering:auto;color-interpolation-filters:linearRGB;fill:#353535;opacity:1;image-rendering:auto;fill-opacity:1;stroke:none;display:inline;color:#000;fill-rule:nonzero;color-rendering:auto;color-interpolation:sRGB"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g transform="translate(-481 -681)" style="fill:#353535;fill-opacity:1">
<path d="m 496 686.76 c 0 -2.077 -1.687 -3.76 -3.769 -3.76 c -1.371 0 -2.571 0.731 -3.231 1.823 c -0.659 -1.092 -1.86 -1.823 -3.231 -1.823 c -2.082 0 -3.769 1.683 -3.769 3.76 0 1.081 0.458 2.054 1.19 2.74 l -0.001 0 5.725 5.5 5.899 -5.5 -0.002 0 c 0.732 -0.686 1.189 -1.659 1.189 -2.74"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g transform="translate(-221.0002 -747)" style="fill:#353535;color:#353535">
<rect width="2" x="-751.98" y="-234.97" rx="0" height="11.968" transform="matrix(0 -1 -1 0 0 0)"/>
<path d="m 235.01 760 0 -1 c -0.001 -0.011 0.001 -0.021 0 -0.031 -0.011 -0.255 -0.128 -0.51 -0.313 -0.687 l -5.719 -6.298 -5.719 6.298 c -0.188 0.188 -0.281 0.453 -0.281 0.719 l 0 1 1 0 c 0.265 0 0.531 -0.093 0.719 -0.281 l 4.281 -4.829 4.281 4.829 c 0.195 0.211 0.469 0.303 0.75 0.281 z"/>
</g>
</svg>
<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="128px" height="128px" id="RSSicon" viewBox="0 0 256 256">
<defs>
<linearGradient x1="0.085" y1="0.085" x2="0.915" y2="0.915" id="RSSg">
<stop offset="0.0" stop-color="#E3702D"/><stop offset="0.1071" stop-color="#EA7D31"/>
<stop offset="0.3503" stop-color="#F69537"/><stop offset="0.5" stop-color="#FB9E3A"/>
<stop offset="0.7016" stop-color="#EA7C31"/><stop offset="0.8866" stop-color="#DE642B"/>
<stop offset="1.0" stop-color="#D95B29"/>
</linearGradient>
</defs>
<rect width="256" height="256" rx="55" ry="55" x="0" y="0" fill="#CC5D15"/>
<rect width="246" height="246" rx="50" ry="50" x="5" y="5" fill="#F49C52"/>
<rect width="236" height="236" rx="47" ry="47" x="10" y="10" fill="url(#RSSg)"/>
<circle cx="68" cy="189" r="24" fill="#FFF"/>
<path d="M160 213h-34a82 82 0 0 0 -82 -82v-34a116 116 0 0 1 116 116z" fill="#FFF"/>
<path d="M184 213A140 140 0 0 0 44 73 V 38a175 175 0 0 1 175 175z" fill="#FFF"/>
</svg>
......@@ -13,36 +13,70 @@
<meta name="robots" content="all">
<link rel="canonical" href="https://postmarketos.org{{ request.path }}">
<link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.ico') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/tachyons.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/codehilite.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<link rel="shortcut icon" href="/static/img/favicon.ico">
<link rel="stylesheet" href="/static/css/base.css">
<link rel="stylesheet" href="/static/css/codehilite.css">
<link rel="alternate" type="application/atom+xml" title="postmarketOS Blog" href="{{ url_for('atom') }}">
{% block extra_link %}{% endblock %}
</head>
<body>
{% include 'header.html' %}
<main class="cf pv4">
<div class="mw8 center">
<header class="header">
<a class="logo" name="^" href="/">
<img src="/logo.svg">
<span>postmarketOS</span>
</a>
<div class="nav">
<div class="nav-row1">
<a href="/blog">blog</a>
<a href="/faq.html">faq</a>
<a href="https://wiki.postmarketos.org">wiki</a>
<a href="https://gitlab.com/postmarketOS">src</a>
</div>
<div class="nav-row2">
<a href="https://wiki.postmarketos.org/wiki/Matrix_and_IRC">matrix/irc</a>
<a href="https://fosstodon.org/@postmarketOS">mastodon</a>
</div>
<div class="nav-row3">
<a href="https://twitter.com/postmarketOS">twitter</a>
<a href="https://reddit.com/r/postmarketOS">reddit</a>
</div>
</div>
<div class="slogan">
A real Linux<br>
distribution<br>
for phones<br>
<small>and other mobile devices.</small>
</div>
<div class="disclaimer">Alpha version. Calls don't work, etc. Only suitable for hackers.</div>
</header>
<main class="main">
{% block body %}
{% endblock %}
</div>
</main>
{% block footer %}
<footer class="bg-white">
<div class="mw8 center w-100 pv4 tc">
<h2>Come help us!</h2>
<ul class="list center tc pl0 pl3-ns">
<li class="dib pa3"><a href="https://wiki.postmarketos.org">Wiki</a></li>
<li class="dib pa3"><a href="https://gitlab.com/postmarketOS">gitlab</a></li>
<li class="dib pa3"><a href="https://reddit.com/r/postmarketOS">/r/postmarketOS</a></li>
<li class="dib pa3"><a href="https://fosstodon.org/@postmarketOS">Mastodon</a></li>
<li class="dib pa3"><a href="https://twitter.com/postmarketOS">Twitter</a></li>
<li class="dib pa3"><a href="https://matrix.to/#/#postmarketos:disroot.org">#postmarketos:disroot.org</a></li>
<li class="dib pa3">#postmarketos on Freenode IRC</li>
</ul>
<a href="{{ url_for('static_page', page='privacy-policy') }}" class="center">Privacy policy</a>
</div>
</footer>
{% endblock %}
</main>
<footer class="footer">
<a href="https://wiki.postmarketos.org/wiki/Contributing" class="icon-button contribute">
<img src="/static/img/icons-numix/emote-love-symbolic.svg">
<span>Contribute</span>
</a>
<div class="nav-bottom">
<!-- scroll to top: the JS version is slightly nicer, as it does not change the URL.
but the non-JS version works as well. -->
<a href="#^" onclick="window.scrollTo(0,0); return false" class="icon-button">
<img src="/static/img/icons-numix/go-top-symbolic.svg">
<span>back to top</span>
</a>
<a href="/blog/feed.atom" class="icon-button">
<img src="/static/img/icons-numix/application-rss+xml-symbolic.svg">
<span>feed</span>
</a>
<a href="/privacy-policy.html" class="icon-button">
<img src="/static/img/icons-numix/changes-secure-symbolic.svg">
<span>privacy policy</span>
</a>
</div>
<div class="copyright">
&copy; 2019 postmarketOS.org contributors
</div>
</footer>
</body>
</html>
{% extends 'base.html' %}
{% block extra_link %}
<link rel="alternate" type="application/atom+xml" title="postmarketOS Blog" href="{{ url_for('atom') }}" />
{% endblock %}
{% extends 'blog-base.html' %}
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block title %}postmarketOS // {{ title }}{% endblock %}
{%block extra_link %}
<link rel="stylesheet" href="/static/css/page.css">
{%endblock%}
{% block body %}
<article class="pa3 lh-copy">
<div class="meta gray">
<span class="f4">{{ date.strftime('%B %d, %Y') }}</span>
<span class="f5 ph3">{{ reading_time }} min. read</span>
</div>
<h1 class="f2 f2-ns">{{ title }}</h1>
<div class="title">
<h1>{{ title | replace(":", ":\n") }}</h1>
<span class="date">{{ date.strftime('%B %d, %Y') }}</span>
<span class="reading_time">{{ reading_time }} min. read</span>
</div>
<div class="separator"></div>
<article class="content alt">
{{ html|safe }}
</article>
{% endblock %}
{% extends 'blog-base.html' %}
{% extends 'base.html' %}
{% block title %}postmarketOS Blog{% endblock %}
{% block title %}postmarketOS // blog{% endblock %}
{%block extra_link %}
<link rel="stylesheet" href="/static/css/blog.css">
{%endblock%}
{% block body %}
<section class="blog">
<h2 class="f3 tc tl-ns">Blog Posts<a href="{{ url_for('atom') }}"><img src="{{ url_for('static', filename='img/rss.svg') }}" class="h1 pl2"></a></h2>
<div class="fl mw9 center">
{% for post in posts %}
<div class="fl w-100">
<div class="fl w-30 gray tr pr2 pr4-ns pa2">
<div class="f4 f3-ns">{{ post.date.strftime('%B %d, %Y') }}</div>
<div class="f5 f4-ns">({{ post.reading_time }} min)</div>
</div>
<div class="fl w-70 pa2 pl4">
<a class="f4 f3-ns black link dim" href="{{ post.url }}">{{ post.title }}</a>
</div>
</div>
{% endfor %}
</div>
</section>
{% for year, posts in year_posts.items() %}
<div class="content {% if loop.index is divisibleby 2 %}alt{% endif %}">
<h2>{{ year }}</h2>
{% for post in posts %}
<div class="post">
<a class="title" href="{{ post.url }}">{{ post.title }}</a>
<span class="date">{{ post.date.strftime('%Y-%m-%d') }}</span>
<span class="reading_time">({{ post.reading_time }} min)</span>
</div>
{% endfor %}
</div>
{% if not loop.last %}
<div class="separator"></div>
{% endif %}
{% endfor %}
{% endblock %}
<header class="bg-white">
<div class="cf mw8 pv3 center">
<div class="fl w-100 w-50-ns pl3-ns">
<a class="tc tl-ns link" href="{{ url_for('home') }}">
<div>
<img class="v-mid" src="{{ url_for('logo_svg') }}">
<span class="dib v-mid ph1 black f2-l f3">postmarketOS</span>
</div>
</a>
</div>
<div class="fl w-100 w-50-ns pr3-ns">
<ul class="tc tr-ns f4 f3-ns pl0">
<li class="dib"><a class="link dim pr3" href="{{ url_for('home') }}">Home</a></li>
<li class="dib"><a class="link dim pr3" href="{{ url_for('blog') }}">Blog</a></li>
<li class="dib"><a class="link dim pr3" href="{{ url_for('static_page', page='faq') }}">FAQ</a></li>
<li class="dib"><a class="link dim pr3" href="https://wiki.postmarketos.org">Wiki</a></li>
<li class="dib"><a class="link dim pr3" href="https://gitlab.com/postmarketOS">gitlab</a></li>
</ul>
</div>
</div>
</header>
This diff is collapsed.
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block title %}postmarketOS // {{ title }}{% endblock %}
{%block extra_link %}
<link rel="stylesheet" href="/static/css/page.css">
{%endblock%}
{% block body %}
<article class="pa3 lh-copy">
<h1 class="f2 f2-ns">{{ title }}</h1>
<div class="title">
<h1>{{ title }}</h1>
</div>
<div class="separator"></div>
<article class="content alt">
{{ html|safe }}
</article>
{% endblock %}
<!doctype html>
<html>
<head>
<meta http-equiv="refresh" content="0;URL={{ url }}"
<meta http-equiv="refresh" content="0;URL={{ url }}">
</head>
<body>Redirecting to <a href="{{ url }}">{{ url }}</a>...</body>
</html>