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"
|
||||
id="svg8"
|
||||
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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -26,8 +26,8 @@
|
|||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="10.044643"
|
||||
inkscape:cy="14.553571"
|
||||
inkscape:cx="24.508929"
|
||||
inkscape:cy="12.857143"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
|
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
94
index.html
94
index.html
|
@ -3,12 +3,13 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<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" />
|
||||
|
||||
<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="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">
|
||||
<title style="display: none;">tung-tap</title>
|
||||
<link rel="stylesheet" href="style.css?v1">
|
||||
|
@ -19,22 +20,27 @@
|
|||
|
||||
<body>
|
||||
|
||||
<!-- <div id="home" style="
|
||||
<dialog id="intro" style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 20px;
|
||||
padding: 10px 32px;
|
||||
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;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
">
|
||||
<img src="icons/tongue.png" style="
|
||||
<img src="icons/tung.png" style="
|
||||
width: 32px; height: 32px;
|
||||
transform: translateY(-5px) rotate(-5deg);
|
||||
">
|
||||
|
@ -43,30 +49,54 @@
|
|||
margin-right: -40px;
|
||||
transform: translate(-32px, 7px) rotate(-45deg) scale(0.8);
|
||||
">
|
||||
<h1 style="font-weight: unset; font-size: 24px; line-height: 24px; margin: 0; color: #fff">
|
||||
TongueTap<span style="font-size: 14px; letter-spacing: 1px;">.app</span>
|
||||
</h1>
|
||||
</div>
|
||||
<p style="
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
font-style: italic;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
">
|
||||
Unicode key-swatch webapp for any cultures tongue!
|
||||
</p>
|
||||
</div> -->
|
||||
<h1 style="font-weight: unset; font-size: 32px; line-height: 32px; margin: 0; color: rgb(var(--txt));">
|
||||
tungtap<span style="font-size: 14px; letter-spacing: 1px;">.app</span>
|
||||
</h1>
|
||||
<p style="
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
|
||||
margin: 0;
|
||||
color: rgb(var(--txt));
|
||||
text-align: center;
|
||||
">
|
||||
easily augment your<br>
|
||||
system's keyboard
|
||||
</p>
|
||||
|
||||
<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 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;
|
||||
touch-action: none;
|
||||
overflow: none;
|
||||
|
||||
|
||||
white-space: pre;
|
||||
width: auto;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
font-family: 'DM Mono', monospace;
|
||||
|
@ -79,8 +109,8 @@
|
|||
|
||||
|
||||
/* display: none; */
|
||||
"></div>
|
||||
<div onclick="copyToClipboard('#tung')" style="
|
||||
"></textarea>
|
||||
<div onclick="copyToClipboard('tung')" style="
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
|
@ -105,12 +135,16 @@
|
|||
line-height: 40px;
|
||||
">
|
||||
<img onclick="$('#nav').toggle()" class="icon-btn" src="icons/tungs.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 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;
|
||||
touch-action: pan-y;
|
||||
overflow-y: scroll;
|
||||
|
@ -127,11 +161,9 @@
|
|||
background-color: rgb(var(--field));
|
||||
color: rgb(var(--txt));
|
||||
|
||||
|
||||
|
||||
/* padding-bottom: 600px; */
|
||||
"></div>
|
||||
<div onclick="copyToClipboard('#text')" style="
|
||||
"></textarea>
|
||||
<div onclick="copyToClipboard('text')" style="
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
|
@ -145,11 +177,11 @@
|
|||
<div id="nav" hidden="true"></div>
|
||||
|
||||
|
||||
<div id="keyboard" onclick="$('#text').focus()"></div>
|
||||
<div id="keyboard" onclick="text.focus()"></div>
|
||||
|
||||
|
||||
<!-- safari disclaimer (centered vertically) -->
|
||||
<div id="disclaimer" hidden style="
|
||||
<div id="disclaimer" style="
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
@ -169,7 +201,7 @@
|
|||
<br>
|
||||
Please use <span style="font-weight: bold;">Chrome</span> or <span style="font-weight: bold;">Firefox</span>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
87
script.js
87
script.js
|
@ -1,3 +1,6 @@
|
|||
doc = document
|
||||
elbyid = (id) => doc.getElementById(id)
|
||||
|
||||
var tung = ""
|
||||
|
||||
var topToggle = false
|
||||
|
@ -18,11 +21,13 @@ $(document).ready(() => {
|
|||
if (localStorage.getItem('tung') === null || localStorage.getItem('tung') == "") {
|
||||
tung = "201C 2014 00D7 00B0 00B7 2022 221E 00B1 2023 201D"
|
||||
localStorage.setItem('tung', tung)
|
||||
|
||||
intro.showModal()
|
||||
}
|
||||
else {
|
||||
tung = localStorage.getItem('tung')
|
||||
}
|
||||
$('#tung').html(tung)
|
||||
elbyid('tung').value = tung
|
||||
layout()
|
||||
|
||||
// persistent text
|
||||
|
@ -30,7 +35,7 @@ $(document).ready(() => {
|
|||
localStorage.setItem('text', "")
|
||||
}
|
||||
else {
|
||||
$('#text').html(localStorage.getItem('text'))
|
||||
elbyid('text').value = localStorage.getItem('text')
|
||||
}
|
||||
|
||||
|
||||
|
@ -152,11 +157,9 @@ function nav() {
|
|||
background-color: #ff79a1;
|
||||
color: #79394f;
|
||||
">
|
||||
Find more character codes in
|
||||
<a target="_blank" href="https://unicode.org/charts/">unicode.org</a>
|
||||
reference charts
|
||||
or sketching in <a target="_blank" href="https://shapecatcher.com/">shapecatcher.com</a>
|
||||
drawbox search!
|
||||
Find more character codes
|
||||
in the <a target="_blank" href="https://unicode.org/charts/">unicode.org</a> reference charts
|
||||
or by sketching in a drawbox search at <a target="_blank" href="https://shapecatcher.com/">shapecatcher.com</a>!
|
||||
</div>`
|
||||
|
||||
$('#nav').html(links + back + html)
|
||||
|
@ -175,7 +178,7 @@ var selected = null
|
|||
function select(index, pick) {
|
||||
let line = lines[index]
|
||||
if (pick) {
|
||||
$('#tung').html(line.split(':')[1].trim())
|
||||
elbyid('tung').value = line.split(':')[1].trim()
|
||||
layout()
|
||||
selected = index
|
||||
} else {
|
||||
|
@ -204,7 +207,7 @@ function getLines(divId) {
|
|||
|
||||
function layout() {
|
||||
// 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, '')
|
||||
if (tung != tungText) {
|
||||
tung = tungText
|
||||
|
@ -246,21 +249,21 @@ function layout() {
|
|||
// override default behavior
|
||||
key.preventDefault()
|
||||
|
||||
// if text is not focused then set the cursor to the end of $('#text')
|
||||
let textEl = $('#text')
|
||||
if (document.activeElement != textEl[0] && window.getSelection().rangeCount == 0) {
|
||||
let selection = window.getSelection()
|
||||
let range = document.createRange()
|
||||
range.selectNodeContents(textEl[0])
|
||||
range.collapse(false)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
}
|
||||
textEl.focus()
|
||||
// if text is not focused then set the cursor to the end of #text
|
||||
// let textEl = elbyid('text')
|
||||
// if (document.activeElement != textEl && window.getSelection().rangeCount == 0) {
|
||||
// let selection = window.getSelection()
|
||||
// let range = document.createRange()
|
||||
// range.selectNodeContents(textEl)
|
||||
// range.collapse(false)
|
||||
// selection.removeAllRanges()
|
||||
// selection.addRange(range)
|
||||
// }
|
||||
// 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'))
|
||||
insertTextAtCursor(char)
|
||||
insertAtCursor(char)
|
||||
|
||||
|
||||
|
||||
|
@ -269,36 +272,31 @@ function layout() {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function insertTextAtCursor(text) {
|
||||
let selection = window.getSelection()
|
||||
let range = selection.getRangeAt(0)
|
||||
range.deleteContents()
|
||||
let node = document.createTextNode(text)
|
||||
range.insertNode(node)
|
||||
range.setStartAfter(node)
|
||||
range.setEndAfter(node)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
function insertAtCursor(text) {
|
||||
const textarea = elbyid('text');
|
||||
const scrollPos = textarea.scrollTop;
|
||||
const caretPos = textarea.selectionStart;
|
||||
const front = textarea.value.substring(0, caretPos);
|
||||
const back = textarea.value.substring(textarea.selectionEnd, textarea.value.length);
|
||||
textarea.value = front + text + back;
|
||||
textarea.selectionStart = caretPos + text.length;
|
||||
textarea.selectionEnd = caretPos + text.length;
|
||||
textarea.scrollTop = scrollPos;
|
||||
textarea.focus();
|
||||
}
|
||||
|
||||
function copyToClipboard(id) {
|
||||
var textEl = $(id)
|
||||
var textarea = elbyid(id)
|
||||
|
||||
// select all the text on the contenteditable div textEl to show it was copied
|
||||
let selection = window.getSelection()
|
||||
let range = document.createRange()
|
||||
range.selectNodeContents(textEl[0])
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
// select all the text in the textarea to show it was copied
|
||||
// textarea.focus()
|
||||
textarea.select()
|
||||
|
||||
if (!navigator.clipboard) {
|
||||
console.error('Clipboard API not supported');
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(textEl.html())
|
||||
navigator.clipboard.writeText(textarea.value)
|
||||
.then(() => {
|
||||
console.log('Text copied to clipboard')
|
||||
})
|
||||
|
@ -358,8 +356,9 @@ function loop(timestamp) {
|
|||
|
||||
|
||||
// check if need to backup the text
|
||||
let text = $('#text').html()
|
||||
let text = elbyid('text').value
|
||||
if (text != lastText) {
|
||||
console.log(text)
|
||||
localStorage.setItem('text', text)
|
||||
lastText = text
|
||||
}
|
||||
|
|
13
style.css
13
style.css
|
@ -12,6 +12,8 @@
|
|||
/* all: unset; */
|
||||
outline: none;
|
||||
/* box-sizing: border-box; */
|
||||
font-family: 'Atkinson Hyperlegible', sans-serif;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,6 +37,8 @@ html {
|
|||
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -53,6 +57,8 @@ body {
|
|||
|
||||
overflow: hidden;
|
||||
touch-action: none;
|
||||
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
/* hide scrollbar */
|
||||
|
@ -118,8 +124,7 @@ a {
|
|||
align-items: baseline;
|
||||
}
|
||||
|
||||
/* textarea {
|
||||
font-family: sans-serif;
|
||||
textarea {
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
padding: 1.5rem 1rem;
|
||||
|
@ -134,11 +139,9 @@ a {
|
|||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
height: -webkit-fill-available;
|
||||
|
||||
background-color: rgb(var(--field));
|
||||
color: rgb(var(--txt));
|
||||
} */
|
||||
}
|
||||
|
||||
#keyboard {
|
||||
display: block;
|
||||
|
|
122
test/index.html
122
test/index.html
|
@ -3,25 +3,76 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<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>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<textarea id="text" rows="10" style="width: 100%;" onclick="">test</textarea>
|
||||
<div id="shelf"></div>
|
||||
</body>
|
||||
<textarea id="text" rows="10" style="width: 100%; box-sizing: border-box;" onclick="">test</textarea>
|
||||
|
||||
</html>
|
||||
<div id="bottombar">This stays stuck to the visual viewport</div>
|
||||
<div id="forcescrolling"></div>
|
||||
<div id="layoutViewport"></div>
|
||||
|
||||
<script>
|
||||
setInterval(() => {
|
||||
let kbHeight = window.innerHeight - window.visualViewport.height
|
||||
kbHeight -= 1
|
||||
<script>
|
||||
// setInterval(() => {
|
||||
// let docHeight = document.documentElement.clientHeight
|
||||
// // docHeight = window.innerHeight
|
||||
// let kbHeight = docHeight - window.visualViewport.height
|
||||
|
||||
document.getElementById('shelf').style.bottom = kbHeight + 'px'
|
||||
// document.getElementById('text').style.height = (window.visualViewport.height - kbHeight) + 'px'
|
||||
}, 10)
|
||||
// // 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
|
||||
|
@ -33,26 +84,37 @@
|
|||
// textarea.select()
|
||||
// }, 10)
|
||||
// }
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
const bottomBar = document.getElementById("bottombar");
|
||||
const layoutViewport = document.getElementById("layoutViewport");
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #79394f;
|
||||
color: #fff;
|
||||
font-family: sans-serif;
|
||||
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>
|
||||
|
||||
#shelf {
|
||||
position: absolute;
|
||||
width: 100%; height: 10px;
|
||||
bottom: 0;
|
||||
background-color: magenta;
|
||||
}
|
||||
</style>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue