feat(web/converse): Import repository

Imports the converse forum software I wrote a few years ago. I want to
clean this up a bit and try using Hotwire with it.

Note: The original repository was AGPL-3.0 licensed. I'm the copyright
holder and have relicensed it to GPL-3.0 in the commit that is being
merged.

Imported from: https://github.com/tazjin/converse

git-subtree-dir: web/converse
git-subtree-mainline: 386afdc794
git-subtree-split: 09168021e7
Change-Id: Ia8b587db5174ef5b3c52910d3d027199150c58e0
This commit is contained in:
Vincent Ambo 2021-04-05 16:55:10 +02:00
commit 8142149e28
54 changed files with 11309 additions and 0 deletions

View file

@ -0,0 +1,80 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Converse: Index</title>
<!-- TODO -->
<meta http-equiv="Content-Security-Policy" content="script-src https://code.getmdl.io 'self';">
<!-- <link rel="shortcut icon" href="images/favicon.png"> -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.blue_grey-orange.min.css" />
<link rel="stylesheet" href="/static/styles.css">
</head>
<body class="converse mdl-base mdl-color-text--grey-700 mdl-color--grey-100">
<div class="mdl-layout mdl-layout--fixed-header mdl-js-layout mdl-color--grey-100">
<header class="mdl-layout__header mdl-layout__header--scroll mdl-color--primary-dark">
<div class="mdl-layout__header-row">
<a href="/" class="mdl-layout-title mdl-color-text--blue-grey-50 cvs-title">Converse</a>
<div class="mdl-layout-spacer"></div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label mdl-color-text--blue-grey-50 search-field">
<form method="get" action="/search">
<input class="mdl-textfield__input" type="search" id="search-query" aria-label="Search" name="query">
<label class="mdl-textfield__label mdl-color-text--blue-grey-100" for="search-query">Search query...</label>
<input type="submit" hidden />
</form>
</div>
&nbsp;
<a href="/thread/new">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--accent mdl-js-ripple-effect">
New Thread
</button>
</a>
</div>
</header>
<main class="mdl-layout__content">
<section class="section--center mdl-grid mdl-grid--no-spacing mdl-shadow--2dp">
<div class="mdl-card mdl-cell mdl-cell--12-col">
<div class="mdl-card__supporting-text mdl-grid">
<h4 class="mdl-cell mdl-cell--12-col">Latest threads:</h4>
<ul class="mdl-list">
{% for thread in threads %}
<li class="mdl-list__item thread-list-item mdl-list__item--three-line">
<a class="thread-link mdl-color-text--grey-800" href="/thread/{{ thread.id }}">
<span class="mdl-list__item-primary-content {% if loop.index < threads.len() %}thread-divider{% endif %}">
<button class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored mdl-list__item-icon">
<i class="material-icons">
{% if thread.sticky %}
announcement
{% else if thread.closed %}
lock
{% else %}
library_books
{% endif %}
</i>
</button>
<span class="thread-title">{{ thread.title }}<span class="thread-author"> by {{ thread.author_name }}</span></span>
<span class="mdl-list__item-text-body">
Last reply by {{ thread.post_author }} on {{ thread.posted }}.
</span>
</span>
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</section>
</main>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer--right-section">
<p>Powered by <a href="https://github.com/tazjin/converse">Converse</a></p>
</div>
</footer>
</div>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
</body>
</html>

View file

@ -0,0 +1,124 @@
{#
This template is shared by the new thread, reply and post-editing pages.
The main display differences between the different editing styles are the
headline of the page ("Submit new thread", "Reply to thread", "Edit post")
and whether or not the subject line field is displayed in the input form.
Every one of these pages can have a variable length list of alerts submitted
into the template, which will be rendered as Boostrap alert boxes above the
user input form.
#}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Converse: Post</title>
<meta http-equiv="Content-Security-Policy" content="script-src https://code.getmdl.io 'self';">
<!-- <link rel="shortcut icon" href="images/favicon.png"> -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.blue_grey-orange.min.css" />
<link rel="stylesheet" href="/static/styles.css">
</head>
<body class="converse mdl-base mdl-color-text--grey-700 mdl-color--grey-100">
<div class="mdl-layout mdl-layout--fixed-header mdl-js-layout mdl-color--grey-100">
<header class="mdl-layout__header mdl-layout__header--scroll mdl-color--primary-dark">
<div class="mdl-layout__header-row">
<a href="/" class="mdl-layout-title mdl-color-text--blue-grey-50 cvs-title">
{% match mode %}
{% when EditingMode::NewThread %}
Converse: Submit new thread
{% when EditingMode::PostReply %}
Converse: Reply to thread
{% when EditingMode::EditPost %}
Converse: Edit post
{% endmatch %}
</a>
<div class="mdl-layout-spacer"></div>
<a href="/">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--accent mdl-js-ripple-effect">
Back to index
</button>
</a>
</div>
</header>
<main class="mdl-layout__content mdl-grid">
<div class="mdl-card mdl-shadow--2dp mdl-cell--8-col">
{% match mode %}
{% when EditingMode::NewThread %}
<form action="/thread/submit" method="post">
{% when EditingMode::PostReply %}
<form action="/thread/reply" method="post">
{% when EditingMode::EditPost %}
<form action="/post/edit" method="post">
{% endmatch %}
{% match mode %}
{% when EditingMode::PostReply %}
<input type="hidden" id="thread_id" name="thread_id" value="{{ id.unwrap() }}">
{% when EditingMode::EditPost %}
<input type="hidden" id="thread_id" name="post_id" value="{{ id.unwrap() }}">
{% else %}
{# no post ID when making a new thread #}
{% endmatch %}
<div class="mdl-card__supporting-text">
{% for alert in alerts %}
<span class="mdl-chip mdl-color--red-200">
<span class="mdl-chip__text">{{ alert }}&nbsp;</span>
</span>
{% endfor %}
{% if mode == EditingMode::NewThread %}
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label mdl-cell--12-col">
<input class="mdl-textfield__input" type="text" id="title" name="title" aria-label="thread title" required {% match title %}{% when Some with (title_text) %}value="{{ title_text }}"{% else %}{# Nothing! #}{% endmatch %}>
<label class="mdl-textfield__label" for="title">Thread title</label>
</div>
{% endif %}
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label mdl-cell--12-col">
<textarea class="mdl-textfield__input" type="text" rows="25" id="post" name="post" aria-label="post content" required>
{%- match post -%}
{%- when Some with (post_text) -%}
{{- post_text -}}
{%- else -%}
{# Nothing! #}
{%- endmatch -%}
</textarea>
<label class="mdl-textfield__label" for="body">Content ...</label>
</div>
</div>
<div class="mdl-card__actions">
<input class="mdl-button mdl-button--raised mdl-button--colored mdl-js-button mdl-js-ripple-effect" type="submit" value="Submit!">
</div>
</form>
</div>
<div class="mdl-card mdl-shadow--2dp mdl-cell--4-col">
<div class="mdl-card__title mdl-card--border">
Quick Markdown primer:
</div>
<div class="mdl-card__supporting-text">
<p>
Remember that you can use <a href="https://daringfireball.net/projects/markdown/basics"><strong>Markdown</strong></a> when
writing your posts:
</p>
<p><i>*italic text*</i></p>
<p><strong>**bold text**</strong></p>
<p><s>~strikethrough text~</s></p>
<p><code>[link text](https://some.link.com/)</code></p>
<p><code>![image text](https://foo.com/thing.jpg)</code></p>
<p>Use <code>*</code> or <code>-</code> to enumerate lists.</p>
<p>See Markdown documentation for more information!</p>
</div>
</div>
</main>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer--right-section">
<p>Powered by <a href="https://github.com/tazjin/converse">Converse</a></p>
</div>
</footer>
</div>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
</body>
</html>

View file

@ -0,0 +1,67 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Converse: Search results</title>
<!-- TODO -->
<meta http-equiv="Content-Security-Policy" content="script-src https://code.getmdl.io 'self';">
<!-- <link rel="shortcut icon" href="images/favicon.png"> -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.blue_grey-orange.min.css" />
<link rel="stylesheet" href="/static/styles.css">
</head>
<body class="converse mdl-base mdl-color-text--grey-700 mdl-color--grey-100">
<div class="mdl-layout mdl-layout--fixed-header mdl-js-layout mdl-color--grey-100">
<header class="mdl-layout__header mdl-layout__header--scroll mdl-color--primary-dark">
<div class="mdl-layout__header-row">
<a href="/" class="mdl-layout-title mdl-color-text--blue-grey-50 cvs-title">Converse</a>
<div class="mdl-layout-spacer"></div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label mdl-color-text--blue-grey-50 search-field">
<form method="get" action="/search">
<input class="mdl-textfield__input" type="search" id="search-query" aria-label="Search" name="query">
<label class="mdl-textfield__label mdl-color-text--blue-grey-100" for="search-query">Search query...</label>
<input type="submit" hidden />
</form>
</div>
&nbsp;
<a href="/">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--accent mdl-js-ripple-effect">
Back to index
</button>
</a>
</div>
</header>
<main class="mdl-layout__content">
<section class="section--center mdl-grid">
<div class="mdl-cell--12-col">
<h4>Search results for '{{ query }}':</h4>
</div>
{% for result in results %}
<div class="mdl-card mdl-cell--6-col search-result mdl-shadow--2dp">
<div class="mdl-card__supporting-text">
<p>Posted in '{{ result.title }}' by {{ result.author }}:</p>
<p>{{ result.headline|safe }}</p>
</div>
<div class="mdl-card__actions mdl-card--border post-actions">
<div class="mdl-layout-spacer"></div>
<a class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored" href="/thread/{{ result.thread_id }}#post-{{ result.post_id }}">
<i class="material-icons">arrow_forward</i>
</a>
</div>
</div>
{% endfor %}
</section>
</main>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer--right-section">
<p>Powered by <a href="https://github.com/tazjin/converse">Converse</a></p>
</div>
</footer>
</div>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
</body>
</html>

View file

@ -0,0 +1,111 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<title>Converse: {{ title }}</title>
<!-- TODO -->
<meta http-equiv="Content-Security-Policy" content="script-src https://code.getmdl.io 'self';">
<!-- <link rel="shortcut icon" href="images/favicon.png"> -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu+Mono">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.blue_grey-orange.min.css" />
<link rel="stylesheet" href="/static/styles.css">
<!-- Syntax highlighting for code -->
<link rel="stylesheet" href="/static/highlight.css">
<style>img { max-width:100%; height:auto; }</style>
<script src="/static/highlight.js"></script>
</head>
<body class="converse mdl-base mdl-color-text--grey-700 mdl-color--grey-100">
<div class="mdl-layout mdl-layout--fixed-header mdl-js-layout mdl-color--grey-100">
<header class="mdl-layout__header mdl-color--primary-dark">
<div class="mdl-layout__header-row">
<a href="/" class="mdl-layout-title mdl-color-text--blue-grey-50 cvs-title">Converse: {{ title }}</a>
<div class="mdl-layout-spacer"></div>
<a href="/">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--accent mdl-js-ripple-effect">
Back to index
</button>
</a>
</div>
</header>
<main class="mdl-layout__content">
{% for post in posts -%}
<section id="post-{{ post.id }}" class="section--center mdl-grid mdl-grid--no-spacing">
<!-- card to display avatars on desktop -->
<div class="mdl-card mdl-shadow--2dp mdl-cell--2-col mdl-cell--hide-phone mdl-cell--hide-tablet avatar-box">
<div class="avatar-card">
<img class="desktop-avatar" src="https://www.gravatar.com/avatar/{{ post.author_gravatar }}?d=monsterid&s=160" />
<p class="user-name">{{ post.author_name }}</p>
</div>
</div>
<!-- card for main post content -->
<div class="mdl-card mdl-shadow--2dp post-box mdl-cell--10-col">
<!-- card section for displaying user & post information on mobile -->
<div class="mdl-card__supporting-text mdl-card--border mdl-cell--hide-desktop mdl-color-text--blue-grey-500 mobile-user">
<img class="mobile-avatar" src="https://www.gravatar.com/avatar/{{ post.author_gravatar }}?d=monsterid"/>
<span>&nbsp;{{ post.author_name }} posted on </span>
<a class="mdl-color-text--blue-grey-500 mobile-date" href="/thread/{{ id }}#post-{{ post.id }}">{{ post.posted }}</a>
</div>
<!-- card section to display post date on desktop -->
<div class="mdl-card__menu mdl-cell--hide-phone mdl-cell--hide-tablet">
<a class="post-date mdl-color-text--blue-grey-500" href="/thread/{{ id }}#post-{{ post.id }}">{{ post.posted }}</a>
</div>
<!-- card section for actual post content -->
<div class="mdl-card__supporting-text post-box">{{ post.body|safe }}</div>
<!-- card section for post actions -->
<div class="mdl-card__actions post-actions">
<div class="mdl-layout-spacer"></div>
{% if post.editable %}
<a href="/post/{{ post.id }}/edit" class="mdl-button mdl-js-button mdl-button--accent" id="edit-post-{{ post.id }}" aria-label="Edit post">
<i class="material-icons">edit</i>
<span class="mdl-tooltip mdl-tooltip--top" for="edit-post-{{ post.id }}">Edit post</span>
</a>
{% endif %}
<button class="mdl-button mdl-js-button mdl-button--accent" id="quote-post-{{ post.id }}" aria-label="Quote post" disabled>
<i class="material-icons">reply</i>
<span class="mdl-tooltip mdl-tooltip--top" for="quote-post-{{ post.id }}">Quote post</span>
</button>
</div>
</div>
</section>
{% endfor %}
<!-- section for writing a response on the same page -->
<section id="post-reply" class="section--center mdl-grid mdl-grid--no-spacing reply-box">
<div class="mdl-card mdl-shadow--2dp mdl-cell--12-col">
{% if closed %}
<div class="mdl-card__supporting-text">
This thread is <b>closed</b> and can no longer be responded to.
</div>
{% else %}
<form id="reply-form" action="/thread/reply" method="post">
<input type="hidden" id="thread_id" name="thread_id" value="{{ id }}">
<div class="mdl-card__supporting-text">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label mdl-cell--12-col">
<textarea class="mdl-textfield__input" type="text" rows="8" id="post" name="post" aria-label="reply content"></textarea>
<label class="mdl-textfield__label" for="post">Write a reply</label>
</div>
<button class="mdl-button mdl-button--raised mdl-button--primary mdl-js-button mdl-js-ripple-effect" type="submit">
Post!
</button>
</div>
</form>
{% endif %}
</div>
</section>
</main>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer--right-section">
<p>Powered by <a href="https://github.com/tazjin/converse">Converse</a></p>
</div>
</footer>
</div>
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
</body>
</html>