Skip to content

Instantly share code, notes, and snippets.

@abe-lib
Last active November 15, 2018 04:31
Show Gist options
  • Save abe-lib/2c9e29cd87623d2b1ac089eeff7b0502 to your computer and use it in GitHub Desktop.
Save abe-lib/2c9e29cd87623d2b1ac089eeff7b0502 to your computer and use it in GitHub Desktop.
簡易メモ帳components
<template>
<div style="display: flex;flex-direction: column; width: 100%;">
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item v-for="(item) in memos"
:key="item.key"
:index="item.key">
<el-popover
class="popOver"
placement="top-start"
width="240"
trigger="click">
<div class="el-popover__content">
<span>Title:</span><input type="text" v-model="item.title" @blur="editMemo('')">
</div>
<span slot="reference">{{item.title}}</span>
</el-popover>
<span class="menu-text">{{item.title}}</span>
<i class="el-icon-close" @click="dialogVisible = true"></i>
</el-menu-item>
</el-menu>
<Edit :viewMode="viewMode" :editText="memoContent" @editMemo="editMemo" v-if="Object.keys(memos).length"/>
<el-dialog
title="削除"
:visible.sync="dialogVisible"
width="30%">
<span>本当に削除しますか?</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">キャンセル</el-button>
<el-button type="primary" @click="deleteMemo(false)">削除</el-button>
</span>
</el-dialog>
<el-dialog title="ログイン(まだ未実装)" :visible.sync="dialogFormVisible" @close="$emit('formVisible',false)">
<el-form :model="form">
<el-form-item label="E-mail" :label-width="formLabelWidth">
<el-input v-model="form.email" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="Password" :label-width="formLabelWidth">
<el-input type="password" v-model="form.passward" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('formVisible',false)">キャンセル</el-button>
<el-button type="primary" @click="$emit('formVisible',false)">送信</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Edit from '@/components/edit'
export default {
components : {
Edit
},
props:['viewMode','dialogFormVisible'],
data() {
return {
activeIndex: '',
memoIndex: '',
dialogVisible: false,
popVisible: false,
formLabelWidth: '120px',
form: {
email: '',
password: '',
},
user: ""
};
},
computed: {
//Vuexからメモ情報をゲッターで取得
memos: function () {
return this.$store.getters.memos
},
//本文をedit.vueに渡すために抽出
memoContent: function () {
if(this.memos[this.memoIndex]){
return this.memos[this.memoIndex].content
}
}
},
methods: {
//メモの選択した時
handleSelect(key, keyPath) {
this.activeIndex = key;
this.memoIndex = this.memos.findIndex(
memo => memo.key === this.activeIndex
);
},
//タイトルを変更するためのツールチップを表示
popOver(key){
if(key == this.activeIndex){
this.popVisible = true;
}
},
//メモを編集した時
editMemo(memo){
if(memo){ //本文修正の時だけ代入
this.memos[this.memoIndex].content = memo
}
this.$store.dispatch('editMemo',this.memos[this.memoIndex]);
},
//メモを削除した時
deleteMemo(display){
this.dialogVisible = display;
this.$store.dispatch('deleteMemo',{ key: this.activeIndex, index: this.memoIndex });
this.activeIndex = "";
},
},
created: function(){
this.user = this.$store.getters.user;
}
}
</script>
<style scoped>
.el-menu--horizontal>.el-menu-item {
height: 48px;
line-height: 48px;
transition: color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);
}
.el-menu--horizontal>.el-menu-item * {
vertical-align: initial;
}
.el-menu-item .popOver {
display: none;
}
.el-menu-item .popOver span{
line-height: 48px;
display: inline-block;
}
.el-menu-item.is-active .popOver {
display: inline-block;
}
.el-menu-item.is-active .menu-text {
display: none;
}
.el-menu-item [class^=el-icon-].el-icon-close {
font-size: 12px;
width: 0;
overflow: hidden;
border-radius: 50%;
text-align: center;
transition: all .3s cubic-bezier(.645,.045,.355,1);
position: relative;
top: 2px;
}
.el-menu-item.is-active:hover {
padding: 0 10px;
}
.el-menu-item.is-active:hover [class^=el-icon-].el-icon-close {
width: 12px;
margin-left: 8px;
}
[class^=el-icon-].el-icon-close:hover {
color: #409EFF;
}
.el-popover__content {
display: flex;
}
.el-popover__content input {
flex-grow: 1;
padding: 2px;
}
</style>
<template>
<div id="note" class="wrapper">
<div class="contents" :class="viewMode">
<div class="contents__edit"><textarea :value="editText" @input="$emit('editMemo',$event.target.value)"></textarea></div>
<div class="contents__view"><div v-html="compiledMarkdown"></div></div>
</div>
</div>
</template>
<script>
import Marked from 'marked'
import HighlightJs from 'highlight.js'
export default {
props:['viewMode','editText'],
data() {
return {
activeIndex: '',
memoIndex: '',
};
},
computed: {
//markdownを変換する
compiledMarkdown: function () {
let memo;
if(this.editText){
var renderer = new Marked.Renderer;
renderer.code = function(code, language) {
return '<pre'+'><code class="hljs language-'+ language +'">' + HighlightJs.highlightAuto(code).value + '</code></pre>';
};
Marked.setOptions({
breaks: true,
langPrefix: 'language-',
sanitize: true,
renderer: renderer
})
return Marked(this.editText)
}
}
}
}
</script>
<style>
.wrapper {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
height: 100%;
background-color: #fff;
}
.contents {
width: 100%;
flex-grow: 1;
display: flex;
flex-direction: row;
overflow: hidden;
}
.contents__edit,
.contents__view {
width: 50%;
transition: width .3s;
}
.contents__edit {
background-color: #f8f8f8;
}
.contents__edit textarea {
background-color: #f8f8f8;
padding: 10px;
border: none;
width: 100%;
min-height: 100%;
height: auto;
flex-grow: 1;
outline: none;
resize: none;
line-height: 160%;
overflow: inherit;
}
.contents__view div {
height: 100%;
overflow: auto;
padding: 10px;
}
.contents.edit .contents__edit {
width: 100%;
}
.contents.edit .contents__view {
width: 0;
padding: 0;
overflow: hidden;
}
.contents.view .contents__edit {
width: 0;
padding: 0;
overflow: hidden;
}
.contents.view .contents__view {
width: 100%;
}
.contents__view .pl-c {
color: #6a737d;
}
.contents__view .pl-c1,
.contents__view .pl-s .pl-v {
color: #005cc5;
}
.contents__view .pl-e,
.contents__view .pl-en {
color: #6f42c1;
}
.contents__view .pl-smi,
.contents__view .pl-s .pl-s1 {
color: #24292e;
}
.contents__view .pl-ent {
color: #22863a;
}
.contents__view .pl-k {
color: #d73a49;
}
.contents__view .pl-s,
.contents__view .pl-pds,
.contents__view .pl-s .pl-pse .pl-s1,
.contents__view .pl-sr,
.contents__view .pl-sr .pl-cce,
.contents__view .pl-sr .pl-sre,
.contents__view .pl-sr .pl-sra {
color: #032f62;
}
.contents__view .pl-v,
.contents__view .pl-smw {
color: #e36209;
}
.contents__view .pl-bu {
color: #b31d28;
}
.contents__view .pl-ii {
color: #fafbfc;
background-color: #b31d28;
}
.contents__view .pl-c2 {
color: #fafbfc;
background-color: #d73a49;
}
.contents__view .pl-c2::before {
content: "^M";
}
.contents__view .pl-sr .pl-cce {
font-weight: bold;
color: #22863a;
}
.contents__view .pl-ml {
color: #735c0f;
}
.contents__view .pl-mh,
.contents__view .pl-mh .pl-en,
.contents__view .pl-ms {
font-weight: bold;
color: #005cc5;
}
.contents__view .pl-mi {
font-style: italic;
color: #24292e;
}
.contents__view .pl-mb {
font-weight: bold;
color: #24292e;
}
.contents__view .pl-md {
color: #b31d28;
background-color: #ffeef0;
}
.contents__view .pl-mi1 {
color: #22863a;
background-color: #f0fff4;
}
.contents__view .pl-mc {
color: #e36209;
background-color: #ffebda;
}
.contents__view .pl-mi2 {
color: #f6f8fa;
background-color: #005cc5;
}
.contents__view .pl-mdr {
font-weight: bold;
color: #6f42c1;
}
.contents__view .pl-ba {
color: #586069;
}
.contents__view .pl-sg {
color: #959da5;
}
.contents__view .pl-corl {
text-decoration: underline;
color: #032f62;
}
.contents__view .octicon {
display: inline-block;
vertical-align: text-top;
fill: currentColor;
}
.contents__view a {
background-color: transparent;
}
.contents__view a:active,
.contents__view a:hover {
outline-width: 0;
}
.contents__view strong {
font-weight: inherit;
}
.contents__view strong {
font-weight: bolder;
}
.contents__view h1 {
font-size: 2em;
margin: 0.67em 0;
}
.contents__view img {
border-style: none;
}
.contents__view code,
.contents__view kbd,
.contents__view pre {
font-family: monospace, monospace;
font-size: 1em;
}
.contents__view hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
.contents__view input {
font: inherit;
margin: 0;
}
.contents__view input {
overflow: visible;
}
.contents__view [type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
.contents__view * {
box-sizing: border-box;
}
.contents__view input {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
.contents__view a {
color: #0366d6;
text-decoration: none;
}
.contents__view a:hover {
text-decoration: underline;
}
.contents__view strong {
font-weight: 600;
}
.contents__view hr {
height: 0;
margin: 15px 0;
overflow: hidden;
background: transparent;
border: 0;
border-bottom: 1px solid #dfe2e5;
}
.contents__view hr::before {
display: table;
content: "";
}
.contents__view hr::after {
display: table;
clear: both;
content: "";
}
.contents__view table {
border-spacing: 0;
border-collapse: collapse;
}
.contents__view td,
.contents__view th {
padding: 0;
}
.contents__view h1,
.contents__view h2,
.contents__view h3,
.contents__view h4,
.contents__view h5,
.contents__view h6 {
margin-top: 0;
margin-bottom: 0;
}
.contents__view h1 {
font-size: 32px;
font-weight: 600;
}
.contents__view h2 {
font-size: 24px;
font-weight: 600;
}
.contents__view h3 {
font-size: 20px;
font-weight: 600;
}
.contents__view h4 {
font-size: 16px;
font-weight: 600;
}
.contents__view h5 {
font-size: 14px;
font-weight: 600;
}
.contents__view h6 {
font-size: 12px;
font-weight: 600;
}
.contents__view p {
margin-top: 0;
margin-bottom: 10px;
}
.contents__view blockquote {
margin: 0;
}
.contents__view ul,
.contents__view ol {
padding-left: 0;
margin-top: 0;
margin-bottom: 0;
}
.contents__view ol ol,
.contents__view ul ol {
list-style-type: lower-roman;
}
.contents__view ul ul ol,
.contents__view ul ol ol,
.contents__view ol ul ol,
.contents__view ol ol ol {
list-style-type: lower-alpha;
}
.contents__view dd {
margin-left: 0;
}
.contents__view code {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
}
.contents__view pre {
margin-top: 0;
margin-bottom: 0;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
}
.contents__view .octicon {
vertical-align: text-bottom;
}
.contents__view .pl-0 {
padding-left: 0 !important;
}
.contents__view .pl-1 {
padding-left: 4px !important;
}
.contents__view .pl-2 {
padding-left: 8px !important;
}
.contents__view .pl-3 {
padding-left: 16px !important;
}
.contents__view .pl-4 {
padding-left: 24px !important;
}
.contents__view .pl-5 {
padding-left: 32px !important;
}
.contents__view .pl-6 {
padding-left: 40px !important;
}
.contents__view::before {
display: table;
content: "";
}
.contents__view::after {
display: table;
clear: both;
content: "";
}
.contents__view>*:first-child {
margin-top: 0 !important;
}
.contents__view>*:last-child {
margin-bottom: 0 !important;
}
.contents__view a:not([href]) {
color: inherit;
text-decoration: none;
}
.contents__view .anchor {
float: left;
padding-right: 4px;
margin-left: -20px;
line-height: 1;
}
.contents__view .anchor:focus {
outline: none;
}
.contents__view p,
.contents__view blockquote,
.contents__view ul,
.contents__view ol,
.contents__view dl,
.contents__view table,
.contents__view pre {
margin-top: 0;
margin-bottom: 16px;
}
.contents__view hr {
height: 0.25em;
padding: 0;
margin: 24px 0;
background-color: #e1e4e8;
border: 0;
}
.contents__view blockquote {
padding: 0 1em;
color: #6a737d;
border-left: 0.25em solid #dfe2e5;
}
.contents__view blockquote>:first-child {
margin-top: 0;
}
.contents__view blockquote>:last-child {
margin-bottom: 0;
}
.contents__view kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #444d56;
vertical-align: middle;
background-color: #fafbfc;
border: solid 1px #c6cbd1;
border-bottom-color: #959da5;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #959da5;
}
.contents__view h1,
.contents__view h2,
.contents__view h3,
.contents__view h4,
.contents__view h5,
.contents__view h6 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: 600;
line-height: 1.25;
}
.contents__view h1 .octicon-link,
.contents__view h2 .octicon-link,
.contents__view h3 .octicon-link,
.contents__view h4 .octicon-link,
.contents__view h5 .octicon-link,
.contents__view h6 .octicon-link {
color: #1b1f23;
vertical-align: middle;
visibility: hidden;
}
.contents__view h1:hover .anchor,
.contents__view h2:hover .anchor,
.contents__view h3:hover .anchor,
.contents__view h4:hover .anchor,
.contents__view h5:hover .anchor,
.contents__view h6:hover .anchor {
text-decoration: none;
}
.contents__view h1:hover .anchor .octicon-link,
.contents__view h2:hover .anchor .octicon-link,
.contents__view h3:hover .anchor .octicon-link,
.contents__view h4:hover .anchor .octicon-link,
.contents__view h5:hover .anchor .octicon-link,
.contents__view h6:hover .anchor .octicon-link {
visibility: visible;
}
.contents__view h1 {
padding-bottom: 0.3em;
font-size: 2em;
border-bottom: 1px solid #eaecef;
}
.contents__view h2 {
padding-bottom: 0.3em;
font-size: 1.5em;
border-bottom: 1px solid #eaecef;
}
.contents__view h3 {
font-size: 1.25em;
}
.contents__view h4 {
font-size: 1em;
}
.contents__view h5 {
font-size: 0.875em;
}
.contents__view h6 {
font-size: 0.85em;
color: #6a737d;
}
.contents__view ul,
.contents__view ol {
padding-left: 2em;
}
.contents__view ul ul,
.contents__view ul ol,
.contents__view ol ol,
.contents__view ol ul {
margin-top: 0;
margin-bottom: 0;
}
.contents__view li {
word-wrap: break-all;
}
.contents__view li>p {
margin-top: 16px;
}
.contents__view li+li {
margin-top: 0.25em;
}
.contents__view dl {
padding: 0;
}
.contents__view dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: 600;
}
.contents__view dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.contents__view table {
display: block;
width: 100%;
overflow: auto;
}
.contents__view table th {
font-weight: 600;
}
.contents__view table th,
.contents__view table td {
padding: 6px 13px;
border: 1px solid #dfe2e5;
}
.contents__view table tr {
background-color: #fff;
border-top: 1px solid #c6cbd1;
}
.contents__view table tr:nth-child(2n) {
background-color: #f6f8fa;
}
.contents__view img {
max-width: 100%;
box-sizing: content-box;
background-color: #fff;
}
.contents__view img[align=right] {
padding-left: 20px;
}
.contents__view img[align=left] {
padding-right: 20px;
}
/* .contents__view code {
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27,31,35,0.05);
border-radius: 3px;
}
.contents__view pre {
word-wrap: normal;
}
.contents__view pre>code {
padding: 0;
margin: 0;
font-size: 100%;
word-break: normal;
white-space: pre;
background: transparent;
border: 0;
}*/
.contents__view .highlight {
margin-bottom: 16px;
}
.contents__view .highlight pre {
margin-bottom: 0;
word-break: normal;
}
/*.contents__view .highlight pre,
.contents__view pre {
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
background-color: #f6f8fa;
border-radius: 3px;
}
.contents__view pre code {
display: inline;
max-width: auto;
padding: 0;
margin: 0;
overflow: visible;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}*/
.contents__view .full-commit .btn-outline:not(:disabled):hover {
color: #005cc5;
border-color: #005cc5;
}
.contents__view kbd {
display: inline-block;
padding: 3px 5px;
font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
line-height: 10px;
color: #444d56;
vertical-align: middle;
background-color: #fafbfc;
border: solid 1px #d1d5da;
border-bottom-color: #c6cbd1;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #c6cbd1;
}
.contents__view :checked+.radio-label {
position: relative;
z-index: 1;
border-color: #0366d6;
}
.contents__view .task-list-item {
list-style-type: none;
}
.contents__view .task-list-item+.task-list-item {
margin-top: 3px;
}
.contents__view .task-list-item input {
margin: 0 0.2em 0.25em -1.6em;
vertical-align: middle;
}
.contents__view hr {
border-bottom-color: #eee;
}
</style>
<template>
<el-header style="display: flex;align-items:center;border-bottom: 1px solid #eee;">
<span style="margin-right: 30px;">TEMPO MEMO</span>
<el-radio-group v-model="tabPosition" size="small" style="margin-right: 30px" @input="changeMode">
<el-radio-button label="edit"><i class="el-icon-edit"></i></el-radio-button>
<el-radio-button label="editview"><i class="el-icon-edit"></i><i class="el-icon-view"></i></el-radio-button>
<el-radio-button label="view"><i class="el-icon-view"></i></el-radio-button>
</el-radio-group>
<div class="subMenu">
<el-button type="warning" round size="medium" icon="el-icon-plus" @click="addMemo" :disabled="Object.keys(memos).length > 9">新規作成</el-button>
<el-button icon="el-icon-download" circle size="medium" style="margin-left: 30px" @click="textDownload" id="download" download="markdown.txt" href="#"></el-button>
<span v-if="isLogin" style="margin-left: 30px;">{{user.displayName}}さん</span>
<el-button type="text" size="medium" style="margin-left: 30px" @click="$emit('formVisible',true)" v-else>ログイン</el-button>
<el-dropdown style="margin-left: 30px" @command="handleCommand">
<i class="el-icon-setting"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="logout" v-if="isLogin">ログアウト</el-dropdown-item>
<el-dropdown-item command="signup" v-else>Googleアカウントでログイン</el-dropdown-item>
<el-dropdown-item><nuxt-link to="/help">ヘルプ</nuxt-link></el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-header>
</template>
<script>
export default {
data() {
return {
tabPosition: 'edit',
};
},
props: ["viewMode","dialogFormVisible","isLogin"],
computed: {
user() {
return this.$store.getters.user;
},
memos() {
return this.$store.getters.memos;
}
},
methods:{
//編集モードを切り替えた時、親の関数viewChangeに渡す
changeMode: function(type){
   this.$emit('viewChange',type);
localStorage.setItem('tempoMemo_style', type);
  },
//新規作成ボタンを押した時
addMemo: function () {
let memo = {
title: "未設定",
content: "",
userId: this.user.uid,
updateDate: new Date()
}
this.$store.dispatch('addMemo',memo)
},
//elementのdropdown(ログイン、ログアウトを押した時)、commandで判断して処理を分ける
handleCommand(command) {
if(command == "signup"){
this.$store.dispatch('userCheck',true);
}else if(command == "logout"){
this.$store.dispatch('userCheck',false);
}
},
//jsonダウンロード押した時
textDownload: function () {
var csv = this.$store.getters.memos;
let blob = new Blob([JSON.stringify(csv, null, ' ')], { type: 'application/json' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'markdown.json'
link.click()
}
},
created: function () {
//ログイン中か否か確認のためVuexのonAuth
this.$store.dispatch('onAuth');
//編集モードをlocalStorageから取得
if(localStorage.getItem('tempoMemo_style')){
this.tabPosition = localStorage.getItem('tempoMemo_style');
this.$emit('viewChange',this.tabPosition);
}else{
this.tabPosition = this.viewMode;
}
}
};
</script>
<style scoped>
i[class^=el-icon] {
font-size: 18px;
}
.subMenu {
flex-grow:1;
text-align: right;
}
.subMenu i {
font-size: 20px;
}
.el-dropdown {
vertical-align: middle;
}
.subMenu .el-button.el-button--medium {
font-size: 14px;
}
.subMenu .el-button.el-button--medium i {
font-size: 14px;
}
.el-dropdown-menu__item a {
display: block;
text-decoration: none;
color: inherit;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment