New preact based frontend UI for the TTT.
Added rollup compiling
@ -1,3 +1,3 @@
|
||||
last 2 major version
|
||||
>0.5%
|
||||
not dead
|
||||
not ie < 12
|
||||
|
12
babel.config.js
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
module.exports = exports = {
|
||||
plugins: [
|
||||
[ '@babel/plugin-proposal-class-properties', { loose: true } ],
|
||||
],
|
||||
presets: [
|
||||
[ '@babel/preset-env', {
|
||||
// useBuiltIns: 'usage',
|
||||
} ],
|
||||
'preact',
|
||||
],
|
||||
};
|
@ -20,7 +20,7 @@ module.exports = exports = class File {
|
||||
|
||||
const file = path.parse(filepath);
|
||||
|
||||
this._basename();
|
||||
this._basename(file);
|
||||
|
||||
this.kind = kind(filepath);
|
||||
this.type = type(filepath);
|
||||
@ -28,7 +28,7 @@ module.exports = exports = class File {
|
||||
this.cwd = file.dir;
|
||||
this.ext = this.preprocessed ? file.ext : normalizedExt(file.ext);
|
||||
this.name = file.name; // index, fileA, fileB
|
||||
this.basename = file.basename; // index.ext, fileA.ext, fileB.ext
|
||||
this.basename = file.base; // index.ext, fileA.ext, fileB.ext
|
||||
|
||||
const dir = this._dir(file.dir);
|
||||
if (dir) {
|
||||
@ -59,7 +59,7 @@ module.exports = exports = class File {
|
||||
if (file.name[0] === '_') {
|
||||
this.preprocessed = true;
|
||||
file.name = file.name.slice(1);
|
||||
file.basename = file.basename.slice(1);
|
||||
file.base = file.base.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ const { siteInfo } = require(resolve('package.json'));
|
||||
module.exports = exports = async function writePageContent (engines, pages, posts, prod) {
|
||||
const postIndex = index(posts, engines);
|
||||
await processPages(engines, [ ...posts, ...pages ], postIndex, prod);
|
||||
postIndex.latest = { ...pageJSON(postIndex.latest), content: postIndex.latest.content };
|
||||
return postIndex;
|
||||
};
|
||||
|
||||
@ -78,6 +79,7 @@ function pageState (page, posts) {
|
||||
|
||||
function pageJSON (post) {
|
||||
return {
|
||||
id: post.id,
|
||||
url: post.url,
|
||||
fullurl: post.fullurl,
|
||||
json: '/' + post.json,
|
||||
|
@ -72,6 +72,8 @@ module.exports = exports = class Post extends Page {
|
||||
_parse (...args) {
|
||||
super._parse(...args);
|
||||
|
||||
this.id = this.meta.id;
|
||||
|
||||
if (!this.titlecard) this.titlecard = '/tweets/titlecard.png';
|
||||
|
||||
this.meta.tags = (this.meta.tags || []).reduce((result, tag) => {
|
||||
|
@ -37,6 +37,7 @@ const EXT = exports.EXT = {
|
||||
CSS: '.css',
|
||||
SCSS: '.scss',
|
||||
JS: '.js',
|
||||
JSX: '.jsx',
|
||||
};
|
||||
|
||||
const {
|
||||
@ -53,12 +54,14 @@ const {
|
||||
CSS,
|
||||
SCSS,
|
||||
JS,
|
||||
JSX,
|
||||
} = EXT;
|
||||
|
||||
const NORMALIZE_EXT = {
|
||||
[JPG]: JPEG,
|
||||
[M4V]: MP4,
|
||||
[HBS]: HTML,
|
||||
[JSX]: JS,
|
||||
};
|
||||
|
||||
const normalizedExt = exports.normalizedExt = (ext) => {
|
||||
@ -72,7 +75,7 @@ const isHandlebars = exports.isHandlebars = is(XML, HBS, HTML);
|
||||
const isMarkdown = exports.isMarkdown = is(MD);
|
||||
const isPage = exports.isPage = is(isHandlebars, isMarkdown);
|
||||
const isAsset = exports.isAsset = is(isImage, isVideo);
|
||||
const isArtifact = exports.isArtifact = is(CSS, SCSS, JS);
|
||||
const isArtifact = exports.isArtifact = is(CSS, SCSS, JS, JSX);
|
||||
exports.isCleanUrl = is(HBS, MD);
|
||||
|
||||
|
||||
@ -92,7 +95,7 @@ exports.type = dictMatch({
|
||||
[TYPE.HANDLEBARS]: isHandlebars,
|
||||
[TYPE.MARKDOWN]: isMarkdown,
|
||||
[TYPE.VIDEO]: isVideo,
|
||||
[TYPE.SCRIPT]: is(JS),
|
||||
[TYPE.SCRIPT]: is(JS, JSX),
|
||||
[TYPE.STYLE]: is(SCSS, CSS),
|
||||
}, TYPE.OTHER);
|
||||
|
||||
|
53
build/rollup.js
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
const { resolve } = require('./resolve');
|
||||
const { rollup } = require('rollup');
|
||||
const alias = require('@rollup/plugin-alias');
|
||||
const commonjs = require('@rollup/plugin-commonjs');
|
||||
const nodeResolve = require('@rollup/plugin-node-resolve');
|
||||
const replace = require('@rollup/plugin-replace');
|
||||
const babel = require('rollup-plugin-babel');
|
||||
const svg = require('rollup-plugin-react-svg');
|
||||
const { terser } = require('rollup-plugin-terser');
|
||||
|
||||
const plugins = [
|
||||
replace({ 'process.env.NODE_ENV': '"production"' }),
|
||||
alias({
|
||||
entries: [
|
||||
{ find: 'react', replacement: 'preact/compat' },
|
||||
{ find: 'react-dom', replacement: 'preact/compat' },
|
||||
{ find: 'svg', replacement: resolve('svg') },
|
||||
{ find: 'utils', replacement: resolve('build/lib/util.js') },
|
||||
],
|
||||
}),
|
||||
svg(),
|
||||
babel({
|
||||
exclude: 'node_modules/**',
|
||||
}),
|
||||
nodeResolve(),
|
||||
commonjs({
|
||||
include: 'node_modules/**',
|
||||
}),
|
||||
];
|
||||
|
||||
|
||||
module.exports = exports = async function (input, prod) {
|
||||
const inputOptions = {
|
||||
input,
|
||||
plugins,
|
||||
};
|
||||
|
||||
const outputOptions = {
|
||||
format: 'iife',
|
||||
sourcemap: 'inline',
|
||||
plugins: prod
|
||||
? [ terser({ output: { comments: false } }) ]
|
||||
: undefined,
|
||||
|
||||
};
|
||||
|
||||
const bundle = await rollup(inputOptions);
|
||||
const output = await bundle.generate(outputOptions);
|
||||
|
||||
// console.log(output);
|
||||
return output.output[0].code;
|
||||
};
|
@ -1,9 +1,10 @@
|
||||
const glob = require('./lib/glob');
|
||||
const { ROOT, readFile } = require('./resolve');
|
||||
const { ROOT, readFile, resolve } = require('./resolve');
|
||||
const actions = require('./actions');
|
||||
const File = require('./file');
|
||||
const Promise = require('bluebird');
|
||||
const { minify } = require('terser');
|
||||
const rollup = require('./rollup');
|
||||
|
||||
module.exports = exports = async function scripts (prod) {
|
||||
const globalFiles = await glob('js/_*.js', { cwd: ROOT, nodir: true });
|
||||
@ -18,10 +19,12 @@ module.exports = exports = async function scripts (prod) {
|
||||
const globalScript = new ClientScript('js/global.js');
|
||||
await globalScript.concat(globalFiles, prod);
|
||||
|
||||
const files = await Promise.map(glob('js/*.js', { cwd: ROOT, nodir: true }), async (filepath) => {
|
||||
const files = await Promise.map(glob('js/*.{js,jsx}', { cwd: ROOT, nodir: true }), async (filepath) => {
|
||||
const f = new ClientScript(filepath);
|
||||
if (f.preprocessed) return false;
|
||||
if (f.globalScript) return false;
|
||||
|
||||
await f.load(prod);
|
||||
|
||||
return f;
|
||||
}).filter(Boolean);
|
||||
|
||||
@ -35,12 +38,35 @@ module.exports = exports = async function scripts (prod) {
|
||||
|
||||
class ClientScript extends File {
|
||||
|
||||
_basename (file) {
|
||||
super._basename(file);
|
||||
|
||||
this.globalScript = false;
|
||||
if (file.name[0] === '_') {
|
||||
this.globalScript = true;
|
||||
file.name = file.name.slice(1);
|
||||
file.base = file.base.slice(1);
|
||||
}
|
||||
|
||||
this.rollup = false;
|
||||
if (file.name[0] === '$') {
|
||||
this.rollup = true;
|
||||
file.name = file.name.slice(1);
|
||||
file.base = file.base.slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
_dir (dir) {
|
||||
dir = dir.split('/');
|
||||
return dir;
|
||||
}
|
||||
|
||||
async load (prod) {
|
||||
if (this.rollup) {
|
||||
this.content = await rollup(resolve(this.input), prod);
|
||||
return;
|
||||
}
|
||||
|
||||
let contents = (await readFile(this.input).catch(() => '')).toString('utf8');
|
||||
if (prod) {
|
||||
const { code, error } = minify(contents);
|
||||
|
@ -51,7 +51,7 @@ function watcher () {
|
||||
], scss);
|
||||
|
||||
watch([
|
||||
'js/*.js',
|
||||
'js/*.{js,jsx}',
|
||||
], scripts);
|
||||
|
||||
watch([
|
||||
|
132
js/$tweets.jsx
Normal file
@ -0,0 +1,132 @@
|
||||
/** @jsx h */
|
||||
|
||||
import { h, render, Component, Fragment } from 'preact';
|
||||
import map from 'lodash/map';
|
||||
// import memoize from 'lodash/memoize';
|
||||
import { format } from 'date-fns';
|
||||
import Sync from 'svg/sync-alt.svg';
|
||||
import Link from 'svg/link.svg';
|
||||
|
||||
// const If = ({t,children}) => (!!t && <Fragment>{children}</Fragment>)
|
||||
|
||||
const Raw = ({ html }) => <div dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
|
||||
const Post = ({ post }) => (
|
||||
<article>
|
||||
<div class="post-head">
|
||||
<div class="post-tags">
|
||||
{map(post.tags, (v, k) => <a href={'/tweets/#tag=' + k} class="post-link tag">{v}</a>)}
|
||||
{map(post.author, (v) => <a href={'/tweets/#author=' + v} class="post-link author">{v}</a>)}
|
||||
</div>
|
||||
<a href={post.url} class="post-link" title={format(new Date(post.date), 'MMMM do, yyyy')}><span class="svg-icon"><Link /></span> Permalink</a>
|
||||
</div>
|
||||
<div class="post-content">{post.content ? <Raw html={post.content} /> : <div class="loading"><Sync /></div>}</div>
|
||||
</article>
|
||||
);
|
||||
|
||||
class App extends Component {
|
||||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
const index = this.props.index;
|
||||
const hash = window.location.hash.slice(1);
|
||||
this.state = {
|
||||
hash,
|
||||
loading: false,
|
||||
posts: Object.fromEntries(index.posts.map((post) => [ post.id, post ])),
|
||||
tags: index.tags,
|
||||
authors: index.authors,
|
||||
latest: index.latest,
|
||||
};
|
||||
|
||||
this.loading = new Map();
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.hashedPosts = this.hashedPosts.bind(this);
|
||||
this.ensurePost = this.ensurePost.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('hashchange', this.onChange);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('hashchange', this.onChange);
|
||||
}
|
||||
|
||||
onChange () {
|
||||
this.setState({
|
||||
hash: window.location.hash.slice(1),
|
||||
prevHash: this.state.hash,
|
||||
});
|
||||
}
|
||||
|
||||
parseHash () {
|
||||
return this.state.hash && String(this.state.hash).split('=').filter(Boolean) || [];
|
||||
}
|
||||
|
||||
hashedPosts (target, value) {
|
||||
const posts = Object.values(this.state.posts);
|
||||
if (!target && !value) return [ this.state.latest ];
|
||||
return posts.filter((post) => {
|
||||
// console.log({ post, target, value })
|
||||
if (target === 'tag') return !!post.tags[value];
|
||||
if (target === 'author') return post.author.includes(value);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
ensurePost ({ id, json }) {
|
||||
if (this.loading.has(id)) return this.loading.get(id);
|
||||
const p = fetch(json)
|
||||
.then((res) => res.json())
|
||||
.then((post) => {
|
||||
this.setState({
|
||||
posts: { ...this.state.posts, [post.id]: post },
|
||||
});
|
||||
})
|
||||
.catch(console.error); // eslint-disable-line no-console
|
||||
|
||||
this.loading.set(id, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
render () {
|
||||
const [ target, value ] = this.parseHash();
|
||||
const posts = this.hashedPosts(target, value);
|
||||
|
||||
if (this.state.loading) {
|
||||
return <div class="loading"><Sync /></div>;
|
||||
}
|
||||
|
||||
posts.forEach(this.ensurePost);
|
||||
|
||||
let caption = null;
|
||||
if (target === 'tag') caption = <h4>Threads about {this.state.tags[value] || value}</h4>;
|
||||
if (target === 'author') caption = <h4>Tweets by {value}</h4>;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{caption}
|
||||
{map(posts, (post, i) =>
|
||||
<Post post={post} key={i} />,
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function run () {
|
||||
const index = await fetch('/tweets/index.json').then((res) => res.json());
|
||||
|
||||
|
||||
const target = document.querySelector('.post-index section');
|
||||
while (target.firstChild) {
|
||||
target.removeChild(target.firstChild);
|
||||
}
|
||||
render(<App index={index} />, target);
|
||||
}
|
||||
|
||||
run().catch(console.error); // eslint-disable-line
|
12
js/.eslintrc
@ -1,12 +0,0 @@
|
||||
{
|
||||
"extends": "twipped/browser",
|
||||
"env": {"es6": true, "jquery": true},
|
||||
"rules": {
|
||||
'indent': [ 2, 2, {
|
||||
'MemberExpression': 1,
|
||||
} ],
|
||||
'prefer-arrow-callback': 0,
|
||||
'object-shorthand': 0,
|
||||
'node/no-unsupported-features/node-builtins': 0
|
||||
}
|
||||
}
|
27
js/.eslintrc.js
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
module.exports = exports = {
|
||||
extends: "twipped/browser",
|
||||
env: {es6: true, jquery: true},
|
||||
rules: {
|
||||
'indent': [ 2, 2, {
|
||||
'MemberExpression': 1,
|
||||
} ],
|
||||
'prefer-arrow-callback': 0,
|
||||
'object-shorthand': 0,
|
||||
'node/no-unsupported-features/node-builtins': 0
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: '$*.jsx',
|
||||
extends: "twipped/react",
|
||||
rules: {
|
||||
'react/jsx-indent': [2, 2, {checkAttributes: true}],
|
||||
"react/no-unknown-property": [2, { ignore: ['class'] }],
|
||||
'node/no-unpublished-import': 0,
|
||||
"node/no-missing-import": ["error", {
|
||||
"allowModules": ["svg", 'react']
|
||||
}]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
1815
package-lock.json
generated
21
package.json
@ -25,8 +25,17 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.8.7",
|
||||
"@babel/plugin-proposal-class-properties": "~7.8.3",
|
||||
"@babel/preset-env": "~7.8.7",
|
||||
"@rollup/plugin-alias": "~3.0.1",
|
||||
"@rollup/plugin-commonjs": "~11.0.2",
|
||||
"@rollup/plugin-node-resolve": "~7.1.1",
|
||||
"@rollup/plugin-replace": "~2.3.1",
|
||||
"autoprefixer": "~9.7.4",
|
||||
"aws-sdk": "~2.624.0",
|
||||
"babel-eslint": "~10.1.0",
|
||||
"babel-preset-preact": "~2.0.0",
|
||||
"backbone": "~1.4.0",
|
||||
"bluebird": "~3.7.2",
|
||||
"bootstrap": "~4.4.1",
|
||||
@ -37,6 +46,7 @@
|
||||
"eslint-config-twipped": "~3.4.0",
|
||||
"eslint-plugin-node": "~11.0.0",
|
||||
"eslint-plugin-promise": "~4.2.1",
|
||||
"eslint-plugin-react": "~7.19.0",
|
||||
"express": "~4.17.1",
|
||||
"fancy-log": "~1.3.3",
|
||||
"forever": "~2.0.0",
|
||||
@ -67,14 +77,13 @@
|
||||
"png-to-ico": "~2.0.6",
|
||||
"popper.js": "~1.16.0",
|
||||
"postcss": "~7.0.27",
|
||||
"preact": "~10.3.3",
|
||||
"rev-hash": "~3.0.0",
|
||||
"rev-path": "~2.0.0",
|
||||
"rollup": "~1.31.1",
|
||||
"rollup-plugin-alias": "~2.2.0",
|
||||
"rollup-plugin-commonjs": "~10.1.0",
|
||||
"rollup-plugin-json": "~4.0.0",
|
||||
"rollup-plugin-node-resolve": "~5.2.0",
|
||||
"rollup-plugin-string": "~3.0.0",
|
||||
"rollup": "~2.0.2",
|
||||
"rollup-plugin-babel": "~4.4.0",
|
||||
"rollup-plugin-react-svg": "~3.0.3",
|
||||
"rollup-plugin-terser": "~5.2.0",
|
||||
"rss": "~1.2.2",
|
||||
"serve-index": "~1.9.1",
|
||||
"slugify": "~1.3.6",
|
||||
|
@ -5,7 +5,8 @@ title: Tweets by @Emmy_Zje
|
||||
description: 'On the topic of shame and guilt for being trans.'
|
||||
author: Emmy_Zje
|
||||
tags:
|
||||
- Transgender
|
||||
- Shame
|
||||
- Euphoria
|
||||
tweets:
|
||||
- https://twitter.com/Emmy_Zje/status/1200891565478236161
|
||||
- https://twitter.com/Emmy_Zje/status/1201138482569195526
|
||||
|
@ -1,43 +1,44 @@
|
||||
<div class="pager {{className}}">
|
||||
<div class="back">
|
||||
{{#is meta.url '/gdb/what-is-gender' }}<a href="/gdb/" class="btn btn-primary left">{{icon 'chevron-left'}} Introduction</a>{{/is}}
|
||||
{{#is meta.url '/gdb/history' }}<a href="/gdb/what-is-gender" class="btn btn-primary left">{{icon 'chevron-left'}} What Is Gender?</a>{{/is}}
|
||||
{{#is meta.url '/gdb/euphoria' }}<a href="/gdb/history" class="btn btn-primary left">{{icon 'chevron-left'}} The History of Gender Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/physical-dysphoria' }}<a href="/gdb/euphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Gender Euphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/biochemical-dysphoria' }}<a href="/gdb/physical-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Physical Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/social-dysphoria' }}<a href="/gdb/biochemical-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Biochemical Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/societal-dysphoria' }}<a href="/gdb/social-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Social Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/sexual-dysphoria' }}<a href="/gdb/societal-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Societal Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/presentational-dysphoria'}}<a href="/gdb/sexual-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Sexual Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/historical-dysphoria' }}<a href="/gdb/presentational-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Presentational Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/managed-dysphoria' }}<a href="/gdb/historical-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Historical Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/impostor-syndrome' }}<a href="/gdb/managed-dysphoria" class="btn btn-primary left">{{icon 'chevron-left'}} Managed Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/diagnoses' }}<a href="/gdb/impostor-syndrome" class="btn btn-primary left">{{icon 'chevron-left'}} Impostor Syndrome</a>{{/is}}
|
||||
{{#is meta.url '/gdb/treatment' }}<a href="/gdb/diagnoses" class="btn btn-primary left">{{icon 'chevron-left'}} Clinical Diagnoses</a>{{/is}}
|
||||
{{#is meta.url '/gdb/causes' }}<a href="/gdb/treatment" class="btn btn-primary left">{{icon 'chevron-left'}} Treating Gender Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/chromosomes' }}<a href="/gdb/causes" class="btn btn-primary left">{{icon 'chevron-left'}} Causes of Gender Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/conclusion' }}<a href="/gdb/chromosomes" class="btn btn-primary left">{{icon 'chevron-left'}} Disorders of Sexual Development</a>{{/is}}
|
||||
<div class="prev">
|
||||
{{#is meta.url '/gdb/what-is-gender' }}<a href="/gdb/" class="btn btn-primary left">{{icon 'angle-left'}} Introduction</a>{{/is}}
|
||||
{{#is meta.url '/gdb/history' }}<a href="/gdb/what-is-gender" class="btn btn-primary left">{{icon 'angle-left'}} What Is Gender?</a>{{/is}}
|
||||
{{#is meta.url '/gdb/euphoria' }}<a href="/gdb/history" class="btn btn-primary left">{{icon 'angle-left'}} The History of Gender Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/physical-dysphoria' }}<a href="/gdb/euphoria" class="btn btn-primary left">{{icon 'angle-left'}} Gender Euphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/biochemical-dysphoria' }}<a href="/gdb/physical-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Physical Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/social-dysphoria' }}<a href="/gdb/biochemical-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Biochemical Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/societal-dysphoria' }}<a href="/gdb/social-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Social Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/sexual-dysphoria' }}<a href="/gdb/societal-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Societal Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/presentational-dysphoria'}}<a href="/gdb/sexual-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Sexual Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/historical-dysphoria' }}<a href="/gdb/presentational-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Presentational Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/managed-dysphoria' }}<a href="/gdb/historical-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Historical Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/impostor-syndrome' }}<a href="/gdb/managed-dysphoria" class="btn btn-primary left">{{icon 'angle-left'}} Managed Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/diagnoses' }}<a href="/gdb/impostor-syndrome" class="btn btn-primary left">{{icon 'angle-left'}} Impostor Syndrome</a>{{/is}}
|
||||
{{#is meta.url '/gdb/treatment' }}<a href="/gdb/diagnoses" class="btn btn-primary left">{{icon 'angle-left'}} Clinical Diagnoses</a>{{/is}}
|
||||
{{#is meta.url '/gdb/causes' }}<a href="/gdb/treatment" class="btn btn-primary left">{{icon 'angle-left'}} Treating Gender Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/chromosomes' }}<a href="/gdb/causes" class="btn btn-primary left">{{icon 'angle-left'}} Causes of Gender Dysphoria</a>{{/is}}
|
||||
{{#is meta.url '/gdb/conclusion' }}<a href="/gdb/chromosomes" class="btn btn-primary left">{{icon 'angle-left'}} Disorders of Sexual Development</a>{{/is}}
|
||||
</div>
|
||||
|
||||
<div class="forward">
|
||||
{{#is meta.url '/' }}<a href="/gdb/what-is-gender" class="btn btn-primary right">Continue Reading {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb' }}<a href="/gdb/what-is-gender" class="btn btn-primary right">What is Gender? {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/what-is-gender' }}<a href="/gdb/history" class="btn btn-primary right">The History of Gender Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/history' }}<a href="/gdb/euphoria" class="btn btn-primary right">Gender Euphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/euphoria' }}<a href="/gdb/physical-dysphoria" class="btn btn-primary right">Physical Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/physical-dysphoria' }}<a href="/gdb/biochemical-dysphoria" class="btn btn-primary right">Biochemical Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/biochemical-dysphoria' }}<a href="/gdb/social-dysphoria" class="btn btn-primary right">Social Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/social-dysphoria' }}<a href="/gdb/societal-dysphoria" class="btn btn-primary right">Societal Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/societal-dysphoria' }}<a href="/gdb/sexual-dysphoria" class="btn btn-primary right">Sexual Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/sexual-dysphoria' }}<a href="/gdb/presentational-dysphoria" class="btn btn-primary right">Presentational Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/presentational-dysphoria'}}<a href="/gdb/historical-dysphoria" class="btn btn-primary right">Historical Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/historical-dysphoria' }}<a href="/gdb/managed-dysphoria" class="btn btn-primary right">Managed Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/managed-dysphoria' }}<a href="/gdb/impostor-syndrome" class="btn btn-primary right">Impostor Syndrome {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/impostor-syndrome' }}<a href="/gdb/diagnoses" class="btn btn-primary right">Clinical Diagnoses {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/diagnoses' }}<a href="/gdb/treatment" class="btn btn-primary right">Treating Gender Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/treatment' }}<a href="/gdb/causes" class="btn btn-primary right">Causes of Gender Dysphoria {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/causes' }}<a href="/gdb/chromosomes" class="btn btn-primary right">But... but... the chromosomes! {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/chromosomes' }}<a href="/gdb/conclusion" class="btn btn-primary right">Conclusion {{icon 'chevron-right'}}</a>{{/is}}
|
||||
{{!-- <div class="first"></div>
|
||||
<div class="last"></div> --}}
|
||||
<div class="next">
|
||||
{{#is meta.url '/' }}<a href="/gdb/what-is-gender" class="btn btn-primary right">Continue Reading {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb' }}<a href="/gdb/what-is-gender" class="btn btn-primary right">What is Gender? {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/what-is-gender' }}<a href="/gdb/history" class="btn btn-primary right">The History of Gender Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/history' }}<a href="/gdb/euphoria" class="btn btn-primary right">Gender Euphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/euphoria' }}<a href="/gdb/physical-dysphoria" class="btn btn-primary right">Physical Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/physical-dysphoria' }}<a href="/gdb/biochemical-dysphoria" class="btn btn-primary right">Biochemical Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/biochemical-dysphoria' }}<a href="/gdb/social-dysphoria" class="btn btn-primary right">Social Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/social-dysphoria' }}<a href="/gdb/societal-dysphoria" class="btn btn-primary right">Societal Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/societal-dysphoria' }}<a href="/gdb/sexual-dysphoria" class="btn btn-primary right">Sexual Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/sexual-dysphoria' }}<a href="/gdb/presentational-dysphoria" class="btn btn-primary right">Presentational Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/presentational-dysphoria'}}<a href="/gdb/historical-dysphoria" class="btn btn-primary right">Historical Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/historical-dysphoria' }}<a href="/gdb/managed-dysphoria" class="btn btn-primary right">Managed Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/managed-dysphoria' }}<a href="/gdb/impostor-syndrome" class="btn btn-primary right">Impostor Syndrome {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/impostor-syndrome' }}<a href="/gdb/diagnoses" class="btn btn-primary right">Clinical Diagnoses {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/diagnoses' }}<a href="/gdb/treatment" class="btn btn-primary right">Treating Gender Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/treatment' }}<a href="/gdb/causes" class="btn btn-primary right">Causes of Gender Dysphoria {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/causes' }}<a href="/gdb/chromosomes" class="btn btn-primary right">But... but... the chromosomes! {{icon 'angle-right'}}</a>{{/is}}
|
||||
{{#is meta.url '/gdb/chromosomes' }}<a href="/gdb/conclusion" class="btn btn-primary right">Conclusion {{icon 'angle-right'}}</a>{{/is}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -18,30 +18,54 @@ description: "A collection of the best twitter threads on transgender and gender
|
||||
<link rel="canonical" href="{{#if canonical}}{{canonical}}{{else}}https://{{page.domain}}{{url}}{{/if}}">
|
||||
{{/content}}
|
||||
|
||||
{{#content "bodyClass"}}page ttt{{/content}}
|
||||
{{#content "bodyClass"}}post{{/content}}
|
||||
|
||||
{{#content "body"}}
|
||||
|
||||
<!-- <h1>Trans Twitter Topics</h1> -->
|
||||
{{#content "post-header"}}
|
||||
<div class="disclaimer"><div class="container" style="text-align: center">
|
||||
<h1>Trans Twitter Topics</h1>
|
||||
<strong>A collection of the best Twitter threads on transgender and gender dysphoria topics.</strong>
|
||||
<p>Have a thread that you think belongs here? <a href="https://twitter.com/TwippingVanilla">Send it my way</a>.</p>
|
||||
</div></div>
|
||||
{{/content}}
|
||||
|
||||
<section class="ttt-grid">
|
||||
{{#append "postscripts"}}
|
||||
<script type="text/javascript" src="{{rev '/js/tweets.js'}}"></script>
|
||||
{{/append}}
|
||||
|
||||
{{#each posts}}{{#unless draft}}
|
||||
<div class="ttt-post {{#if flags.bordered}} bordered{{/if}}">
|
||||
<div class="ttt-head">
|
||||
<div class="ttt-tags">{{#each meta.tags}}<a href="#{{@key}}" class="ttt-tag">{{this}}</a>{{/each}}</div>
|
||||
<a href="{{this.url}}" class="ttt-link" title="{{date this.dateCreated 'MMMM do, yyyy'}}">{{icon 'link'}} Permalink</a>
|
||||
{{#content "body"}}
|
||||
|
||||
<div class="post-index">
|
||||
<section>
|
||||
{{#with posts.latest}}
|
||||
<article>
|
||||
<div class="post-head">
|
||||
<div class="post-tags">
|
||||
{{#each meta.tags}}<a href="#tag={{@key}}" class="post-link tag">{{this}}</a>{{/each}}
|
||||
{{#each meta.author}}<a href="#author={{this}}" class="post-link author">{{this}}</a>{{/each}}
|
||||
</div>
|
||||
<div class="ttt-wrap">{{{this.content}}}</div>
|
||||
<a href="{{this.url}}" class="post-link" title="{{date this.date 'MMMM do, yyyy'}}">{{icon 'link'}} Permalink</a>
|
||||
</div>
|
||||
{{/unless}}{{/each}}
|
||||
|
||||
<div class="post-content">{{{this.content}}}</div>
|
||||
<div class="pager">
|
||||
<div class="prev">{{#if siblings.prev}}<a href="{{siblings.prev}}" class="btn btn-primary left">{{icon 'angle-left'}} Back</a>{{/if}}</div>
|
||||
<div class="first">{{#if siblings.first}}<a href="{{siblings.first}}" class="btn btn-primary left">{{icon 'angle-double-left'}} Newest</a>{{/if}}</div>
|
||||
<div class="last">{{#if siblings.last}}<a href="{{siblings.last}}" class="btn btn-primary right">Oldest {{icon 'angle-double-right'}}</a>{{/if}}</div>
|
||||
<div class="next">{{#if siblings.next}}<a href="{{siblings.next}}" class="btn btn-primary right">Next {{icon 'angle-right'}}</a>{{/if}}</div>
|
||||
</div>
|
||||
</article>
|
||||
{{/with}}
|
||||
</section>
|
||||
|
||||
<aside class="tags">
|
||||
<h4>Topics</h4>
|
||||
<div class="post-tags">{{#each posts.tags}}<a href="#tag={{@key}}" class="post-link tag">{{this}}</a>{{/each}}</div>
|
||||
</aside>
|
||||
<aside class="authors">
|
||||
<h4>Authors</h4>
|
||||
<div class="post-tags">{{#each posts.authors}}<a href="#author={{this}}" class="post-link author">{{this}}</a>{{/each}}</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
{{/content}}
|
||||
|
||||
{{/extend}}
|
||||
|
139
scss/_page.scss
@ -1,5 +1,5 @@
|
||||
|
||||
body.page {
|
||||
body.page, body.post {
|
||||
@media (max-width: 500px) {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
@ -123,33 +123,49 @@ body.gdb {
|
||||
}
|
||||
}
|
||||
|
||||
body.ttt {
|
||||
body.post {
|
||||
$borderColor: #e1e8ed;
|
||||
$borderHover: #ccd6dd;
|
||||
$textLight: #697882;
|
||||
$textDark: #1c2022;
|
||||
$textHover: #3b94d9;
|
||||
$borderRadius: .35em;
|
||||
$articleWidth: 660px;
|
||||
$sidebarWidth: 220px;
|
||||
|
||||
|
||||
.ttt-grid {
|
||||
padding: 1em;
|
||||
max-width: 660px;
|
||||
margin: 0 auto;
|
||||
.disclaimer {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.ttt-post {
|
||||
.loading {
|
||||
min-height: 400px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// background: red;
|
||||
color: $gray-400;
|
||||
|
||||
svg {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
animation: spinner-border 1s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
article {
|
||||
max-width: $articleWidth;
|
||||
margin: 0 auto 1em;
|
||||
|
||||
background: $gutter-bg;
|
||||
padding: 0.6em 1em;
|
||||
margin: 0 0 2em 0;
|
||||
border-radius: $borderRadius;
|
||||
box-shadow: inset 0 1px 2px rgba($gray-600, 0.2);
|
||||
|
||||
.ttt-head {
|
||||
.post-head {
|
||||
display: flex;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
.ttt-tags {
|
||||
.post-tags {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@ -163,31 +179,118 @@ body.ttt {
|
||||
box-shadow: 0 1px 2px rgba($gray-600, 0.5);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tweet:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ttt-tag {
|
||||
margin: 0.25em 0.5em 0.25em 0;
|
||||
}
|
||||
|
||||
.ttt-link {
|
||||
.post-link {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
|
||||
.svg-icon {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
margin-right: 0.4em;
|
||||
}
|
||||
}
|
||||
|
||||
.ttt-tag, .ttt-link {
|
||||
background: white;
|
||||
color: $gray-700;
|
||||
border: 1px solid $borderColor;
|
||||
font-size: 10px;
|
||||
padding: 2px 5px;
|
||||
border-radius: $borderRadius;
|
||||
box-shadow: 0 1px 1px rgba($gray-600, 0.2);
|
||||
|
||||
margin: 0.25em 0.5em 0.25em 0;
|
||||
}
|
||||
|
||||
.post-link.tag {
|
||||
color: $trans-pink-darkest;
|
||||
border-color: $trans-pink;
|
||||
}
|
||||
|
||||
.post-link.author {
|
||||
color: $trans-blue-dark;
|
||||
border-color: $trans-blue;
|
||||
}
|
||||
|
||||
.post-index {
|
||||
max-width: 1200px;
|
||||
display: grid;
|
||||
|
||||
section { grid-area: articles; }
|
||||
aside {
|
||||
|
||||
h4 { text-align: center; }
|
||||
|
||||
.post-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: stretch;
|
||||
|
||||
.post-link {
|
||||
flex: 1;
|
||||
flex-basis: $sidebarWidth / 2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
&.authors {
|
||||
grid-area: authors;
|
||||
}
|
||||
|
||||
&.tags {
|
||||
grid-area: tags;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $articleWidth + $sidebarWidth) {
|
||||
grid-template-columns: 100%;
|
||||
grid-row-gap: 1em;
|
||||
grid-template-areas:
|
||||
'articles'
|
||||
'tags'
|
||||
'authors'
|
||||
;
|
||||
|
||||
aside {
|
||||
max-width: $articleWidth;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $articleWidth + $sidebarWidth) {
|
||||
grid-template-columns: $articleWidth 1fr;
|
||||
grid-column-gap: 1em;
|
||||
grid-template-areas:
|
||||
'articles tags'
|
||||
'articles authors'
|
||||
;
|
||||
|
||||
aside {
|
||||
position: relative;
|
||||
.post-tags {
|
||||
display: grid;
|
||||
grid-template-columns: repeat( auto-fill, minmax( $sidebarWidth / 2 - 15, 1fr ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $sidebarWidth + $articleWidth + $sidebarWidth) {
|
||||
grid-template-columns: 1fr $articleWidth 1fr;
|
||||
grid-column-gap: 1em;
|
||||
grid-template-areas:
|
||||
'tags articles authors'
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,10 +3,8 @@
|
||||
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 5px;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1em 0;
|
||||
margin-top: -1em;
|
||||
@ -17,6 +15,7 @@
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-basis: 23%;
|
||||
}
|
||||
|
||||
.btn {
|
||||
@ -24,16 +23,20 @@
|
||||
box-shadow: 0px 1px 5px rgba(#000, 0.5);
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
// width: 100%;
|
||||
min-width: 75%;
|
||||
width: 100%;
|
||||
// min-width: 75%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.back, .back .btn {
|
||||
.btn.left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.forward, .forward .btn {
|
||||
.btn.right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
span.svg-icon {
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,14 @@ h4, h5, .h4, .h5 { font-weight: 600; }
|
||||
$trans-white: #fff;
|
||||
$trans-pink: #F7A8B8;
|
||||
$trans-blue: #55CDFC;
|
||||
$trans-pink-lightest: #fef6f7;
|
||||
$trans-pink-light: #fde6eb;
|
||||
$trans-blue-light: #b9eafe;
|
||||
$trans-blue-lightest: #f0f8ff;
|
||||
$trans-pink-dark: #ee4b6c;
|
||||
$trans-blue-dark: #0377a4;
|
||||
$trans-pink-darkest: #ea1c46;
|
||||
$trans-blue-darkest: #025372;
|
||||
$primary: #fc0a7e;
|
||||
|
||||
$header-bg-1: #E81179;
|
||||
@ -87,7 +90,7 @@ $header-full-height: 100px;
|
||||
// @import "bootstrap/scss/tooltip";
|
||||
// @import "bootstrap/scss/popover";
|
||||
// @import "bootstrap/scss/carousel";
|
||||
// @import "bootstrap/scss/spinners";
|
||||
@import "bootstrap/scss/spinners";
|
||||
@import "bootstrap/scss/utilities";
|
||||
@import "bootstrap/scss/print";
|
||||
|
||||
|
1
svg/angle-double-left.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M223.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L319.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L393.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34zm-192 34l136 136c9.4 9.4 24.6 9.4 33.9 0l22.6-22.6c9.4-9.4 9.4-24.6 0-33.9L127.9 256l96.4-96.4c9.4-9.4 9.4-24.6 0-33.9L201.7 103c-9.4-9.4-24.6-9.4-33.9 0l-136 136c-9.5 9.4-9.5 24.6-.1 34z"/></svg>
|
After Width: | Height: | Size: 477 B |
1
svg/angle-double-right.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34zm192-34l-136-136c-9.4-9.4-24.6-9.4-33.9 0l-22.6 22.6c-9.4 9.4-9.4 24.6 0 33.9l96.4 96.4-96.4 96.4c-9.4 9.4-9.4 24.6 0 33.9l22.6 22.6c9.4 9.4 24.6 9.4 33.9 0l136-136c9.4-9.2 9.4-24.4 0-33.8z"/></svg>
|
After Width: | Height: | Size: 479 B |
1
svg/angle-left.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 512"><path fill="currentColor" d="M31.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L127.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L201.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34z"/></svg>
|
After Width: | Height: | Size: 289 B |
1
svg/angle-right.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 512"><path fill="currentColor" d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z"/></svg>
|
After Width: | Height: | Size: 290 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z"/></svg>
|
Before Width: | Height: | Size: 380 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"/></svg>
|
Before Width: | Height: | Size: 339 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"/></svg>
|
Before Width: | Height: | Size: 382 B |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z"/></svg>
|
Before Width: | Height: | Size: 385 B |
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M448 48v32a16 16 0 0 1-16 16h-48v368a16 16 0 0 1-16 16h-32a16 16 0 0 1-16-16V96h-32v368a16 16 0 0 1-16 16h-32a16 16 0 0 1-16-16V352h-32a160 160 0 0 1 0-320h240a16 16 0 0 1 16 16z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M448 48v32a16 16 0 0 1-16 16h-48v368a16 16 0 0 1-16 16h-32a16 16 0 0 1-16-16V96h-32v368a16 16 0 0 1-16 16h-32a16 16 0 0 1-16-16V352h-32a160 160 0 0 1 0-320h240a16 16 0 0 1 16 16z"/></svg>
|
||||
|
Before Width: | Height: | Size: 258 B After Width: | Height: | Size: 279 B |
1
svg/sync-alt.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M370.72 133.28C339.458 104.008 298.888 87.962 255.848 88c-77.458.068-144.328 53.178-162.791 126.85-1.344 5.363-6.122 9.15-11.651 9.15H24.103c-7.498 0-13.194-6.807-11.807-14.176C33.933 94.924 134.813 8 256 8c66.448 0 126.791 26.136 171.315 68.685L463.03 40.97C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.749zM32 296h134.059c21.382 0 32.09 25.851 16.971 40.971l-41.75 41.75c31.262 29.273 71.835 45.319 114.876 45.28 77.418-.07 144.315-53.144 162.787-126.849 1.344-5.363 6.122-9.15 11.651-9.15h57.304c7.498 0 13.194 6.807 11.807 14.176C478.067 417.076 377.187 504 256 504c-66.448 0-126.791-26.136-171.315-68.685L48.97 471.03C33.851 486.149 8 475.441 8 454.059V320c0-13.255 10.745-24 24-24z"/></svg>
|
After Width: | Height: | Size: 863 B |
@ -22,7 +22,9 @@
|
||||
|
||||
{{#content "body"}}
|
||||
<article class="markup">
|
||||
<div class="post-content">{{{contents}}}</div>
|
||||
<div class="post-content">
|
||||
{{{contents}}}
|
||||
</div>
|
||||
</article>
|
||||
{{/content}}
|
||||
|
||||
|
47
templates/post.hbs
Normal file
@ -0,0 +1,47 @@
|
||||
{{#extend "layout"}}
|
||||
|
||||
{{#content "meta"}}
|
||||
<meta property="og:title" content="{{meta.title}}{{#if meta.subtitle}}, {{meta.subtitle}}{{/if}}">
|
||||
<meta property="og:description" content="{{meta.description}}">
|
||||
{{#if titlecard}}<meta property="og:image" content="https://{{page.domain}}{{rev titlecard}}">{{/if}}
|
||||
<meta property="og:url" content="https://{{page.domain}}{{url}}">
|
||||
<meta name="twitter:title" content="{{meta.title}}{{#if meta.subtitle}}, {{meta.subtitle}}{{/if}}">
|
||||
<meta name="twitter:description" content="{{meta.description}}">
|
||||
{{#if titlecard}}
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:image" content="https://{{page.domain}}{{rev titlecard}}">
|
||||
{{/if}}
|
||||
<link rel="canonical" href="{{#if canonical}}{{canonical}}{{else}}https://{{page.domain}}{{url}}{{/if}}">
|
||||
{{/content}}
|
||||
|
||||
{{#append 'post-header'}}
|
||||
{{#if meta.preBody}}{{import meta.preBody}}{{/if}}
|
||||
{{/append}}
|
||||
|
||||
{{#content "bodyClass"}}{{#each classes}}{{this}} {{/each}}post{{/content}}
|
||||
|
||||
{{#content "body"}}
|
||||
<div class="disclaimer"><div class="container" style="text-align: center">
|
||||
<h1>Trans Twitter Topics</h1>
|
||||
<strong>A collection of the best Twitter threads on transgender and gender dysphoria topics.</strong>
|
||||
<p>Have a thread that you think belongs here? <a href="https://twitter.com/TwippingVanilla">Send it my way</a>.</p>
|
||||
</div></div>
|
||||
<article>
|
||||
<div class="post-head">
|
||||
<div class="post-tags">
|
||||
{{#each meta.tags}}<a href="/tweets/#tag={{@key}}" class="post-link tag">{{this}}</a>{{/each}}
|
||||
{{#each meta.author}}<a href="/tweets/#author={{this}}" class="post-link author">{{this}}</a>{{/each}}
|
||||
</div>
|
||||
<a href="{{url}}" class="post-link" title="{{date dateCreated 'MMMM do, yyyy'}}">{{icon 'link'}} Permalink</a>
|
||||
</div>
|
||||
<div class="post-content markup">{{{contents}}}</div>
|
||||
<div class="pager">
|
||||
<div class="prev">{{#if siblings.prev}}<a href="{{siblings.prev}}" class="btn btn-primary left">{{icon 'angle-left'}} Back</a>{{/if}}</div>
|
||||
<div class="first">{{#if siblings.first}}<a href="{{siblings.first}}" class="btn btn-primary left">{{icon 'angle-double-left'}} Newest</a>{{/if}}</div>
|
||||
<div class="last">{{#if siblings.last}}<a href="{{siblings.last}}" class="btn btn-primary right">Oldest {{icon 'angle-double-right'}}</a>{{/if}}</div>
|
||||
<div class="next">{{#if siblings.next}}<a href="{{siblings.next}}" class="btn btn-primary right">Next {{icon 'angle-right'}}</a>{{/if}}</div>
|
||||
</div>
|
||||
</article>
|
||||
{{/content}}
|
||||
|
||||
{{/extend}}
|