intro modal & textareas
This commit is contained in:
parent
cb1a8a1705
commit
889032a54d
7 changed files with 370 additions and 128 deletions
80
icons/intro.svg
Normal file
80
icons/intro.svg
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 32 32.000001"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||||
|
sodipodi:docname="intro.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#808080"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="11.2"
|
||||||
|
inkscape:cx="34.955357"
|
||||||
|
inkscape:cy="15.625"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1053"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#808080"
|
||||||
|
showguides="true" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1090.5197)">
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:none;stroke:#ffffff;stroke-width:1.33746;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
id="path8463"
|
||||||
|
cx="21.428558"
|
||||||
|
cy="1106.5197"
|
||||||
|
r="9.5965786" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.768293;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
id="rect8569"
|
||||||
|
width="1.7928504"
|
||||||
|
height="6.1344175"
|
||||||
|
x="20.532131"
|
||||||
|
y="1105.6642" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:none;stroke:#ffffff;stroke-width:1.36366;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
id="path8573"
|
||||||
|
cx="21.428558"
|
||||||
|
cy="1102.4698"
|
||||||
|
r="0.67988187" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
66
icons/start.svg
Normal file
66
icons/start.svg
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 32 32.000001"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||||
|
sodipodi:docname="start.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#808080"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="11.2"
|
||||||
|
inkscape:cx="24.508929"
|
||||||
|
inkscape:cy="12.857143"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1053"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#808080"
|
||||||
|
showguides="true" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1090.5197)">
|
||||||
|
<path
|
||||||
|
id="rect314"
|
||||||
|
style="fill:#ffffff;stroke:#ffffff;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
d="m 8.4841806,1098.0389 16.9962374,8.4808 -16.9962374,8.4807 z"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2 KiB |
|
@ -8,7 +8,7 @@
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg8"
|
id="svg8"
|
||||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||||
sodipodi:docname="tongue.svg"
|
sodipodi:docname="tung.svg"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -26,8 +26,8 @@
|
||||||
inkscape:pageopacity="0"
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="11.2"
|
inkscape:zoom="11.2"
|
||||||
inkscape:cx="10.044643"
|
inkscape:cx="24.508929"
|
||||||
inkscape:cy="14.553571"
|
inkscape:cy="12.857143"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:current-layer="layer1"
|
inkscape:current-layer="layer1"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
|
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
92
index.html
92
index.html
|
@ -3,12 +3,13 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="interactive-widget=resizes-content, width=device-width, initial-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="interactive-widget=resizes-content, width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
|
<!-- <meta name="virtual-keyboard" content="resize-layout" /> future feature? -->
|
||||||
<meta name="google" content="notranslate" />
|
<meta name="google" content="notranslate" />
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="icons/tung.svg">
|
<link rel="apple-touch-icon" sizes="180x180" href="icons/tung.svg">
|
||||||
<link rel="icon" type="image/svg+xml" sizes="any" href="icons/tung.svg">
|
<link rel="icon" type="image/svg+xml" sizes="any" href="icons/tung.svg">
|
||||||
<link rel="manifest" href="manifest.webmanifest">
|
<link rel="manifest" href="manifest.webmanifest">
|
||||||
<meta name="description" content="Augment your keyboard with the symbols you need to type in your language.">
|
<meta name="description" content="Easily augment your system's keyboard">
|
||||||
<meta name="author" content="Ethan Merchant">
|
<meta name="author" content="Ethan Merchant">
|
||||||
<title style="display: none;">tung-tap</title>
|
<title style="display: none;">tung-tap</title>
|
||||||
<link rel="stylesheet" href="style.css?v1">
|
<link rel="stylesheet" href="style.css?v1">
|
||||||
|
@ -18,23 +19,28 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<!-- <div id="home" style="
|
<dialog id="intro" style="
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 10px 20px;
|
padding: 10px 32px;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
background-color: #79394f;
|
background-color: rgb(var(--field));
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: rgb(var(--txt));
|
||||||
|
border-radius: var(--key-radius);
|
||||||
|
font-size: 24px;
|
||||||
|
z-index: -1;
|
||||||
">
|
">
|
||||||
<div style="
|
<!-- <div style="
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
">
|
">
|
||||||
<img src="icons/tongue.png" style="
|
<img src="icons/tung.png" style="
|
||||||
width: 32px; height: 32px;
|
width: 32px; height: 32px;
|
||||||
transform: translateY(-5px) rotate(-5deg);
|
transform: translateY(-5px) rotate(-5deg);
|
||||||
">
|
">
|
||||||
|
@ -43,30 +49,54 @@
|
||||||
margin-right: -40px;
|
margin-right: -40px;
|
||||||
transform: translate(-32px, 7px) rotate(-45deg) scale(0.8);
|
transform: translate(-32px, 7px) rotate(-45deg) scale(0.8);
|
||||||
">
|
">
|
||||||
<h1 style="font-weight: unset; font-size: 24px; line-height: 24px; margin: 0; color: #fff">
|
</div> -->
|
||||||
TongueTap<span style="font-size: 14px; letter-spacing: 1px;">.app</span>
|
<h1 style="font-weight: unset; font-size: 32px; line-height: 32px; margin: 0; color: rgb(var(--txt));">
|
||||||
</h1>
|
tungtap<span style="font-size: 14px; letter-spacing: 1px;">.app</span>
|
||||||
</div>
|
</h1>
|
||||||
<p style="
|
<p style="
|
||||||
font-size: 14px;
|
font-size: 16px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
font-style: italic;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #fff;
|
color: rgb(var(--txt));
|
||||||
|
text-align: center;
|
||||||
">
|
">
|
||||||
Unicode key-swatch webapp for any cultures tongue!
|
easily augment your<br>
|
||||||
|
system's keyboard
|
||||||
</p>
|
</p>
|
||||||
</div> -->
|
|
||||||
|
<img onclick="intro.close()" class="icon-btn" src="/icons/start.svg" style="
|
||||||
|
outline: 2px solid white;
|
||||||
|
outline-offset: 6px;
|
||||||
|
border-radius: 18px;
|
||||||
|
margin: 16px;
|
||||||
|
mix-blend-mode: difference;
|
||||||
|
">
|
||||||
|
|
||||||
|
<div style="
|
||||||
|
position: fixed;
|
||||||
|
top: 100px;
|
||||||
|
right: 100px;
|
||||||
|
color: rgb(var(--txt));
|
||||||
|
">edit keys ↗</div>
|
||||||
|
|
||||||
|
<div style="
|
||||||
|
position: fixed;
|
||||||
|
bottom: 150px;
|
||||||
|
color: rgb(var(--txt));
|
||||||
|
">↙ tap keys ↘</div>
|
||||||
|
|
||||||
|
</dialog>
|
||||||
|
|
||||||
<div style="display: block; position: relative; background-color: white;">
|
<div style="display: block; position: relative; background-color: white;">
|
||||||
<div hidden="true" id="tung" onclick="layout()" oninput="layout()" contenteditable="true" spellcheck="false" style="
|
<textarea hidden="true" id="tung" onclick="layout()" oninput="layout()" spellcheck="false" style="
|
||||||
user-select: text;
|
user-select: text;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
overflow: none;
|
overflow: none;
|
||||||
|
|
||||||
|
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
width: auto;
|
width: 100%;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-family: 'DM Mono', monospace;
|
font-family: 'DM Mono', monospace;
|
||||||
|
@ -79,8 +109,8 @@
|
||||||
|
|
||||||
|
|
||||||
/* display: none; */
|
/* display: none; */
|
||||||
"></div>
|
"></textarea>
|
||||||
<div onclick="copyToClipboard('#tung')" style="
|
<div onclick="copyToClipboard('tung')" style="
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -105,12 +135,16 @@
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
">
|
">
|
||||||
<img onclick="$('#nav').toggle()" class="icon-btn" src="icons/tungs.svg">
|
<img onclick="$('#nav').toggle()" class="icon-btn" src="icons/tungs.svg">
|
||||||
<img onclick="TopToggle()" class="icon-btn" src="icons/tung.svg">
|
<div style="display: flex;">
|
||||||
|
<img onclick="intro.showModal()" class="icon-btn" src="icons/intro.svg">
|
||||||
|
<img onclick="TopToggle()" class="icon-btn" src="icons/tung.svg">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div style="flex-grow: 1; overflow: hidden; position: relative; background-color: white;">
|
<div style="flex-grow: 1; overflow: hidden; position: relative; background-color: white;">
|
||||||
<div id="text" onclick="$('#text').focus()" contenteditable="true" spellcheck="false" style="
|
<!-- onclick="$('#text').focus()" -->
|
||||||
|
<textarea id="text" spellcheck="false" style="
|
||||||
user-select: text;
|
user-select: text;
|
||||||
touch-action: pan-y;
|
touch-action: pan-y;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
@ -127,11 +161,9 @@
|
||||||
background-color: rgb(var(--field));
|
background-color: rgb(var(--field));
|
||||||
color: rgb(var(--txt));
|
color: rgb(var(--txt));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* padding-bottom: 600px; */
|
/* padding-bottom: 600px; */
|
||||||
"></div>
|
"></textarea>
|
||||||
<div onclick="copyToClipboard('#text')" style="
|
<div onclick="copyToClipboard('text')" style="
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -145,11 +177,11 @@
|
||||||
<div id="nav" hidden="true"></div>
|
<div id="nav" hidden="true"></div>
|
||||||
|
|
||||||
|
|
||||||
<div id="keyboard" onclick="$('#text').focus()"></div>
|
<div id="keyboard" onclick="text.focus()"></div>
|
||||||
|
|
||||||
|
|
||||||
<!-- safari disclaimer (centered vertically) -->
|
<!-- safari disclaimer (centered vertically) -->
|
||||||
<div id="disclaimer" hidden style="
|
<div id="disclaimer" style="
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
@ -169,7 +201,7 @@
|
||||||
<br>
|
<br>
|
||||||
Please use <span style="font-weight: bold;">Chrome</span> or <span style="font-weight: bold;">Firefox</span>.
|
Please use <span style="font-weight: bold;">Chrome</span> or <span style="font-weight: bold;">Firefox</span>.
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
87
script.js
87
script.js
|
@ -1,3 +1,6 @@
|
||||||
|
doc = document
|
||||||
|
elbyid = (id) => doc.getElementById(id)
|
||||||
|
|
||||||
var tung = ""
|
var tung = ""
|
||||||
|
|
||||||
var topToggle = false
|
var topToggle = false
|
||||||
|
@ -18,11 +21,13 @@ $(document).ready(() => {
|
||||||
if (localStorage.getItem('tung') === null || localStorage.getItem('tung') == "") {
|
if (localStorage.getItem('tung') === null || localStorage.getItem('tung') == "") {
|
||||||
tung = "201C 2014 00D7 00B0 00B7 2022 221E 00B1 2023 201D"
|
tung = "201C 2014 00D7 00B0 00B7 2022 221E 00B1 2023 201D"
|
||||||
localStorage.setItem('tung', tung)
|
localStorage.setItem('tung', tung)
|
||||||
|
|
||||||
|
intro.showModal()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tung = localStorage.getItem('tung')
|
tung = localStorage.getItem('tung')
|
||||||
}
|
}
|
||||||
$('#tung').html(tung)
|
elbyid('tung').value = tung
|
||||||
layout()
|
layout()
|
||||||
|
|
||||||
// persistent text
|
// persistent text
|
||||||
|
@ -30,7 +35,7 @@ $(document).ready(() => {
|
||||||
localStorage.setItem('text', "")
|
localStorage.setItem('text', "")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#text').html(localStorage.getItem('text'))
|
elbyid('text').value = localStorage.getItem('text')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,11 +157,9 @@ function nav() {
|
||||||
background-color: #ff79a1;
|
background-color: #ff79a1;
|
||||||
color: #79394f;
|
color: #79394f;
|
||||||
">
|
">
|
||||||
Find more character codes in
|
Find more character codes
|
||||||
<a target="_blank" href="https://unicode.org/charts/">unicode.org</a>
|
in the <a target="_blank" href="https://unicode.org/charts/">unicode.org</a> reference charts
|
||||||
reference charts
|
or by sketching in a drawbox search at <a target="_blank" href="https://shapecatcher.com/">shapecatcher.com</a>!
|
||||||
or sketching in <a target="_blank" href="https://shapecatcher.com/">shapecatcher.com</a>
|
|
||||||
drawbox search!
|
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
$('#nav').html(links + back + html)
|
$('#nav').html(links + back + html)
|
||||||
|
@ -175,7 +178,7 @@ var selected = null
|
||||||
function select(index, pick) {
|
function select(index, pick) {
|
||||||
let line = lines[index]
|
let line = lines[index]
|
||||||
if (pick) {
|
if (pick) {
|
||||||
$('#tung').html(line.split(':')[1].trim())
|
elbyid('tung').value = line.split(':')[1].trim()
|
||||||
layout()
|
layout()
|
||||||
selected = index
|
selected = index
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,7 +207,7 @@ function getLines(divId) {
|
||||||
|
|
||||||
function layout() {
|
function layout() {
|
||||||
// keymap (tung is the proprietary name)
|
// keymap (tung is the proprietary name)
|
||||||
let tungText = $('#tung').html() //.replace('\r\n', '\n')
|
let tungText = elbyid('tung').value //.replace('\r\n', '\n')
|
||||||
tungText = tungText.replace(/<div>/g, '\n').replace(/<\/div>/g, '')
|
tungText = tungText.replace(/<div>/g, '\n').replace(/<\/div>/g, '')
|
||||||
if (tung != tungText) {
|
if (tung != tungText) {
|
||||||
tung = tungText
|
tung = tungText
|
||||||
|
@ -246,21 +249,21 @@ function layout() {
|
||||||
// override default behavior
|
// override default behavior
|
||||||
key.preventDefault()
|
key.preventDefault()
|
||||||
|
|
||||||
// if text is not focused then set the cursor to the end of $('#text')
|
// if text is not focused then set the cursor to the end of #text
|
||||||
let textEl = $('#text')
|
// let textEl = elbyid('text')
|
||||||
if (document.activeElement != textEl[0] && window.getSelection().rangeCount == 0) {
|
// if (document.activeElement != textEl && window.getSelection().rangeCount == 0) {
|
||||||
let selection = window.getSelection()
|
// let selection = window.getSelection()
|
||||||
let range = document.createRange()
|
// let range = document.createRange()
|
||||||
range.selectNodeContents(textEl[0])
|
// range.selectNodeContents(textEl)
|
||||||
range.collapse(false)
|
// range.collapse(false)
|
||||||
selection.removeAllRanges()
|
// selection.removeAllRanges()
|
||||||
selection.addRange(range)
|
// selection.addRange(range)
|
||||||
}
|
// }
|
||||||
textEl.focus()
|
// textEl.focus()
|
||||||
|
|
||||||
// insert key character into contenteditable div $('#text') at cursor position
|
// insert key character at cursor position in textarea
|
||||||
let char = String.fromCharCode("0x" + $(key.target).attr('charcode'))
|
let char = String.fromCharCode("0x" + $(key.target).attr('charcode'))
|
||||||
insertTextAtCursor(char)
|
insertAtCursor(char)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,36 +272,31 @@ function layout() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insertAtCursor(text) {
|
||||||
|
const textarea = elbyid('text');
|
||||||
|
const scrollPos = textarea.scrollTop;
|
||||||
function insertTextAtCursor(text) {
|
const caretPos = textarea.selectionStart;
|
||||||
let selection = window.getSelection()
|
const front = textarea.value.substring(0, caretPos);
|
||||||
let range = selection.getRangeAt(0)
|
const back = textarea.value.substring(textarea.selectionEnd, textarea.value.length);
|
||||||
range.deleteContents()
|
textarea.value = front + text + back;
|
||||||
let node = document.createTextNode(text)
|
textarea.selectionStart = caretPos + text.length;
|
||||||
range.insertNode(node)
|
textarea.selectionEnd = caretPos + text.length;
|
||||||
range.setStartAfter(node)
|
textarea.scrollTop = scrollPos;
|
||||||
range.setEndAfter(node)
|
textarea.focus();
|
||||||
selection.removeAllRanges()
|
|
||||||
selection.addRange(range)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyToClipboard(id) {
|
function copyToClipboard(id) {
|
||||||
var textEl = $(id)
|
var textarea = elbyid(id)
|
||||||
|
|
||||||
// select all the text on the contenteditable div textEl to show it was copied
|
// select all the text in the textarea to show it was copied
|
||||||
let selection = window.getSelection()
|
// textarea.focus()
|
||||||
let range = document.createRange()
|
textarea.select()
|
||||||
range.selectNodeContents(textEl[0])
|
|
||||||
selection.removeAllRanges()
|
|
||||||
selection.addRange(range)
|
|
||||||
|
|
||||||
if (!navigator.clipboard) {
|
if (!navigator.clipboard) {
|
||||||
console.error('Clipboard API not supported');
|
console.error('Clipboard API not supported');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigator.clipboard.writeText(textEl.html())
|
navigator.clipboard.writeText(textarea.value)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('Text copied to clipboard')
|
console.log('Text copied to clipboard')
|
||||||
})
|
})
|
||||||
|
@ -358,8 +356,9 @@ function loop(timestamp) {
|
||||||
|
|
||||||
|
|
||||||
// check if need to backup the text
|
// check if need to backup the text
|
||||||
let text = $('#text').html()
|
let text = elbyid('text').value
|
||||||
if (text != lastText) {
|
if (text != lastText) {
|
||||||
|
console.log(text)
|
||||||
localStorage.setItem('text', text)
|
localStorage.setItem('text', text)
|
||||||
lastText = text
|
lastText = text
|
||||||
}
|
}
|
||||||
|
|
13
style.css
13
style.css
|
@ -12,6 +12,8 @@
|
||||||
/* all: unset; */
|
/* all: unset; */
|
||||||
outline: none;
|
outline: none;
|
||||||
/* box-sizing: border-box; */
|
/* box-sizing: border-box; */
|
||||||
|
font-family: 'Atkinson Hyperlegible', sans-serif;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +37,8 @@ html {
|
||||||
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
height: 100dvh;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -53,6 +57,8 @@ body {
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
|
|
||||||
|
height: 100dvh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hide scrollbar */
|
/* hide scrollbar */
|
||||||
|
@ -118,8 +124,7 @@ a {
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* textarea {
|
textarea {
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
padding: 1.5rem 1rem;
|
padding: 1.5rem 1rem;
|
||||||
|
@ -134,11 +139,9 @@ a {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
|
||||||
height: -webkit-fill-available;
|
|
||||||
|
|
||||||
background-color: rgb(var(--field));
|
background-color: rgb(var(--field));
|
||||||
color: rgb(var(--txt));
|
color: rgb(var(--txt));
|
||||||
} */
|
}
|
||||||
|
|
||||||
#keyboard {
|
#keyboard {
|
||||||
display: block;
|
display: block;
|
||||||
|
|
154
test/index.html
154
test/index.html
|
@ -3,56 +3,118 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
|
<style>
|
||||||
|
/* html, body {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 2048px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #79394f;
|
||||||
|
color: #fff;
|
||||||
|
font-family: sans-serif;
|
||||||
|
} */
|
||||||
|
|
||||||
|
#layoutViewport {
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
#bottombar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: -20px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: red;
|
||||||
|
transform-origin: left bottom;
|
||||||
|
transform: translate(0px, 0px) scale(1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<title style="display: none;">test</title>
|
<title style="display: none;">test</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<textarea id="text" rows="10" style="width: 100%;" onclick="">test</textarea>
|
<textarea id="text" rows="10" style="width: 100%; box-sizing: border-box;" onclick="">test</textarea>
|
||||||
<div id="shelf"></div>
|
|
||||||
|
<div id="bottombar">This stays stuck to the visual viewport</div>
|
||||||
|
<div id="forcescrolling"></div>
|
||||||
|
<div id="layoutViewport"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// setInterval(() => {
|
||||||
|
// let docHeight = document.documentElement.clientHeight
|
||||||
|
// // docHeight = window.innerHeight
|
||||||
|
// let kbHeight = docHeight - window.visualViewport.height
|
||||||
|
|
||||||
|
// // relative to ICB
|
||||||
|
// // window.visualViewport.pageTop
|
||||||
|
|
||||||
|
// // relative to LayoutViewport
|
||||||
|
// // window.visualViewport.offsetTop
|
||||||
|
|
||||||
|
// // kbHeight -= 1
|
||||||
|
|
||||||
|
// // document.getElementById('text').style.height = (window.visualViewport.height - kbHeight) + 'px'
|
||||||
|
// // document.getElementById('shelf').style.top = window.visualViewport.height + window.visualViewport.pageTop - 32 + 'px'
|
||||||
|
|
||||||
|
// // document.getElementById('shelf').style.top = window.visualViewport.pageTop + 'px'
|
||||||
|
// // document.getElementById('shelf').style.height = window.visualViewport.height + 'px'
|
||||||
|
// }, 60)
|
||||||
|
|
||||||
|
// window.visualViewport.addEventListener('resize', () => {
|
||||||
|
// document.getElementById('shelf').style.top = window.visualViewport.height - 32 + 'px'
|
||||||
|
// })
|
||||||
|
|
||||||
|
// // on scroll
|
||||||
|
// window.visualViewport.addEventListener('scroll', () => {
|
||||||
|
// })
|
||||||
|
|
||||||
|
// function selectText() {
|
||||||
|
// // flash the textarea to stop ios from scrolling
|
||||||
|
// let textarea = document.querySelector('textarea')
|
||||||
|
// textarea.style.display = 'none'
|
||||||
|
// setTimeout(() => {
|
||||||
|
// textarea.style.display = 'block'
|
||||||
|
// // select the text
|
||||||
|
// textarea.select()
|
||||||
|
// }, 10)
|
||||||
|
// }
|
||||||
|
|
||||||
|
const bottomBar = document.getElementById("bottombar");
|
||||||
|
const layoutViewport = document.getElementById("layoutViewport");
|
||||||
|
|
||||||
|
let pendingUpdate = false;
|
||||||
|
function viewportHandler(event) {
|
||||||
|
if (pendingUpdate) return;
|
||||||
|
pendingUpdate = true;
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
pendingUpdate = false;
|
||||||
|
|
||||||
|
// Since the bar is position: fixed we need to offset it by the
|
||||||
|
// visual viewport's offset from the layout viewport origin.
|
||||||
|
const viewport = event.target;
|
||||||
|
const offsetLeft = viewport.offsetLeft;
|
||||||
|
const offsetTop =
|
||||||
|
viewport.height -
|
||||||
|
layoutViewport.getBoundingClientRect().height +
|
||||||
|
viewport.offsetTop;
|
||||||
|
|
||||||
|
// You could also do this by setting style.left and style.top if you
|
||||||
|
// use width: 100% instead.
|
||||||
|
bottomBar.style.transform = `translate(${offsetLeft}px, ${offsetTop}px) scale(${
|
||||||
|
1 / viewport.scale
|
||||||
|
})`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.visualViewport.addEventListener('scroll', viewportHandler);
|
||||||
|
window.visualViewport.addEventListener('resize', viewportHandler);
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<script>
|
|
||||||
setInterval(() => {
|
|
||||||
let kbHeight = window.innerHeight - window.visualViewport.height
|
|
||||||
kbHeight -= 1
|
|
||||||
|
|
||||||
document.getElementById('shelf').style.bottom = kbHeight + 'px'
|
|
||||||
// document.getElementById('text').style.height = (window.visualViewport.height - kbHeight) + 'px'
|
|
||||||
}, 10)
|
|
||||||
|
|
||||||
// function selectText() {
|
|
||||||
// // flash the textarea to stop ios from scrolling
|
|
||||||
// let textarea = document.querySelector('textarea')
|
|
||||||
// textarea.style.display = 'none'
|
|
||||||
// setTimeout(() => {
|
|
||||||
// textarea.style.display = 'block'
|
|
||||||
// // select the text
|
|
||||||
// textarea.select()
|
|
||||||
// }, 10)
|
|
||||||
// }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
html, body {
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
background-color: #79394f;
|
|
||||||
color: #fff;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
#shelf {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%; height: 10px;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: magenta;
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Add table
Reference in a new issue