Commit f3f07260 authored by Emma's avatar Emma 🏳🌈

built-in markdown help/improve markdown preview

fixes #2
parent c41d3271
Pipeline #59317790 passed with stages
in 8 minutes and 1 second
.form-help {
color: var(--text-muted);
font-size: 0.875rem;
margin-bottom: 0;
.form-row + .form-row > & {
......
.formatting-help {
&__table {
border-collapse: collapse;
margin-top: 0.5rem;
td {
border: solid 1px var(--border);
padding: 0.125em 0.25em;
}
}
&__toggle {
opacity: 1;
position: absolute;
z-index: -1;
}
&__toggle:focus ~ &__link > .no-underline__exempt {
text-decoration: underline;
}
&__link {
color: var(--link);
cursor: pointer;
}
&__arrow::after {
border-left: 0.5ch solid transparent;
border-right: 0.5ch solid transparent;
border-top: 0.5ch solid;
content: '';
display: inline-block;
vertical-align: middle;
}
&__toggle:checked ~ &__link > &__arrow::after {
border-bottom: 0.5ch solid;
border-top: none;
}
&__toggle:not(:checked) ~ &__table {
display: none;
}
}
@import (reference) '../_variables';
.markdown-input {
margin-bottom: 0;
&__preview {
background: var(--bg-red);
border-radius: 4px;
display: flex;
flex-direction: column;
margin: 1rem 0;
padding: 1rem 1rem 0;
}
}
@import (reference) '../_variables';
.markdown-preview {
margin-bottom: 1rem;
@media screen and (min-width: @desktop-min-width) {
max-width: 40rem;
}
&:empty {
display: none;
}
&__title {
margin-bottom: 0.5rem;
}
&__inner {
background: var(--accent);
max-height: 20rem;
overflow: auto;
padding: 1rem 1rem 0;
scrollbar-color: var(--primary) var(--accent);
scrollbar-width: thin;
}
}
// remove bottom margin that is applied to many block elements
.no-margin {
margin-bottom: 0;
margin-bottom: 0 !important;
}
......@@ -18,7 +18,8 @@
@import '_form/form-error-list';
@import '_form/form-row';
@import '_form/form-help';
@import '_form/markdown-input';
@import '_form/formatting-help';
@import '_form/markdown-preview';
@import '_form/required-indicator';
@import '_form/unstylable-widget';
......
......@@ -3,30 +3,25 @@
import debounce from 'lodash.debounce';
// noinspection NpmUsedModulesInstalled
import Routing from 'fosjsrouting';
import translator from 'bazinga-translator';
import $ from 'jquery';
function createPreview() {
const $input = $(this);
$.ajax({
url: Routing.generate('markdown_preview'),
method: 'POST',
dataType: 'html',
data: { markdown: $(this).val() },
data: { markdown: $input.val() },
}).done(content => {
const html = content.length > 0
? `<div class="markdown-input__preview">${content}</div>`
? `<h3 class="markdown-preview__title">${translator.trans('markdown_type.preview')}</h3>
<div class="markdown-preview__inner">${content}</div>`
: '';
$(this)
.closest('.markdown-input')
.find('.markdown-input__preview-container')
.html(html);
$('#' + $input.attr('id') + '_preview').html(html);
});
}
$(function () {
$(document).on(
'input',
'.js-enable-post-previews .markdown-input__input',
debounce(createPreview, 600)
);
});
$(() => $(document).on('input', '.js-markdown-preview', debounce(createPreview, 600)));
......@@ -6,3 +6,4 @@ twig:
strict_variables: '%kernel.debug%'
form_themes:
- "_forms/standard_form_theme.html.twig"
- "_forms/markdown.html.twig"
......@@ -3,6 +3,8 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as BaseAbstractController;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
abstract class AbstractController extends BaseAbstractController {
......@@ -17,4 +19,15 @@ abstract class AbstractController extends BaseAbstractController {
throw new BadRequestHttpException('Invalid CSRF token');
}
}
protected function createNamedForm(
$name,
$type = FormType::class,
$data = null,
array $options = []
): FormInterface {
return $this->container
->get('form.factory')
->createNamed($name, $type, $data, $options);
}
}
......@@ -61,7 +61,9 @@ final class CommentController extends AbstractController {
$routeParams['comment_id'] = $commentId;
}
$form = $this->createForm(CommentType::class, null, [
$name = $this->getFormName($submissionId, $commentId);
$form = $this->createNamedForm($name, CommentType::class, null, [
'action' => $this->generateUrl('comment_post', $routeParams),
'forum' => $forumRepository->findOneByCaseInsensitiveName($forumName),
]);
......@@ -93,9 +95,12 @@ final class CommentController extends AbstractController {
Request $request,
EventDispatcherInterface $dispatcher
) {
$name = $this->getFormName($submission, $comment);
$data = new CommentData($submission);
$form = $this->createForm(CommentType::class, $data, ['forum' => $forum]);
$form = $this->createNamedForm($name, CommentType::class, $data, [
'forum' => $forum,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
......@@ -290,4 +295,13 @@ final class CommentController extends AbstractController {
'slug' => Slugger::slugify($comment->getSubmission()->getTitle()),
]);
}
private function getFormName($submission, $comment): string {
$submissionId = $submission instanceof Submission ? $submission->getId() : $submission;
$commentId = $comment instanceof Comment ? $comment->getId() : $comment;
return isset($commentId)
? 'reply_to_comment_'.$commentId
: 'reply_to_submission_'.$submissionId;
}
}
{% block markdown_row %}
{{ form_row(form, {
attr: { class: (app.user.enablePostPreviews ?? false) ? 'js-markdown-preview' },
help: block('_markdown_help'),
help_attr: { class: 'formatting-help' },
raw_help: true
}) }}
<div class="markdown-preview" id="{{ form.vars.id }}_preview"></div>
{%- endblock markdown_row %}
{% block _markdown_help %}
<input type="checkbox" class="formatting-help__toggle" id="{{ id~'_markdown_help' }}">
<span class="fg-muted text-sm">{{ 'help.markdown_allowed'|trans }}</span>
<label class="formatting-help__link no-underline text-sm" for="{{ id~'_markdown_help' }}">
<span class="no-underline__exempt">{{- 'markdown_type.help'|trans }}</span>
<span class="formatting-help__arrow" role="presentation"></span>
</label>
{% filter spaceless %}
<table class="formatting-help__table">
<tbody>
<tr>
<td>
<p>{{ 'markdown_type.paragraph'|trans }}</p>
<p class="no-margin">{{ 'markdown_type.another_paragraph'|trans }}</p>
</td>
<td>
<kbd>
{{ 'markdown_type.paragraph'|trans }}<br>
<br>
{{ 'markdown_type.another_paragraph'|trans }}
</kbd>
</td>
</tr>
<tr>
<td>
{{ 'markdown_type.line'|trans }}<br>
{{ 'markdown_type.break'|trans }}
</td>
<td>
<kbd>
{{ 'markdown_type.line'|trans }} \<br>
{{ 'markdown_type.break'|trans }}
</kbd>
</td>
</tr>
<tr>
<td><em>{{ 'markdown_type.emphasis'|trans }}</em></td>
<td><kbd>*{{ 'markdown_type.emphasis'|trans }}*</kbd></td>
</tr>
<tr>
<td><strong>{{ 'markdown_type.strong_emphasis'|trans }}</strong></td>
<td><kbd>**{{ 'markdown_type.strong_emphasis'|trans }}**</kbd></td>
</tr>
<tr>
<td><del>{{ 'markdown_type.strikethrough'|trans }}</del></td>
<td><kbd>~~{{ 'markdown_type.strikethrough'|trans }}~~</kbd></td>
</tr>
<tr>
<td>
<h1>{{ 'markdown_type.heading_1'|trans }}</h1>
<h2>{{ 'markdown_type.heading_2'|trans }}</h2>
<h3>{{ 'markdown_type.heading_3'|trans }}</h3>
<h4>{{ 'markdown_type.heading_4'|trans }}</h4>
<h5>{{ 'markdown_type.heading_5'|trans }}</h5>
<h6 class="no-margin">{{ 'markdown_type.heading_6'|trans }}</h6>
</td>
<td>
<kbd>
{{ 'markdown_type.heading_1'|trans }}<br>
===<br>
<br>
{{ 'markdown_type.heading_2'|trans }}<br>
---<br>
<br>
### {{ 'markdown_type.heading_3'|trans }}<br>
#### {{ 'markdown_type.heading_4'|trans }}<br>
##### {{ 'markdown_type.heading_5'|trans }}<br>
###### {{ 'markdown_type.heading_6'|trans }}
</kbd>
</td>
</tr>
<tr>
<td>
<ul class="no-margin">
<li>{{ 'markdown_type.list_item'|trans }}</li>
<li>{{ 'markdown_type.list_item'|trans }}</li>
</ul>
</td>
<td>
<kbd>
* {{ 'markdown_type.list_item'|trans }}<br>
* {{ 'markdown_type.list_item'|trans }}<br>
</kbd>
</td>
</tr>
<tr>
<td>
<ol class="no-margin">
<li>{{ 'markdown_type.list_item'|trans }}</li>
<li>{{ 'markdown_type.list_item'|trans }}</li>
</ol>
</td>
<td>
<kbd>
1. {{ 'markdown_type.list_item'|trans }}<br>
2. {{ 'markdown_type.list_item'|trans }}<br>
</kbd>
</td>
</tr>
<tr>
<td>
<a href="#" tabindex="-1">{{ 'markdown_type.link'|trans }}</a><br>
<a href="#" tabindex="-1">/f/{{ 'markdown_type.forum'|trans }}</a><br>
<a href="#" tabindex="-1">/u/{{ 'markdown_type.user'|trans }}</a><br>
<a href="#" tabindex="-1">/w/{{ 'markdown_type.wiki_page'|trans }}</a>
</td>
<td>
<kbd>
[{{ 'markdown_type.link'|trans }}](http://example.com)<br>
/f/{{ 'markdown_type.forum'|trans }}<br>
/u/{{ 'markdown_type.user'|trans }}<br>
/w/{{ 'markdown_type.wiki_page'|trans }}
</kbd>
</td>
</tr>
<tr>
<td>
<blockquote>
<p>{{ 'markdown_type.blockquote'|trans }}</p>
<p class="no-margin">{{ 'markdown_type.another_paragraph'|trans }}</p>
</blockquote>
</td>
<td>
<kbd>
&gt; {{ 'markdown_type.blockquote'|trans }}<br>
&gt;<br>
&gt; {{ 'markdown_type.another_paragraph'|trans }}
</kbd>
</td>
</tr>
<tr>
<td>{{ 'markdown_type.horizontal_rule'|trans }}<hr></td>
<td>
<kbd>
{{ 'markdown_type.horizontal_rule'|trans }}<br>
<br>
---
</kbd>
</td>
</tr>
<tr>
<td><code>{{ 'markdown_type.inline_code'|trans }}</code></td>
<td><kbd>`{{ 'markdown_type.inline_code'|trans }}`</kbd></td>
</tr>
<tr>
<td>
<code>
<span class="fg-blue">&lt;</span><span class="fg-orange">div</span><span class="fg-blue">&gt;</span><br>
&nbsp;&nbsp;<span class="fg-text">{{ 'markdown_type.code_block'|trans }}</span><br>
<span class="fg-blue">&lt;/</span><span class="fg-orange">div</span><span class="fg-blue">&gt;</span><br>
</code>
</td>
<td>
<kbd>
~~~html<br>
&lt;div&gt;<br>
&nbsp;&nbsp;{{ 'markdown_type.code_block'|trans }}<br>
&lt;/div&gt;<br>
~~~
</kbd>
</td>
</tr>
</tbody>
</table>
{% endfilter %}
{% endblock _markdown_help %}
......@@ -90,12 +90,12 @@
{%- block form_row -%}
{%- if help is not empty -%}
{%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
{%- set widget_attr = (widget_attr ?? {})|merge({ attr: { 'aria-describedby': id~"_help" } }) -%}
{%- endif -%}
{{- form_errors(form) -}}
<div class="form-row form__row">
{{- form_label(form) -}}
{{- form_widget(form, widget_attr ?? {}) -}}
{{- form_label(form, null, label_attr ?? {}) -}}
{{- form_widget(form, attr|merge(widget_attr ?? {})) -}}
</div>
{{- form_help(form) -}}
{%- endblock form_row -%}
......@@ -110,23 +110,6 @@
{%- endif -%}
{%- endblock form_errors -%}
{%- block markdown_row -%}
{%- set attr = attr|merge({'class': (attr.class ?? '')~' markdown-input__input'}) -%}
<div class="form__row form__row--markdown markdown-input">
{{- form_label(form) -}}
{{- form_errors(form) -}}
{{- block('textarea_widget') -}}
<p class="no-margin text-align-right">
{#- TODO: don't link to an external site -#}
<a href="http://commonmark.org/help/" target="_blank" class="text-sm">
{{- 'markdown_type.help'|trans -}}
</a>
</p>
<div class="markdown-input__preview-container"></div>
</div>
{{- form_help(form) -}}
{%- endblock markdown_row -%}
{# labels #}
{% block choice_label %}
......
......@@ -27,8 +27,7 @@
<body class="{% block page_classes '' %}
{{ app.user ? 'user-logged-in' : 'user-anonymous' }}
{{ (app.user.nightMode ?? false) ? 'night-mode' }}
{{ (app.user.enablePostPreviews ?? true) ? 'js-enable-post-previews' }}">
{{ (app.user.nightMode ?? false) ? 'night-mode' }}">
{% block site_alerts %}
<div class="site-alerts">
{%- for type, notices in app.flashes -%}
......
......@@ -78,15 +78,15 @@
{% endblock %}
{% block _preferred_fonts_help %}
<p>{{ 'help.preferred_fonts'|trans }}</p>
<p>
<p class="fg-muted text-sm">{{ 'help.preferred_fonts'|trans }}</p>
<p class="fg-muted text-sm">
{{ 'help.preferred_fonts_served'|trans }}
{%- for font in font_list() if font_names(font) == [font] %}
{{- loop.index != 1 ? ', ' -}}
<strong>{{ font|capitalize }}</strong>
{%- endfor %}
</p>
<p>
<p class="fg-muted text-sm">
{{ 'help.preferred_fonts_aliases'|trans }}
{%- for font in font_list() if font_names(font) != [font] %}
{{- loop.index != 1 ? ', ' -}}
......
......@@ -33,8 +33,8 @@ class UserControllerTest extends WebTestCase {
$client = $this->createEmmaClient();
$crawler = $client->request('GET', '/f/cats/3');
$form = $crawler->selectButton('comment[submit]')->form([
'comment[comment]' => 'You will be notified about this comment.',
$form = $crawler->selectButton('reply_to_submission_3[submit]')->form([
'reply_to_submission_3[comment]' => 'You will be notified about this comment.',
]);
$client->submit($form);
......@@ -52,8 +52,8 @@ class UserControllerTest extends WebTestCase {
$client = $this->createEmmaClient();
$crawler = $client->request('GET', '/f/cats/3/-/comment/3/');
$form = $crawler->selectButton('comment[submit]')->form([
'comment[comment]' => 'You will be notified about this comment.',
$form = $crawler->selectButton('reply_to_comment_3[submit]')->form([
'reply_to_comment_3[comment]' => 'You will be notified about this comment.',
]);
$client->submit($form);
......
......@@ -220,6 +220,7 @@ help:
preferred_fonts: 'Comma-separated list of the fonts you prefer. These can be fonts from your system, or from the list of server-provided fonts below.'
preferred_fonts_served: 'Server-provided fonts (available everywhere): '
preferred_fonts_aliases: 'Aliased font names: '
markdown_allowed: Markdown allowed.
inbox:
message_reply_head: 'Re: %title%'
......@@ -343,7 +344,30 @@ login_form:
reset_password: Reset password?
markdown_type:
help: Syntax reference
preview: Preview
help: Formatting help
paragraph: Paragraph
another_paragraph: Another paragraph
line: line
break: break
emphasis: Emphasis
strong_emphasis: Strong emphasis
strikethrough: Strikethrough
heading_1: Heading 1
heading_2: Heading 2
heading_3: Heading 3
heading_4: Heading 4
heading_5: Heading 5
heading_6: Heading 6
list_item: List item
link: Link
forum: forum
user: user
wiki_page: wiki_page
blockquote: Blockquote
horizontal_rule: Horizontal rule
inline_code: Inline code
code_block: Code block
message_form:
title: Title
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment