|
<html> |
|
|
|
<head> |
|
<title>Itoma v0.3.3</title> |
|
<meta charset="utf-8" /> |
|
|
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> |
|
<!-- |
|
<script src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script> |
|
--> |
|
<script type="module"> |
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; |
|
import zenuml from 'https://cdn.jsdelivr.net/npm/@mermaid-js/[email protected]/dist/mermaid-zenuml.esm.min.mjs'; |
|
mermaid.initialize({ startOnLoad: false }); |
|
await mermaid.registerExternalDiagrams([zenuml]); |
|
globalThis.mermaid = mermaid; |
|
</script> |
|
|
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" |
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"> |
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css"> |
|
<!-- |
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github.min.css"> |
|
--> |
|
|
|
<style> |
|
body.light-mode { |
|
--bg-color: #fdfdfd; |
|
--color: #111111; |
|
--viewer-header-color: rgba(20,20,20,0.2); |
|
--btn-color: #333333; |
|
--btn-hover-color: #e1e1e1; |
|
--btn-disable-color: #aaaaaa; |
|
--btn_embed-border-color: #bbb; |
|
--btn_float-color: rgba(0, 0, 0, 0.3); |
|
|
|
--btn_check-bg-color: #0d6efd; |
|
--input-bg-color: #f5f5f5; |
|
--input-border-color: #cccccc; |
|
|
|
--drawer-bg-color: rgba(0, 0, 0, 0.3); |
|
--drawer_content-bg-color: #fafafa; |
|
--drawer_remove-color: rgba(255, 0, 0, 0.7); |
|
--menu-hover-color: #eeeeee; |
|
--menu-border-color: #eeeeee; |
|
|
|
--nav-bg-color: #eeeeee; |
|
--nav-border-color: #cccccc; |
|
|
|
--splitter-color: #eeeeee; |
|
--splitter-hover-color: #0d6efd; |
|
|
|
--editor-bg-color: #fdfdfd; |
|
--editor-color: #111111; |
|
--viewer-bg-color: #fdfdfd; |
|
--html-bg-color: #ffffff; |
|
|
|
--modal-bg-color: #f5f5f5; |
|
--modal-border-color: #cccccc; |
|
--btn_appy-color: #0d6efd; |
|
|
|
--mode-change: background-color 0.5s, color 0.5s; |
|
|
|
--scroll-color: #aaaaaa; |
|
--scroll-hover-color: #999999; |
|
--scroll-bg-color: #cccccc; |
|
} |
|
|
|
body.dark-mode { |
|
--bg-color: #111111; |
|
--color: #e1e1e1; |
|
--viewer-header-color: rgba(240,240,240,0.2); |
|
--btn-color: #cccccc; |
|
--btn-hover-color: #444444; |
|
--btn-disable-color: #aaaaaa; |
|
--btn_embed-border-color: #666666; |
|
--btn_float-color: rgba(255, 255, 255, 0.3); |
|
|
|
--btn_check-bg-color: #000055; |
|
--input-bg-color: #444444; |
|
--input-border-color: #555555; |
|
|
|
--drawer-bg-color: rgba(0, 0, 0, 0.5); |
|
--drawer_content-bg-color: #222222; |
|
--drawer_remove-color: rgba(255, 0, 0, 0.5); |
|
--menu-hover-color: #292929; |
|
--menu-border-color: #333333; |
|
|
|
--nav-bg-color: #333333; |
|
--nav-border-color: #444444; |
|
|
|
--splitter-color: #333333; |
|
--splitter-hover-color: #000055; |
|
|
|
--editor-bg-color: #222222; |
|
--editor-color: #f1f1f1; |
|
--viewer-bg-color: #222222; |
|
--html-bg-color: #222222; |
|
|
|
--modal-bg-color: #222222; |
|
--modal-border-color: #333333; |
|
--btn_appy-color: #5daefd; |
|
|
|
--mode-change: background-color 0.2s, color 0.2s; |
|
|
|
--scroll-color: #393939; |
|
--scroll-hover-color: #444444; |
|
--scroll-bg-color: #292929; |
|
} |
|
|
|
body { |
|
background-color: var(--bg-color); |
|
color: var(--color); |
|
|
|
overflow: hidden; |
|
transition: var(--mode-change); |
|
} |
|
|
|
.itomaInput { |
|
background-color: var(--input-bg-color) !important; |
|
color: var(--color) !important; |
|
border: 1px solid var(--input-border-color) !important; |
|
transition: var(--mode-change); |
|
} |
|
|
|
#fileGroup>input { |
|
background-color: var(--input-bg-color) !important; |
|
color: var(--color) !important; |
|
|
|
border-top: 1px solid var(--input-border-color); |
|
border-bottom: 1px solid var(--input-border-color); |
|
border-right: 1px solid var(--input-border-color); |
|
border-left: 1px solid var(--input-border-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
#fileGroup>button { |
|
border-top: 1px solid var(--input-border-color); |
|
border-bottom: 1px solid var(--input-border-color); |
|
border-right: 1px solid var(--input-border-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
.btn { |
|
color: var(--btn-color); |
|
transition: var(--mode-change); |
|
} |
|
|
|
.btn:hover { |
|
background-color: var(--btn-hover-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
.btn:disabled { |
|
border: 0; |
|
color: var(--btn-disable-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
::-webkit-scrollbar { |
|
cursor: auto; |
|
width: 14px; |
|
} |
|
|
|
::-webkit-scrollbar-thumb { |
|
cursor: auto; |
|
background: var(--scroll-color); |
|
} |
|
|
|
::-webkit-scrollbar-thumb:hover { |
|
background: var(--scroll-hover-color); |
|
} |
|
|
|
::-webkit-scrollbar-track { |
|
background: var(--scroll-bg-color); |
|
} |
|
|
|
|
|
#nav { |
|
background-color: var(--nav-bg-color) !important; |
|
border-bottom: 1px solid var(--nav-border-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
#logo>a { |
|
margin-right: 0px; |
|
} |
|
|
|
#logo>span { |
|
font-size: 20px; |
|
margin-right: 20px; |
|
} |
|
|
|
#name { |
|
width: 300px; |
|
} |
|
|
|
#autoBtn { |
|
margin-top: 8px; |
|
background-color: var(--input-bg-color); |
|
border-color: var(--input-border-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
#autoBtn:checked { |
|
margin-top: 8px; |
|
background-color: var(--btn_check-bg-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
#drawer { |
|
background-color: var(--drawer-bg-color); |
|
width: 100vw; |
|
height: 100vh; |
|
min-width: 100vw; |
|
min-height: 100vh; |
|
margin: 0; |
|
padding: 0; |
|
|
|
transition: 0.2s; |
|
position: absolute; |
|
opacity: 0; |
|
visibility: hidden; |
|
z-index: 1000; |
|
} |
|
|
|
#drawer.show { |
|
transition: 0.5s; |
|
opacity: 1; |
|
visibility: visible; |
|
} |
|
|
|
#drawer>.row { |
|
height: 100vh; |
|
min-height: 100vh; |
|
margin: 0; |
|
padding: 0; |
|
} |
|
|
|
#drawerContent { |
|
margin: 0; |
|
padding: 0; |
|
} |
|
|
|
#drawerContent>ul { |
|
height: 100%; |
|
background-color: var(--drawer_content-bg-color); |
|
border-right: 1px solid var(--menu-border-color); |
|
} |
|
|
|
#drawerContent>ul>li { |
|
background-color: var(--drawer_content-bg-color); |
|
color: var(--color); |
|
border-radius: 0; |
|
border-top: 0; |
|
border-bottom: 1px solid var(--menu-border-color); |
|
border-right: 0; |
|
border-left: 0; |
|
} |
|
|
|
#drawerContent>ul>li:last-child { |
|
border-top: 1px solid var(--menu-border-color); |
|
border-bottom: 0; |
|
} |
|
|
|
.menuBtn { |
|
display: flex; |
|
flex-flow: row; |
|
cursor: pointer; |
|
} |
|
|
|
.menuBtn:hover { |
|
background-color: var(--menu-hover-color) !important; |
|
} |
|
|
|
.menuBtn>button { |
|
margin-left: auto; |
|
} |
|
|
|
.menuBtn>button>i { |
|
color: var(--drawer_remove-color); |
|
} |
|
|
|
#infoBtn { |
|
margin-top: auto; |
|
} |
|
|
|
|
|
#content { |
|
display: flex; |
|
flex-flow: row; |
|
width: 100vw; |
|
height: calc(100vh - 50px); |
|
} |
|
|
|
.editorStyle { |
|
resize: none; |
|
border: none; |
|
outline: none; |
|
|
|
padding: 10px; |
|
|
|
background-color: var(--editor-bg-color); |
|
color: var(--editor-color); |
|
|
|
} |
|
|
|
#editor { |
|
height: calc(100vh - 50px); |
|
width: calc(100% / 2 - 5px); |
|
transition: var(--mode-change); |
|
} |
|
|
|
#splitter { |
|
cursor: ew-resize; |
|
width: 10px; |
|
height: calc(100vh - 50px); |
|
border: none; |
|
background-color: var(--splitter-color); |
|
} |
|
|
|
#splitter:hover { |
|
transition: 0.5s; |
|
background-color: var(--splitter-hover-color); |
|
} |
|
|
|
#viewer { |
|
outline: none; |
|
width: calc(100% / 2 - 5px); |
|
height: 100%; |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
#messageContainer { |
|
z-index: 4000; |
|
} |
|
|
|
#message>div { |
|
display: flex; |
|
margin: 0px; |
|
} |
|
|
|
#message>div>i { |
|
font-size: 36px; |
|
} |
|
|
|
#message>div>span { |
|
margin-left: 20px; |
|
} |
|
|
|
#message>div>button { |
|
margin-top: 8px; |
|
margin-left: auto; |
|
} |
|
|
|
.modal>div>div.modal-content { |
|
background-color: var(--modal-bg-color); |
|
} |
|
|
|
.modal>div>div.modal-content>div.modal-header { |
|
border-bottom: 1px solid var(--modal-border-color); |
|
} |
|
|
|
.modal>div>div.modal-content>div.modal-body { |
|
min-height: 80px; |
|
} |
|
|
|
.modal>div>div.modal-content>div.modal-footer { |
|
border-top: 1px solid var(--modal-border-color); |
|
} |
|
|
|
.modal>div>div.modal-content>div.modal-footer>button { |
|
font-size: 24px; |
|
margin-left: 24px; |
|
} |
|
|
|
.modal>div>div.modal-content>div.modal-footer>button.apply { |
|
font-weight: bold; |
|
color: var(--btn_appy-color); |
|
} |
|
|
|
|
|
#editorFontText { |
|
width: 100%; |
|
} |
|
|
|
#viewerStyleText { |
|
width: 100%; |
|
min-height: 400px; |
|
} |
|
|
|
|
|
|
|
.htmlViewer { |
|
margin: 0; |
|
padding: 10px; |
|
background-color: var(--html-bg-color); |
|
overflow: auto; |
|
} |
|
|
|
#html { |
|
width: 100vw; |
|
height: 100vh; |
|
min-width: 100vw; |
|
min-height: 100vh; |
|
max-width: 100vw; |
|
max-height: 100vh; |
|
|
|
transition: 0.2s; |
|
position: absolute; |
|
opacity: 0; |
|
visibility: hidden; |
|
z-index: 2000; |
|
} |
|
|
|
#editorFont { |
|
position: absolute; |
|
left: calc(100vw / 2 - 10px - 36px - 48px); |
|
bottom: 15px; |
|
font-size: 36px; |
|
color: var(--btn_float-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
#hidden { |
|
position: absolute; |
|
right: 28px; |
|
bottom: 15px; |
|
font-size: 36px; |
|
color: var(--btn_float-color); |
|
|
|
transition: var(--mode-change); |
|
} |
|
|
|
#html.show { |
|
transition: 0.5s; |
|
opacity: 1; |
|
visibility: visible; |
|
} |
|
|
|
#htmlController { |
|
position: absolute; |
|
right: 20px; |
|
bottom: 10px; |
|
|
|
border-radius: 10%; |
|
z-index: 3000; |
|
transition: 0.2s; |
|
|
|
opacity: 0; |
|
visibility: hidden; |
|
padding: 5px; |
|
} |
|
|
|
#htmlController>button { |
|
color: var(--btn_float-color); |
|
font-size: 36px; |
|
margin-left: 30px; |
|
} |
|
|
|
#htmlController.show { |
|
transition: 0.5s; |
|
opacity: 1; |
|
visibility: visible; |
|
} |
|
|
|
/** Added because "ZenUML" breaks the display **/ |
|
#zenuml-intersection-detector-container { |
|
overflow: hidden; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body class="dark-mode"> |
|
|
|
<div id="html" class="htmlViewer"></div> |
|
|
|
<!-- ファイルメニュー表示 --> |
|
<div id="drawer" class="container"> |
|
<div class="row"> |
|
<div class="col-4" id="drawerContent"> |
|
<ul class="list-group" id="history"> |
|
<li id="infoBtn" class="menuBtn list-group-item"> |
|
<i class="bi bi-info-square"></i> |
|
</li> |
|
</ul> |
|
</div> |
|
<div class="col-8" id="drawerBG"> </div> |
|
</div> |
|
</div> |
|
|
|
<button id="hidden" type="button" class="btn"> |
|
<i class="bi bi-filetype-html"></i> |
|
</button> |
|
|
|
<div id="htmlController"> |
|
<button type="button" class="btn btnLightDark"> |
|
<i class="bi bi-moon iconLightDark"></i> |
|
</button> |
|
<button id="htmlDownloadBtn" type="button" class="btn"> |
|
<i class="bi bi-download"></i> |
|
</button> |
|
<button id="htmlCloseBtn" type="button" class="btn"> |
|
<i class="bi bi-box-arrow-right"></i> |
|
</button> |
|
</div> |
|
|
|
<!-- ナビゲーション表示 --> |
|
<nav id="nav" class="navbar bg-body-tertiary"> |
|
<div class="container-fluid"> |
|
<div class="row g-3"> |
|
<div id="logo" class="col-auto"> |
|
<a class="navbar-brand" href="#"> |
|
<button type="button" class="btn" id="drawerBtn"> |
|
<i class="bi bi-list"></i> |
|
</button> |
|
</a> |
|
<span>Itoma</span> |
|
</div> |
|
|
|
<div class="col-auto"> |
|
<div id="fileGroup" class="input-group"> |
|
<input type="text" id="name" class="form-control form-control-sm" placeholder="History name" |
|
value="Itoma.md"> |
|
<button type="button" class="btn" id="saveBtn"> |
|
<i class="bi bi-floppy"></i> |
|
</button> |
|
</div> |
|
</div> |
|
|
|
<div class="col-auto"> |
|
<div class="form-check form-switch"> |
|
<input class="form-check-input" type="checkbox" role="switch" id="autoBtn" data-bs-toggle="tooltip" |
|
data-bs-placement="bottom" data-bs-title="Auto Save" checked> |
|
</div> |
|
</div> |
|
|
|
<div class="col-auto"> |
|
<button type="button" class="btn" id="downloadBtn"> |
|
<i class="bi bi-download"></i> |
|
</button> |
|
</div> |
|
|
|
</div> |
|
|
|
<div class="row g-3"> |
|
<div class="col-auto"> |
|
<button type="button" class="btn" id="styleBtn"> |
|
<i class="bi bi-filetype-css"></i> |
|
</button> |
|
</div> |
|
<div class="col-auto"> |
|
<button type="button" class="btn btnLightDark"> |
|
<i class="bi bi-moon iconLightDark"></i> |
|
</button> |
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
</nav> |
|
|
|
<!-- コンテンツ部分 --> |
|
<div id="content"> |
|
|
|
<!-- テキスト部分 --> |
|
<textarea id="editor" class="editorStyle"></textarea> |
|
|
|
<button id="editorFont" type="button" class="btn"> |
|
<i class="bi bi-fonts"></i> |
|
</button> |
|
|
|
<div id="splitter" draggable="true"> |
|
</div> |
|
|
|
<div id="viewer" class="htmlViewer"></div> |
|
</div> |
|
|
|
<!-- confirm dialog --> |
|
<div id="confirm" class="modal" tabindex="-1"> |
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title" id="modalTitle">Confirmation</h5> |
|
</div> |
|
<div class="modal-body"> |
|
<p id="confirmMsg">The current text is deleted and the history is loaded.</p> |
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn" data-bs-dismiss="modal"> |
|
<i class="bi bi-x-circle"></i> |
|
</button> |
|
<button type="button" class="btn apply" data-bs-dismiss="modal"> |
|
<i class="bi bi-check-circle"></i> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<!-- font setting --> |
|
<div id="editorFontStyle" class="modal" tabindex="-1" data-bs-backdrop="static"> |
|
|
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title">Editor Font Setting</h5> |
|
</div> |
|
<div class="modal-body"> |
|
|
|
<form class="row g-3"> |
|
|
|
<div class="col-auto"> |
|
<input type="text" class="form-control itomaInput" placeholder="FontName" id="fontName"> |
|
</div> |
|
|
|
<div class="col-auto"> |
|
<input type="text" class="form-control itomaInput" placeholder="Size" style="width:100px" id="fontSize"> |
|
</div> |
|
|
|
<div class="col-auto"> |
|
<input type="color" class="form-control form-control-color itomaInput" title="Choose font color" |
|
id="fontColor"> |
|
</div> |
|
|
|
<div class="col-auto"> |
|
<input type="color" class="form-control form-control-color itomaInput" title="Choose background color" |
|
id="fontBGColor"> |
|
</div> |
|
|
|
</form> |
|
|
|
<textarea class="editorStyle" rows="4" id="editorFontText"># Itoma |
|
Itoma is markdown viewer. |
|
This Area is Editor sample.</textarea> |
|
|
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn" data-bs-dismiss="modal"> |
|
<i class="bi bi-x-circle"></i> |
|
</button> |
|
|
|
<button type="button" class="btn" id="editorFontErase"> |
|
<i class="bi bi-eraser"></i> |
|
</button> |
|
|
|
<button type="button" class="btn apply" id="editorFontApply"> |
|
<i class="bi bi-check-circle"></i> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<!-- style setting --> |
|
<div id="viewerStyle" class="modal" tabindex="-1" data-bs-backdrop="static"> |
|
|
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
|
|
<div class="modal-header"> |
|
<h5 class="modal-title" id="modalTitle">Viewer Style Setting</h5> |
|
</div> |
|
|
|
<div class="modal-body"> |
|
<textarea class="editorStyle" id="viewerStyleText"></textarea> |
|
</div> |
|
|
|
<div class="modal-footer"> |
|
<button type="button" class="btn" data-bs-dismiss="modal"> |
|
<i class="bi bi-x-circle"></i> |
|
</button> |
|
|
|
<button type="button" class="btn apply" id="styleApply"> |
|
<i class="bi bi-check-circle"></i> |
|
</button> |
|
|
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<!-- message toast --> |
|
<div id="messageContainer" class="toast-container position-fixed bottom-0 end-0 p-3"> |
|
|
|
<div id="message" class="toast" role="alert" aria-live="assertive" aria-atomic="true"> |
|
|
|
<div class="alert" role="alert"> |
|
<i class="bi"></i> |
|
<span></span> |
|
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> |
|
</div> |
|
|
|
</div> |
|
</div> |
|
|
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" |
|
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" |
|
crossorigin="anonymous"></script> |
|
|
|
<script> |
|
|
|
//file limit 10kB |
|
const UploadMax = 1024 * 10; |
|
// viewer update sec |
|
const updateSec = 0.3; |
|
var changeTextTimeout = -1; |
|
|
|
//localStorage Header(key) |
|
const StorageHeader = "Itoma."; |
|
const historyLimit = 16; |
|
|
|
const saveMinite = 5; |
|
var saveTextInterval = -1; |
|
|
|
// currently displayed text(deciding whether to render) |
|
var nowText = ""; |
|
var nowId = ""; |
|
|
|
var nowWidth = 0; |
|
|
|
const innerStyle = document.createElement('style'); |
|
innerStyle.type = 'text/css'; |
|
innerStyle.textContent = ` |
|
.htmlViewer > h1 { |
|
border-bottom: 2px solid var(--viewer-header-color); |
|
} |
|
|
|
.htmlViewer > h2 { |
|
border-bottom: 1px solid var(--viewer-header-color); |
|
} |
|
`; |
|
document.head.appendChild(innerStyle); |
|
|
|
document.addEventListener("DOMContentLoaded", function (e) { |
|
|
|
//Added mermaid rendering |
|
const renderer = new marked.Renderer(); |
|
renderer.code = (code) => { |
|
if (code.lang == 'mermaid') { |
|
var text = code.text; |
|
return `<pre class="mermaid">${text}</pre>`; |
|
} |
|
return `<pre>${code.text}</pre>` |
|
//return '<pre><code>\n' + hljs.highlightAuto(code).value + '\n</code></pre>'; |
|
} |
|
marked.use({ renderer }); |
|
|
|
/** |
|
* Editor |
|
*/ |
|
const editor = document.querySelector("#editor"); |
|
const editorFontBtn = document.querySelector("#editorFont"); |
|
const viewer = document.querySelector("#viewer"); |
|
|
|
// editor text rendering |
|
const viewEditorText = () => { |
|
viewText(editor.value); |
|
} |
|
|
|
// text rendering |
|
const viewText = (val) => { |
|
if (nowText != val) { |
|
nowText = val; |
|
renderHTML(viewer,val); |
|
} |
|
changeTextTimeout = -1; |
|
} |
|
|
|
const renderHTML = (elm,val) => { |
|
var rtn = marked.marked(val); |
|
elm.innerHTML = rtn; |
|
mermaid.run(); |
|
} |
|
|
|
// Search for indented or interpolated strings in text |
|
const getIndentChar = (before) => { |
|
|
|
var rtn = {} |
|
rtn.indent = ""; |
|
rtn.char = ""; |
|
|
|
const last = before.lastIndexOf('\n') |
|
if (last === -1) { |
|
return rtn; |
|
} |
|
|
|
const line = before.substring(last + 1); |
|
|
|
for (let idx = 0; idx < line.length; ++idx) { |
|
var c = line[idx] |
|
console.log(c) |
|
if (c !== " ") { |
|
if (c === "-") { |
|
rtn.char = "- "; |
|
} else if (c === ">") { |
|
rtn.char = "> "; |
|
} else if (c === "1") { |
|
var c2 = line[idx + 1]; |
|
if (c2 === ".") { |
|
rtn.char = "1. "; |
|
} |
|
} |
|
break; |
|
} |
|
rtn.indent += " "; |
|
} |
|
return rtn |
|
} |
|
|
|
// Change the text in the editor(Enter) |
|
const changeEditorValue = () => { |
|
|
|
const val = editor.value; |
|
const start = editor.selectionStart; |
|
const end = editor.selectionEnd; |
|
|
|
const before = val.substring(0, start) |
|
const after = val.substring(end) |
|
|
|
var obj = getIndentChar(before); |
|
var add = "\n" + obj.indent + obj.char; |
|
|
|
editor.value = before + add + after; |
|
editor.selectionStart = start + add.length; |
|
editor.selectionEnd = start + add.length; |
|
} |
|
|
|
//Editor Input Event |
|
editor.addEventListener("keydown", function (e) { |
|
|
|
if (e.key === "Enter") { |
|
e.preventDefault(); |
|
changeEditorValue(); |
|
} |
|
|
|
// Wait for a certain period of time to display |
|
if (changeTextTimeout === -1) { |
|
viewEditorText(); |
|
changeTextTimeout = setTimeout(function () { |
|
changeTextTimeout = -1; |
|
}, updateSec * 1000); |
|
} else { |
|
clearTimeout(changeTextTimeout); |
|
changeTextTimeout = setTimeout(viewEditorText, updateSec * 1000); |
|
} |
|
}); |
|
|
|
editor.addEventListener("dragover", e => { |
|
e.preventDefault() |
|
//TODO Cursor? |
|
}); |
|
|
|
// dropping a file into the editor |
|
editor.addEventListener("drop", function (e) { |
|
const file = e.dataTransfer.files[0]; |
|
|
|
if (file === undefined) { |
|
return; |
|
} |
|
|
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
if (file.size > UploadMax) { |
|
showMessage("warning", `File size(${file.size}B) exceeds Limit(${UploadMax}B)`) |
|
return; |
|
} |
|
|
|
nameTxt.value = file.name; |
|
const reader = new FileReader(); |
|
|
|
reader.onload = function (e) { |
|
editor.value = e.target.result; |
|
viewText(editor.value); |
|
}; |
|
reader.readAsText(file); |
|
}); |
|
|
|
const createEditorStyle = (name, size, color, bgcolor) => { |
|
var editorStyle = {}; |
|
editorStyle.color = color; |
|
editorStyle.backgroundColor = bgcolor; |
|
editorStyle.fontFamily = name; |
|
editorStyle.fontSize = size; |
|
return editorStyle; |
|
}; |
|
|
|
const saveEditorStyle = (name, size, color, bgcolor) => { |
|
var editorStyle = createEditorStyle(name,size,color,bgcolor); |
|
localStorage.setItem(EditorStyleKey, JSON.stringify(editorStyle)); |
|
writeStyle(editor, editorStyle) |
|
} |
|
|
|
const fontModal = document.querySelector("#editorFontStyle"); |
|
const fontApply = fontModal.querySelector("#editorFontApply"); |
|
const fontErase = fontModal.querySelector("#editorFontErase"); |
|
const fontDialog = new bootstrap.Modal(fontModal); |
|
|
|
const fontName = fontModal.querySelector("#fontName"); |
|
const fontSize = fontModal.querySelector("#fontSize"); |
|
const fontColor = fontModal.querySelector("#fontColor"); |
|
const fontBGColor = fontModal.querySelector("#fontBGColor"); |
|
const fontEditor = fontModal.querySelector(".editorStyle"); |
|
|
|
function setDefaultColor(elm,val) { |
|
if ( val === null || val === "" ) { |
|
elm.value = "#000000"; |
|
elm.checked = true; |
|
} else { |
|
elm.value = val; |
|
elm.checked = false; |
|
} |
|
} |
|
|
|
function getDefaultColor(elm) { |
|
if ( !elm.checked ) { |
|
return elm.value; |
|
} |
|
return "" |
|
} |
|
|
|
function changeSampleEditorColor(e) { |
|
e.target.checked = false; |
|
var editorStyle = createEditorStyle(fontName.value, fontSize.value, |
|
getDefaultColor(fontColor), getDefaultColor(fontBGColor)); |
|
writeStyle(fontEditor, editorStyle); |
|
} |
|
|
|
fontName.addEventListener("change",changeSampleEditorColor); |
|
fontSize.addEventListener("change",changeSampleEditorColor); |
|
fontColor.addEventListener("change",changeSampleEditorColor); |
|
fontBGColor.addEventListener("change",changeSampleEditorColor); |
|
|
|
editorFontBtn.addEventListener("click", function () { |
|
var style = localStorage.getItem(EditorStyleKey); |
|
if (style !== null) { |
|
var s = JSON.parse(style); |
|
|
|
fontName.value = s.fontFamily; |
|
fontSize.value = s.fontSize; |
|
setDefaultColor(fontColor,s.color); |
|
setDefaultColor(fontBGColor,s.backgroundColor); |
|
|
|
writeStyle(fontEditor, s); |
|
} else { |
|
fontName.value = ""; |
|
fontSize.value = ""; |
|
setDefaultColor(fontColor,null); |
|
setDefaultColor(fontBGColor,null); |
|
} |
|
// open dialog |
|
fontDialog.show(); |
|
}); |
|
|
|
fontErase.addEventListener("click", function () { |
|
fontName.value = ""; |
|
fontSize.value = ""; |
|
setDefaultColor(fontColor,null); |
|
setDefaultColor(fontBGColor,null); |
|
writeStyle(fontEditor, createEditorStyle(null,null,null,null)); |
|
}); |
|
|
|
fontApply.addEventListener("click", function () { |
|
saveEditorStyle(fontName.value, fontSize.value, |
|
getDefaultColor(fontColor), getDefaultColor(fontBGColor)); |
|
fontDialog.hide(); |
|
}); |
|
|
|
/* |
|
* screen operation |
|
*/ |
|
const drawerBtn = document.querySelector("#drawerBtn"); |
|
const drawerBG = document.querySelector("#drawerBG"); |
|
const drawer = document.querySelector("#drawer"); |
|
const splitter = document.querySelector("#splitter"); |
|
|
|
// switch drawer |
|
const toggleDrawer = () => { |
|
drawer.classList.toggle("show"); |
|
} |
|
drawerBtn.addEventListener("click", toggleDrawer); |
|
drawerBG.addEventListener("click", toggleDrawer); |
|
|
|
// drag splitter |
|
const dragSplitter = (e) => { |
|
var w = e.clientX; |
|
if (w >= 100) { |
|
nowWidth = w; |
|
redrawEditor(w); |
|
} |
|
} |
|
splitter.addEventListener("dragover", e => e.preventDefault()); |
|
splitter.addEventListener("drag", dragSplitter); |
|
|
|
|
|
/** |
|
* Drawer Operation |
|
*/ |
|
const HistoryKey = StorageHeader + "history"; |
|
|
|
const getHistoryText = (id) => { |
|
var data = localStorage.getItem(StorageHeader + id); |
|
if (data === null) { |
|
data = ""; |
|
} |
|
return data; |
|
} |
|
|
|
const redrawEditor = (w) => { |
|
if (w >= 100) { |
|
editor.style.width = w + "px"; |
|
viewer.style.width = (window.innerWidth - (w + 10)) + "px"; |
|
editorFontBtn.style.left = (w - 48 - 36) + "px"; |
|
} |
|
} |
|
|
|
const openHistory = (obj) => { |
|
nameTxt.value = obj.name; |
|
var txt = getHistoryText(obj.id); |
|
editor.value = txt; |
|
} |
|
|
|
const removeHistory = (id) => { |
|
|
|
var history = getHistoryList(); |
|
var newHis = []; |
|
history.forEach((obj) => { |
|
if (id !== obj.id) { |
|
newHis.push(obj); |
|
} |
|
}) |
|
setHistoryList(newHis); |
|
localStorage.removeItem(StorageHeader + id); |
|
} |
|
|
|
const setHistoryList = (history) => { |
|
localStorage.setItem(HistoryKey, JSON.stringify(history)); |
|
} |
|
|
|
const getHistoryList = () => { |
|
var str = localStorage.getItem(HistoryKey); |
|
var history = []; |
|
if (str !== null && str !== "") { |
|
history = JSON.parse(str); |
|
} |
|
return history; |
|
} |
|
|
|
const drawHistoryMenu = () => { |
|
|
|
var historyUL = document.querySelector("#history"); |
|
var history = getHistoryList(); |
|
|
|
var lis = historyUL.querySelectorAll("li.history") |
|
lis.forEach((li) => { |
|
li.parentElement.removeChild(li); |
|
}); |
|
|
|
history.forEach((obj) => { |
|
|
|
var li = document.createElement("li"); |
|
li.classList.add("list-group-item"); |
|
li.classList.add("menuBtn"); |
|
li.classList.add("history"); |
|
li.setAttribute("data-id", obj.id); |
|
|
|
var d = new Date(Date.parse(obj.date)); |
|
|
|
var div = document.createElement("div"); |
|
div.textContent = d.toLocaleString() + ":" + obj.name; |
|
li.appendChild(div) |
|
|
|
var btn = document.createElement("button"); |
|
btn.setAttribute("type", "button") |
|
btn.classList.add("btn") |
|
var icon = document.createElement("i"); |
|
icon.classList.add("bi"); |
|
icon.classList.add("bi-trash"); |
|
btn.appendChild(icon); |
|
li.appendChild(btn) |
|
|
|
li.addEventListener("click", function (e) { |
|
showConfirm("The current text is deleted and the history is loaded.").then(function () { |
|
openHistory(obj); |
|
viewEditorText(); |
|
toggleDrawer(); |
|
}).catch((err) => { |
|
if (err) { |
|
console.error(err); |
|
showErrorMessage(err); |
|
} |
|
}); |
|
}); |
|
|
|
btn.addEventListener("click", function (e) { |
|
e.stopPropagation(); |
|
showConfirm("Delete history").then(function () { |
|
removeHistory(obj.id); |
|
drawHistoryMenu(); |
|
}); |
|
}); |
|
historyUL.prepend(li); |
|
}); |
|
|
|
var header = document.createElement("li") |
|
header.classList.add("list-group-item"); |
|
header.classList.add("history"); |
|
header.textContent = "History"; |
|
historyUL.prepend(header); |
|
} |
|
|
|
const saveHistory = (auto) => { |
|
|
|
var name = getName(); |
|
|
|
var txt = editor.value; |
|
var str = getHistoryText(nowId); |
|
|
|
if (str === txt) { |
|
showMessage("info", "No changes, so no saving."); |
|
return; |
|
} |
|
|
|
var str = localStorage.getItem(HistoryKey); |
|
var history = []; |
|
if (str !== null && str !== "") { |
|
history = JSON.parse(str); |
|
} |
|
|
|
var obj = {}; |
|
obj.name = name; |
|
obj.date = (new Date()).toISOString(); |
|
obj.id = self.crypto.randomUUID(); |
|
nowId = obj.id; |
|
|
|
history.push(obj); |
|
|
|
var newhis = []; |
|
var leng = history.length; |
|
for (var idx = 0; idx < leng; ++idx) { |
|
var obj = history[idx]; |
|
var remove = false; |
|
if ((leng - historyLimit) > idx) { |
|
remove = true; |
|
} |
|
|
|
if (remove) { |
|
localStorage.removeItem(StorageHeader + obj.id); |
|
} else { |
|
newhis.push(obj); |
|
} |
|
} |
|
|
|
setHistoryList(newhis); |
|
localStorage.setItem(StorageHeader + obj.id, txt); |
|
|
|
showMessage("success", "Save " + name); |
|
drawHistoryMenu(); |
|
} |
|
|
|
const info = document.querySelector("#infoBtn"); |
|
info.addEventListener("click", function (e) { |
|
viewText(versionText); |
|
toggleDrawer(); |
|
}); |
|
|
|
|
|
/** |
|
* Nav Operation |
|
*/ |
|
|
|
const nameTxt = document.querySelector("#name"); |
|
const getName = () => { |
|
var n = nameTxt.value; |
|
if (n === "") { |
|
n = "empty.md"; |
|
} |
|
return n; |
|
} |
|
|
|
const getNameExt = (ext) => { |
|
var n = getName(); |
|
var idx = n.lastIndexOf("\."); |
|
if (idx !== -1) { |
|
n = n.substring(0, idx); |
|
} |
|
return n + "." + ext; |
|
} |
|
|
|
const saveBtn = document.querySelector("#saveBtn"); |
|
saveBtn.addEventListener("click", function () { |
|
saveHistory(false); |
|
}); |
|
|
|
const setAutoSave = () => { |
|
saveTextInterval = setInterval(function (e) { |
|
saveHistory(true); |
|
}, 1000 * 60 * saveMinite); |
|
} |
|
|
|
const autoBtn = document.querySelector("#autoBtn"); |
|
autoBtn.addEventListener("change", function () { |
|
var autoSave = autoBtn.checked; |
|
showMessage("info", "Auto Save " + (autoSave ? "start" : "stop")); |
|
if (autoSave) { |
|
if (saveTextInterval !== -1) { |
|
clearInterval(saveTextInterval); |
|
} else { |
|
setAutoSave(); |
|
} |
|
} else { |
|
saveTextInterval = -1; |
|
} |
|
}); |
|
|
|
const downloadBtn = document.querySelector("#downloadBtn"); |
|
downloadBtn.addEventListener("click", function () { |
|
|
|
var n = getNameExt("md"); |
|
|
|
var text = editor.value; |
|
const blob = new Blob([text], { type: "text/plain" }); |
|
|
|
var url = URL.createObjectURL(blob); |
|
var a = document.createElement("a"); |
|
a.href = url; |
|
a.download = n; |
|
|
|
a.click(); |
|
}); |
|
|
|
// More on Light/Dark Mode later. |
|
|
|
|
|
const errModal = document.querySelector("#confirm"); |
|
const msgTxt = errModal.querySelector("#confirmMsg"); |
|
const dialog = new bootstrap.Modal(errModal); |
|
|
|
const showConfirmDialog = (msg, callback) => { |
|
msgTxt.textContent = msg; |
|
dialog.show(); |
|
|
|
var hidden = function () { |
|
|
|
//fade not work |
|
var elm = document.activeElement; |
|
if (elm.classList.contains("apply")) { |
|
callback(true) |
|
} else { |
|
callback(false) |
|
} |
|
|
|
errModal.removeEventListener("hidden.bs.modal", hidden); |
|
} |
|
|
|
errModal.addEventListener("hidden.bs.modal", hidden); |
|
} |
|
|
|
const toastElm = document.querySelector("#message"); |
|
var toast = new bootstrap.Toast(toastElm); |
|
|
|
const showToast = (auto, icon, alert, msg, stack) => { |
|
|
|
toast._config.delay = 3000; |
|
toast._config.autohide = auto; |
|
|
|
var frame = toastElm.querySelector("div"); |
|
frame.classList.remove(...frame.classList); |
|
frame.classList.add("alert", alert); |
|
|
|
var i = frame.querySelector("i"); |
|
i.classList.remove(...i.classList); |
|
i.classList.add("bi", icon); |
|
if (stack != undefined) { |
|
i.addEventListener("dblclick", function () { |
|
}); |
|
} |
|
|
|
var span = toastElm.querySelector("span"); |
|
span.textContent = msg; |
|
|
|
toast.show(); |
|
} |
|
|
|
const showErrorMessage = (err) => { |
|
showMessage("error", msg, stack); |
|
} |
|
|
|
const showMessage = (t, msg, stack) => { |
|
|
|
var auto = true; |
|
var icon = "bi-info-circle"; |
|
var alert = "alert-" + t; |
|
|
|
if (t === "success") { |
|
icon = "bi-check-circle"; |
|
} else if (t === "warning") { |
|
icon = "bi-exclamation-triangle"; |
|
auto = false; |
|
} else if (t === "error") { |
|
icon = "bi-exclamation-circle"; |
|
alert = "alert-danger"; |
|
auto = false; |
|
} |
|
|
|
showToast(auto, icon, alert, msg, stack); |
|
} |
|
|
|
showConfirm = async (msg) => { |
|
var p = new Promise((res, rej) => { |
|
try { |
|
showConfirmDialog(msg, function (ok) { |
|
if (ok) { |
|
res(); |
|
} else { |
|
rej(); |
|
} |
|
}) |
|
} catch (err) { |
|
console.warn(err); |
|
rej(err); |
|
} |
|
}); |
|
return p; |
|
} |
|
|
|
const html = document.querySelector("#html"); |
|
const hidden = document.querySelector("#hidden"); |
|
const cntl = document.querySelector("#htmlController"); |
|
|
|
const dwn = document.querySelector("#htmlDownloadBtn"); |
|
const back = document.querySelector("#htmlCloseBtn"); |
|
|
|
dwn.addEventListener("click", function (e) { |
|
cntl.classList.remove("show"); |
|
const blob = new Blob([document.documentElement.outerHTML], { type: 'text/html' }); |
|
const link = document.createElement('a'); |
|
link.href = URL.createObjectURL(blob); |
|
|
|
link.download = getNameExt("html"); |
|
link.click(); |
|
|
|
html.classList.remove("show"); |
|
}); |
|
|
|
back.addEventListener("click", function (e) { |
|
cntl.classList.remove("show"); |
|
html.classList.remove("show"); |
|
}) |
|
|
|
hidden.addEventListener("click", function (e) { |
|
|
|
renderHTML(html,editor.value); |
|
//html.innerHTML = viewer.innerHTML; |
|
|
|
cntl.classList.add("show"); |
|
html.classList.add("show"); |
|
}); |
|
|
|
const styleModal = document.querySelector("#viewerStyle"); |
|
const styleApply = styleModal.querySelector("#styleApply"); |
|
const styleText = styleModal.querySelector("#viewerStyleText"); |
|
const styleDialog = new bootstrap.Modal(styleModal); |
|
|
|
const styleBtn = document.querySelector("#styleBtn"); |
|
styleBtn.addEventListener("click",function() { |
|
styleText.value = innerStyle.textContent; |
|
styleDialog.show(); |
|
}); |
|
|
|
styleApply.addEventListener("click",function() { |
|
var val = styleText.value; |
|
|
|
var viewerStyleId = localStorage.getItem(ViewerStyleKey); |
|
localStorage.setItem(ViewerStyleKey + "." + viewerStyleId,val); |
|
|
|
innerStyle.textContent = val; |
|
styleDialog.hide(); |
|
}) |
|
|
|
const ldBtns = document.querySelectorAll(".btnLightDark"); |
|
const icons = document.querySelectorAll(".iconLightDark"); |
|
|
|
const changeLightDarkIcon = (icon, mode) => { |
|
if (mode === "light") { |
|
icon.classList.remove("bi-sun"); |
|
icon.classList.add("bi-moon"); |
|
} else { |
|
icon.classList.remove("bi-moon"); |
|
icon.classList.add("bi-sun"); |
|
} |
|
} |
|
|
|
const changeLightDarkAllIcon = (mode) => { |
|
icons.forEach((icon) => { |
|
changeLightDarkIcon(icon, mode); |
|
}) |
|
} |
|
|
|
const changeLightDark = () => { |
|
var list = document.body.classList; |
|
|
|
list.toggle("light-mode"); |
|
list.toggle("dark-mode"); |
|
|
|
var mode = "light"; |
|
if (list.contains("dark-mode")) { |
|
mode = "dark"; |
|
} |
|
|
|
localStorage.setItem(StorageHeader + "mode", mode); |
|
changeLightDarkAllIcon(mode); |
|
}; |
|
|
|
ldBtns.forEach((btn) => { |
|
btn.addEventListener("click", changeLightDark); |
|
}) |
|
|
|
const initializeLightDark = () => { |
|
|
|
//設定があるかを確認 |
|
var mode = localStorage.getItem(StorageHeader + "mode"); |
|
if (mode === null) { |
|
mode = "light"; |
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { |
|
mode = "dark"; |
|
} |
|
} |
|
|
|
document.body.classList.add(mode + "-mode"); |
|
if (mode === "light") { |
|
//初期値を消す |
|
document.body.classList.remove("dark-mode"); |
|
} |
|
changeLightDarkAllIcon(mode); |
|
} |
|
|
|
window.addEventListener("resize", function () { |
|
redrawEditor(nowWidth); |
|
var vendor = document.querySelector("#zenuml-intersection-detector-container"); |
|
if (vendor !== null) { |
|
vendor.style.width = "100vw"; |
|
} |
|
if ( html.classList.contains("show") ) { |
|
renderHTML(html,editor.value); |
|
} |
|
}); |
|
|
|
//Overwrite style object |
|
const writeStyle = (elm, obj) => { |
|
//Overwrite only existing keys |
|
Object.keys(obj).forEach((key) => { |
|
elm.style[key] = obj[key]; |
|
}) |
|
} |
|
|
|
const ViewerStyleKey = StorageHeader + "viewerStyle"; |
|
const ViewerStyleListKey = StorageHeader + "viewerStyleList"; |
|
const initializeViewerStyle = () => { |
|
|
|
var style = innerStyle.textContent; |
|
var viewerStyleId = localStorage.getItem(ViewerStyleKey); |
|
|
|
if ( viewerStyleId !== null ) { |
|
style = localStorage.getItem(ViewerStyleKey + "." + viewerStyleId); |
|
} else { |
|
//default setting |
|
var id = self.crypto.randomUUID(); |
|
var list = []; |
|
var obj = {}; |
|
obj.id = id; |
|
obj.name = "default"; |
|
list.push(obj); |
|
|
|
localStorage.setItem(ViewerStyleKey,id); |
|
localStorage.setItem(ViewerStyleListKey,list) |
|
localStorage.setItem(ViewerStyleKey + "." + id,style); |
|
} |
|
innerStyle.textContent = style; |
|
} |
|
|
|
const EditorStyleKey = StorageHeader + "editorStyle"; |
|
const initializeEditorStyle = () => { |
|
|
|
//キー値の取得 |
|
var fontStyle = localStorage.getItem(EditorStyleKey); |
|
if (fontStyle !== null) { |
|
writeStyle(editor, JSON.parse(fontStyle)); |
|
} |
|
} |
|
|
|
const initializeStyle = () => { |
|
initializeEditorStyle(); |
|
initializeViewerStyle(); |
|
} |
|
|
|
const initialize = () => { |
|
initializeLightDark(); |
|
initializeStyle(); |
|
|
|
editor.value = infoText; |
|
|
|
viewEditorText(); |
|
drawHistoryMenu(); |
|
setAutoSave(); |
|
} |
|
|
|
initialize(); |
|
}); |
|
|
|
var infoText = `# Itoma |
|
|
|
Itoma is markdown viewer. |
|
|
|
## Edit Text |
|
|
|
Write markdown. |
|
You can also drag and drop text files.(Limited to 10kB) |
|
|
|
## Download File |
|
|
|
There is no way to save the file itself, so please download and overwrite the edited text. |
|
|
|
## Download View File |
|
|
|
Press the button at the bottom right of the viewer to switch to HTML mode. |
|
Please download the HTML and use it. |
|
|
|
## Other |
|
|
|
#### History Save |
|
|
|
There is an auto-save feature so that you can use it even if you suddenly close your browser (once every 5 minutes). |
|
If the contents are the same, they will not be saved. |
|
The work state is saved as history (up to 16 times). |
|
|
|
To open it, select History from the menu. |
|
|
|
History is stored in localStorage. |
|
|
|
### Editor font |
|
|
|
You can change the font using the icon in the bottom right of the editor. |
|
|
|
The font name cannot be obtained, so please look it up and enter it yourself. |
|
e.g.) "Source Code Pro" "Fira Code" "Proggy Fonts" etc... |
|
If it's installed on your device, it should be applied. |
|
|
|
Once you specify a color, it cannot be changed in Light or Dark mode. |
|
|
|
To revert, press "Erase" to apply |
|
|
|
### Style Setting |
|
|
|
By default, the following is set. |
|
|
|
<pre class="css"> |
|
.htmlViewer > h1 { |
|
border-bottom: 2px solid var(--viewer-header-color); |
|
} |
|
|
|
.htmlViewer > h2 { |
|
border-bottom: 1px solid var(--viewer-header-color); |
|
} |
|
</pre> |
|
|
|
".htmlViewer" is where the HTML will be output. |
|
If you want to switch between light and dark modes.Please use "body.light-mode" and "body.dark-mode". |
|
Please refer to this file with development tools to check the currently set custom properties. |
|
|
|
For example, the following setting will change the color of the "ZenUML" comments. |
|
|
|
<pre class="css"> |
|
.zenuml .comments p { |
|
color: blue; |
|
} |
|
</pre> |
|
|
|
## Development |
|
|
|
The basic premise of Itoma is that it works with a single HTML file. |
|
I would like to split it into JS files and CSS files, but I am holding back and implementing it. |
|
` |
|
|
|
var versionText = ` |
|
# Itoma 0.3.3 |
|
|
|
|
|
## Mermaid version |
|
|
|
<pre class="mermaid"> |
|
info |
|
</pre> |
|
|
|
## Fixes(0.3.2 -> 0.3.3) |
|
|
|
- Switch between version information and initial display. |
|
- Added redrawing when resizing in HTML mode. |
|
|
|
## Fixes(0.3.1 -> 0.3.2) |
|
|
|
- Changed drawing in HTML mode from copy to render |
|
|
|
## Source |
|
|
|
https://gist.github.com/secondarykey/f7daf8da25c4b2384420bd190ac18245 |
|
|
|
` |
|
|
|
|
|
</script> |
|
</body> |
|
|
|
</html> |