Skip to content

Commit d1e418c

Browse files
authored
Merge pull request #10 from revolter/feature/markdown-text-formatting
Added support for Markdown text formatting
2 parents 12aa5c7 + b8ebe45 commit d1e418c

File tree

4 files changed

+230
-46
lines changed

4 files changed

+230
-46
lines changed

_sass/minima/custom-styles.scss

Lines changed: 114 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,122 @@
1-
html, body {
2-
height: 100%;
3-
}
1+
$default-spacing: 8px;
42

5-
.page-content {
6-
display: flex;
7-
}
3+
$lm-button-background-color: #f0f0f0;
4+
$lm-button-hover-background-color: #e1e1e1;
5+
6+
$dm-button-background-color: #333333;
7+
$dm-button-hover-background-color: #444444;
8+
9+
$button-background-color: $lm-button-background-color;
10+
$button-hover-background-color: $lm-button-hover-background-color;
11+
12+
@if $color-scheme-auto {
13+
:root {
14+
--io-button-background-color: #{$lm-button-background-color};
15+
--io-button-hover-background-color: #{$lm-button-hover-background-color};
16+
}
17+
18+
@media (prefers-color-scheme: dark) {
19+
:root {
20+
--io-button-background-color: #{$dm-button-background-color};
21+
--io-button-hover-background-color: #{$dm-button-hover-background-color};
22+
}
23+
}
824

9-
.page-content > .wrapper, .home {
10-
display: flex;
11-
flex-grow: 1;
25+
$button-background-color: var(--io-button-background-color);
26+
$button-hover-background-color: var(--io-button-hover-background-color);
27+
} @else if $color-scheme-dark {
28+
$button-background-color: $dm-button-background-color;
29+
$button-hover-background-color: $dm-button-hover-background-color;
1230
}
1331

14-
.page-content > .wrapper {
15-
justify-content: center;
32+
html {
33+
height: 100%;
1634
}
1735

18-
textarea {
19-
color: $text-color;
20-
background-color: $code-background-color;
21-
border-color: $border-color-01;
22-
@include relative-font-size(1);
36+
body {
37+
height: 100%;
38+
39+
code {
40+
text-wrap-mode: wrap;
41+
word-wrap: anywhere;
42+
}
43+
44+
.page-content {
45+
display: flex;
46+
47+
.wrapper {
48+
display: flex;
49+
flex-grow: 1;
50+
justify-content: center;
51+
52+
.home {
53+
display: flex;
54+
flex-grow: 1;
55+
flex-direction: column;
56+
gap: $default-spacing;
57+
58+
.toolbar {
59+
display: flex;
60+
justify-content: flex-end;
61+
62+
button {
63+
@include relative-font-size(1);
64+
color: $text-color;
65+
background: $button-background-color;
66+
border-style: solid;
67+
border-width: 1px;
68+
border-color: $border-color-01;
69+
border-radius: 6px;
70+
cursor: pointer;
71+
72+
transition: background 150ms linear;
73+
&:hover {
74+
background: $button-hover-background-color;
75+
}
76+
77+
}
78+
}
79+
80+
.content {
81+
@media screen and (min-width: $on-laptop) {
82+
flex-direction: row;
83+
}
84+
85+
@media not screen and (min-width: $on-laptop) {
86+
flex-direction: column;
87+
}
88+
89+
display: flex;
90+
flex-grow: 1;
91+
justify-content: center;
92+
93+
gap: $default-spacing;
94+
95+
textarea {
96+
color: $text-color;
97+
@include relative-font-size(1);
98+
}
99+
100+
.markdown-preview {
101+
border-style: solid;
102+
border-width: 1px;
103+
104+
@media not screen and (min-width: $on-laptop) {
105+
overflow: auto;
106+
}
107+
}
108+
109+
textarea, .markdown-preview {
110+
flex-grow: 1;
111+
flex-basis: 0;
112+
113+
background-color: $code-background-color;
114+
border-color: $border-color-01;
23115

24-
width: 100%;
25-
padding: 8px;
116+
padding: $default-spacing;
117+
}
118+
}
119+
}
120+
}
121+
}
26122
}

index.html

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
layout: home
33
---
44

5-
<script src="{{ 'pako/dist/pako.js' | node_module_url | relative_url }}"></script>
65
<script src="{{ 'js-base64/base64.js' | node_module_url | relative_url }}"></script>
6+
<script src="{{ 'pako/dist/pako.min.js' | node_module_url | relative_url }}"></script>
7+
<script src="{{ 'showdown/dist/showdown.min.js' | node_module_url | relative_url }}"></script>
8+
9+
{%- assign markdown_preview_id = 'markdown-preview' -%}
10+
{%- capture toggle_markdown_preview_id -%}toggle-{{ markdown_preview_id }}{%- endcapture -%}
711

812
{%- assign textarea_id = 'textarea' -%}
913
{%- capture textarea_placeholder -%}
@@ -25,7 +29,14 @@
2529

2630
{%- endcapture -%}
2731

28-
<textarea id="{{ textarea_id }}" placeholder="{{ textarea_placeholder }}" autofocus></textarea>
32+
<div class="toolbar">
33+
<button id="{{ toggle_markdown_preview_id }}">Toggle Markdown preview</button>
34+
</div>
35+
36+
<div class="content">
37+
<textarea id="{{ textarea_id }}" placeholder="{{ textarea_placeholder }}" autofocus></textarea>
38+
<div id="{{ markdown_preview_id }}" class="markdown-preview"></div>
39+
</div>
2940

3041
<script>
3142
function main() {
@@ -37,18 +48,50 @@
3748
}
3849

3950
function run() {
51+
const toggleMarkdownPreview = document.getElementById('{{ toggle_markdown_preview_id }}');
4052
const textarea = document.getElementById('{{ textarea_id }}');
41-
loadValue(textarea);
53+
const markdownPreview = document.getElementById('{{ markdown_preview_id }}');
54+
55+
loadMarkdownPreviewVisibility(markdownPreview);
56+
addClickListener(toggleMarkdownPreview);
57+
58+
loadValue(textarea, markdownPreview);
4259
addValueListener(textarea);
4360
addFocusListener(textarea);
44-
addHashListener(textarea);
61+
addHashListener(textarea, markdownPreview);
62+
}
63+
64+
function addClickListener(toggleMarkdownPreview) {
65+
toggleMarkdownPreview.addEventListener('click', () => {
66+
const searchParams = new URLSearchParams(window.location.search);
67+
if (isMarkdownPreviewEnabled()) {
68+
searchParams.delete('{{ markdown_preview_id }}');
69+
} else {
70+
searchParams.set('{{ markdown_preview_id }}', 'true');
71+
}
72+
document.location.search = searchParams.toString();
73+
}, false);
74+
}
75+
76+
function loadMarkdownPreviewVisibility(markdownPreview) {
77+
if (isMarkdownPreviewEnabled()) {
78+
markdownPreview.style.display = 'block';
79+
} else {
80+
markdownPreview.style.display = 'none';
81+
}
82+
}
83+
84+
function isMarkdownPreviewEnabled() {
85+
const searchParams = new URLSearchParams(window.location.search);
86+
return searchParams.has('{{ markdown_preview_id }}');
4587
}
4688

47-
function loadValue(textarea) {
89+
function loadValue(textarea, markdownPreview) {
4890
const value = retrieveValue();
4991
const oldValue = textarea.value;
5092
textarea.value = value;
51-
updateTitle(value);
93+
updateMarkdownPreviewIfNeeded(value, markdownPreview);
94+
updateTitle(value, markdownPreview.textContent);
5295
if (oldValue === '') {
5396
textarea.selectionStart = value.length;
5497
}
@@ -66,26 +109,23 @@
66109

67110
function addValueListener(textarea) {
68111
textarea.addEventListener('input', debounce((event) => {
69-
const value = event.target.value;
70-
onValueUpdate(value);
112+
storeValue(event.target.value);
71113
}, 300), false);
72114
}
73115

74116
function addFocusListener(textarea) {
75117
textarea.addEventListener('blur', () => {
76-
const value = textarea.value;
77-
onValueUpdate(value);
118+
storeValue(textarea.value);
78119
}, false);
79120

80121
window.addEventListener('blur', () => {
81-
const value = textarea.value;
82-
onValueUpdate(value);
122+
storeValue(textarea.value);
83123
}, false);
84124
}
85125

86-
function addHashListener(textarea) {
126+
function addHashListener(textarea, markdownPreview) {
87127
window.addEventListener('hashchange', () => {
88-
loadValue(textarea);
128+
loadValue(textarea, markdownPreview);
89129
});
90130
}
91131

@@ -95,22 +135,54 @@
95135
return deserialize(hash.substring(1));
96136
}
97137

98-
function onValueUpdate(value) {
99-
storeValue(value);
100-
updateTitle(value);
101-
}
102-
103138
function storeValue(value) {
104139
window.location.hash = '#' + serialize(value);
105140
}
106141

107-
function updateTitle(value) {
108-
document.title = '{{ site.tagline }}';
142+
function updateTitle(value, markdownValue) {
143+
const finalValue = markdownValue || value;
144+
145+
const titleParts = [];
146+
const customParts = [];
147+
148+
const rawTitle = finalValue.split('\n', 1)[0];
149+
if (rawTitle !== '') {
150+
const truncatedTitle = truncate(rawTitle.trim(), 30);
151+
customParts.push(truncatedTitle);
152+
}
153+
154+
if (isMarkdownPreviewEnabled()) {
155+
customParts.push('Markdown');
156+
}
157+
158+
if (customParts.length > 0) {
159+
titleParts.push(customParts.join(' - '));
160+
}
161+
titleParts.push('{{ site.tagline }}');
109162

110-
const rawTitle = value.split('\n', 1)[0];
111-
if (rawTitle === '') { return; }
112-
const truncatedTitle = truncate(rawTitle.trim(), 30);
113-
document.title = truncatedTitle + ' | ' + document.title;
163+
document.title = titleParts.join(' | ');
164+
}
165+
166+
function updateMarkdownPreviewIfNeeded(value, markdownPreview) {
167+
if (!isMarkdownPreviewEnabled()) { return; }
168+
169+
const converter = new showdown.Converter({
170+
omitExtraWLInCodeBlocks: true,
171+
noHeaderId: true,
172+
parseImgDimensions: true,
173+
simplifiedAutoLink: true,
174+
literalMidWordUnderscores: true,
175+
strikethrough: true,
176+
tables: true,
177+
tasklists: true,
178+
smoothLivePreview: true,
179+
simpleLineBreaks: true,
180+
openLinksInNewWindow: true,
181+
emoji: true,
182+
splitAdjacentBlockquotes: true
183+
});
184+
const html = converter.makeHtml(value);
185+
markdownPreview.innerHTML = html;
114186
}
115187

116188
function truncate(string, limit) {

package-lock.json

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
},
55
"dependencies": {
66
"js-base64": "*",
7-
"pako": "*"
7+
"pako": "*",
8+
"showdown": "*"
89
},
910
"devDependencies": {
1011
"watchy": "*"

0 commit comments

Comments
 (0)