HTMLかけない人でも静的ファイルを読み込んでいい感じの記事を書けるようにする
動機
- HTMLかけない人でもいい感じの記事やテキストページを書けるようにしたい
- HTMLかける人でもテキストページくらいは労力減らして書けるようにしたい
- 利用者自身で好きに編集できるようにしたい
- 内容をDBに保存したりとかAPI連携するとか考えたくない
- 管理画面ちゃんと作るのめんどくさい
実現したもの
- Markdown使う
- .mdの静的ファイルを読み込むようにしたのでファイル上書きすれば更新可能
デモ
インポートしてるmdファイルの中身
- markdown.md
# 見出し1
## 見出し2
`くつしたねこ`, `ハチワレねこ`, または `ジト目ねこ`
+ 哺乳類
- ねこ
* メインクーン
+ ノルウェージャンフォレストキャット
- サバンナキャット
+ Very cute!
好きな柄順
1. 長さの違う靴下
2. 長さがだいたい同じ靴下
3. 全部
:smile:
> 猫
>> ねこ
> > > 🐈
\```
ねこ
ねこ
ねこ
\```
| 種類 | 詳細 |
| ------| -----------|
| メインクーン | かわいい |
| ノルウェージャンフォレストキャット | かわいい|
| サバンナキャット | かわいい |
## Links
[wiki:ネコ](https://ja.wikipedia.org/wiki/%E3%83%8D%E3%82%B3)
[ホバーで説明が出るリンク](https://ja.wikipedia.org/wiki/%E3%83%8D%E3%82%B3 "ねこかわいい")
![ねこ](./img/cat1.jpg)
19^th^
- H~2~O
++Inserted text++
==Marked text==
Footnotes
Footnote 1 link[^first].
Footnote 2 link[^second].
Inline footnote^[Text of inline footnote] definition.
Duplicated footnote reference[^second].
[^first]: Footnote **can have markup**
and multiple paragraphs.
[^second]: Footnote text.
### Abbreviations
This is HTML abbreviation example.
It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
* [HTML]: Hyper Text Markup Language
画像はpublicのフォルダ配下に配置する。
今回はpublicの下にimgフォルダを作って画像を置いているので
http://localhost:8080/img/cat1.jpg
で画像にアクセスできる
実装
使ったもの
Vue.js
vue-markdown
VuiCLI3を使ってるので
npm install --save vue-markdown @vue/cli
でインストールした
axios
階層
MarkdownSmaple
┠ public
┃ ┠ markdown.md --importするmarkdownのファイル
┃ ┠ img
┃ ┗ ┗ cat1.jpg --markdown内で使う画像ファイル
┠ src
┃ ┠ main.js
┃ ┠ assets
┃ ┠ components
┃ ┃ ┠ Markdown.vue
┃ ┃ ┠ md.css --markdown用のcss
┗ ┗ ┗ md_table.css --markdown用(table)のcss
コード
- main.js
axiosを使えるようにする
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios' //追加
Vue.config.productionTip = false
Vue.prototype.$axios = axios //追加
new Vue({
render: h => h(App)
}).$mount('#app')
- Markdown.vue
<template>
<div>
<v-row id="md">
<v-col>
<vue-markdown :source="source"></vue-markdown>
</v-col>
</v-row>
</div>
</template>
<script>
import VueMarkdown from "vue-markdown";
export default {
components: {
VueMarkdown
},
data() {
return { source: "" };
},
mounted: function() {
/* publicのフォルダに置いたmdファイルを取得する
public配下はbuildするとroot直下として扱われる
assetsフォルダの下に置くと読み込まれないので注意 */
this.$axios
.get("./markdown.md")
.then(response => (this.source = response.data));
}
};
</script>
<style>
/* cssファイルをインポート */
@import "./md.css";
@import "./md_table.css";
#md {
position: relative;
left: 5%;
}
</style>
- md.css
ここのcssを一部改修した
cssを変更すればデザインも変わるのでいい感じにしよう
@import url(http://fonts.googleapis.com/css?family=Ubuntu:bold);
@import url(http://fonts.googleapis.com/css?family=Vollkorn);
html {
font-size: 100%;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
body {
max-width:42em;
padding:1em;
margin:auto;
color:#444;
line-height:1.5em;
font-family:Vollkorn, Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif;
font-size:12px;
background:#fefefe;
}
a {
color: #337ab7;
text-decoration:none;
}
a:visited { color: #0b0080; }
a:hover { color: #06e; }
a:active { color:#faa700; }
a:focus { outline: thin dotted; }
a:hover, a:active { outline: 0; }
::-moz-selection{ background: rgba(255,255,0,0.3); color: #000}
::selection{ background: rgba(255,255,0,0.3); color: #000}
a::-moz-selection{ background: rgba(255,255,0,0.3); color: #0645ad}
a::selection{ background: rgba(255,255,0,0.3); color: #0645ad}
p {
margin: 1em 0;
}
img {
max-width: 100%;
}
h1,h2,h3,h4,h5,h6 {
font-family: 'Ubuntu';
font-weight:normal;
color:#111;
line-height:1em;
}
h4, h5, h6 { font-weight: bold; }
h1 { font-size:2.5em; }
h2 { font-size:2em; }
h3 { font-size:1.5em; }
h4 { font-size:1.2em; }
h5 { font-size:1em; }
h6 { font-size:0.9em; }
blockquote {
padding-left: 3em;
margin: 0;
color: #666666;
border-left: 0.5em #EEE solid;
}
hr {
padding: 0;
margin: 1em 0;
display: block;
height: 2px;
border: 0;
border-top: 1px solid #aaa;
border-bottom: 1px solid #eee;
}
pre, kbd, samp {
color: #000;
font-family: monospace, monospace;
_font-family: 'courier new', monospace;
font-size: 0.98em;
}
code{
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
border-radius: 4px;
font-family: monospace, monospace;
_font-family: 'courier new', monospace;
font-size: 0.98em;
}
pre {
white-space: pre;
white-space: pre-wrap;
word-wrap: break-word;
color: #333;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
}
pre code {
padding: 0;
font-size: inherit;
color: inherit;
white-space: pre-wrap;
background-color: transparent;
border-radius: 0;
}
b, strong {
font-weight: bold;
}
dfn { font-style: italic; }
ins { color: #000; text-decoration: underline; }
mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; }
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
ul, ol { margin: 1em 0; padding: 0 0 0 2em; }
li p:last-child { margin:0 }
dd { margin: 0 0 0 2em; }
img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; }
@media only screen and (min-width: 480px) {
body {
max-width: 100%;
font-size: 14px;
}
}
@media only screen and (min-width: 768px) {
body {
max-width:42em;
font-size: 16px;
}
}
@media print {
* { background: transparent !important; color: black !important; filter:none !important; -ms-filter: none !important; }
body{font-size:12pt; max-width:100%;}
a, a:visited { text-decoration: underline; }
hr { height: 1px; border:0; border-bottom:1px solid black; }
a[href]:after { content: " (" attr(href) ")"; }
abbr[title]:after { content: " (" attr(title) ")"; }
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
pre, blockquote { border: 1px solid #999; padding-right: 1em; page-break-inside: avoid; }
tr, img { page-break-inside: avoid; }
img { max-width: 100% !important; }
@page { margin: 0.5cm; }
p, h2, h3 { orphans: 3; widows: 3; }
h2, h3 { page-break-after: avoid; }
}
- md_table.css
長かったので外に出しただけ
table {
border-spacing: 0;
border-collapse: collapse;
}
td, th {
padding: 0
}
thead {
display: table-header-group
}
.table {
width: 100%;
max-width: 100%;
margin-bottom: 20px
}
.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th {
padding: 8px;
line-height: 1.42857143;
vertical-align: top;
border-top: 1px solid #ddd
}
.table>thead>tr>th {
vertical-align: bottom;
border-bottom: 2px solid #ddd
}
.table>caption+thead>tr:first-child>td, .table>caption+thead>tr:first-child>th, .table>colgroup+thead>tr:first-child>td, .table>colgroup+thead>tr:first-child>th, .table>thead:first-child>tr:first-child>td, .table>thead:first-child>tr:first-child>th {
border-top: 0
}
.table>tbody+tbody {
border-top: 2px solid #ddd
}
.table .table {
background-color: #fff
}
.table-condensed>tbody>tr>td, .table-condensed>tbody>tr>th, .table-condensed>tfoot>tr>td, .table-condensed>tfoot>tr>th, .table-condensed>thead>tr>td, .table-condensed>thead>tr>th {
padding: 5px
}
.table-bordered {
border: 1px solid #ddd
}
.table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>thead>tr>th {
border: 1px solid #ddd
}
.table-bordered>thead>tr>td, .table-bordered>thead>tr>th {
border-bottom-width: 2px
}
.table-striped>tbody>tr:nth-of-type(odd) {
background-color: #f9f9f9
}
.table-hover>tbody>tr:hover {
background-color: #f5f5f5
}
table col[class*=col-] {
position: static;
display: table-column;
float: none
}
table td[class*=col-], table th[class*=col-] {
position: static;
display: table-cell;
float: none
}
.table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
background-color: #f5f5f5
}
.table-hover>tbody>tr.active:hover>td, .table-hover>tbody>tr.active:hover>th, .table-hover>tbody>tr:hover>.active, .table-hover>tbody>tr>td.active:hover, .table-hover>tbody>tr>th.active:hover {
background-color: #e8e8e8
}
.table>tbody>tr.success>td, .table>tbody>tr.success>th, .table>tbody>tr>td.success, .table>tbody>tr>th.success, .table>tfoot>tr.success>td, .table>tfoot>tr.success>th, .table>tfoot>tr>td.success, .table>tfoot>tr>th.success, .table>thead>tr.success>td, .table>thead>tr.success>th, .table>thead>tr>td.success, .table>thead>tr>th.success {
background-color: #dff0d8
}
.table-hover>tbody>tr.success:hover>td, .table-hover>tbody>tr.success:hover>th, .table-hover>tbody>tr:hover>.success, .table-hover>tbody>tr>td.success:hover, .table-hover>tbody>tr>th.success:hover {
background-color: #d0e9c6
}
.table>tbody>tr.info>td, .table>tbody>tr.info>th, .table>tbody>tr>td.info, .table>tbody>tr>th.info, .table>tfoot>tr.info>td, .table>tfoot>tr.info>th, .table>tfoot>tr>td.info, .table>tfoot>tr>th.info, .table>thead>tr.info>td, .table>thead>tr.info>th, .table>thead>tr>td.info, .table>thead>tr>th.info {
background-color: #d9edf7
}
.table-hover>tbody>tr.info:hover>td, .table-hover>tbody>tr.info:hover>th, .table-hover>tbody>tr:hover>.info, .table-hover>tbody>tr>td.info:hover, .table-hover>tbody>tr>th.info:hover {
background-color: #c4e3f3
}
.table>tbody>tr.warning>td, .table>tbody>tr.warning>th, .table>tbody>tr>td.warning, .table>tbody>tr>th.warning, .table>tfoot>tr.warning>td, .table>tfoot>tr.warning>th, .table>tfoot>tr>td.warning, .table>tfoot>tr>th.warning, .table>thead>tr.warning>td, .table>thead>tr.warning>th, .table>thead>tr>td.warning, .table>thead>tr>th.warning {
background-color: #fcf8e3
}
.table-hover>tbody>tr.warning:hover>td, .table-hover>tbody>tr.warning:hover>th, .table-hover>tbody>tr:hover>.warning, .table-hover>tbody>tr>td.warning:hover, .table-hover>tbody>tr>th.warning:hover {
background-color: #faf2cc
}
.table>tbody>tr.danger>td, .table>tbody>tr.danger>th, .table>tbody>tr>td.danger, .table>tbody>tr>th.danger, .table>tfoot>tr.danger>td, .table>tfoot>tr.danger>th, .table>tfoot>tr>td.danger, .table>tfoot>tr>th.danger, .table>thead>tr.danger>td, .table>thead>tr.danger>th, .table>thead>tr>td.danger, .table>thead>tr>th.danger {
background-color: #f2dede
}
.table-hover>tbody>tr.danger:hover>td, .table-hover>tbody>tr.danger:hover>th, .table-hover>tbody>tr:hover>.danger, .table-hover>tbody>tr>td.danger:hover, .table-hover>tbody>tr>th.danger:hover {
background-color: #ebcccc
}
.table-responsive {
min-height: .01%;
overflow-x: auto
}
まとめ
利用規約とか軽い日記とか労力かけたくないけど見栄えよくしたい場合にいいと思います。
HTMLかけなくてもコマンド使えればなんとかなる
コマンド使えない人も使えるようにするなら管理画面作ってあげたほうがいいけど、静的ファイル更新するだけなのでそこまで難しくなさそう