first commit
55
icons/back.svg
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?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="back.svg"
|
||||
xml:space="preserve"
|
||||
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="7.919596"
|
||||
inkscape:cx="10.669736"
|
||||
inkscape:cy="13.131983"
|
||||
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
|
||||
style="fill:none;stroke:#ffffff;stroke-width:3.199;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 15.92301,1097.1929 -9.2381147,9.2381 9.4155007,9.4155"
|
||||
id="path11921" /><path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:3.199;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 25.315019,1106.6491 H 7.0812466"
|
||||
id="path11925" /></g></svg>
|
After Width: | Height: | Size: 2.1 KiB |
72
icons/copy.svg
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32.000001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="copy.svg">
|
||||
<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="18.306958"
|
||||
inkscape:cy="14.832193"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1027"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="22"
|
||||
inkscape:window-maximized="1" />
|
||||
<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" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1090.5197)">
|
||||
<rect
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.706;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect1373"
|
||||
width="15.616629"
|
||||
height="15.616629"
|
||||
x="3.8530145"
|
||||
y="1094.2299" />
|
||||
<rect
|
||||
y="1103.1393"
|
||||
x="12.762503"
|
||||
height="15.616629"
|
||||
width="15.616629"
|
||||
id="rect1375"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.706;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
117
icons/salish-keyboard-icon.svg
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="192"
|
||||
height="192"
|
||||
viewBox="0 0 192 192.00001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="salish-keyboard-icon.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
inkscape:export-filename="C:\dofdev\Salish Keyboard\salish-keyboard-icon.png"
|
||||
inkscape:export-xdpi="256"
|
||||
inkscape:export-ydpi="256">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient1965">
|
||||
<stop
|
||||
style="stop-color:#1c161b;stop-opacity:0.5"
|
||||
offset="0"
|
||||
id="stop1961" />
|
||||
<stop
|
||||
style="stop-color:#1c161b;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop1963" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1965"
|
||||
id="linearGradient1971"
|
||||
x1="92.405533"
|
||||
y1="1010.9304"
|
||||
x2="147.82085"
|
||||
y2="1062.9532"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.56078431"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.979899"
|
||||
inkscape:cx="66.492719"
|
||||
inkscape:cy="101.6195"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:snap-global="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1027"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="22"
|
||||
inkscape:window-maximized="1"
|
||||
units="px"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-page="true"
|
||||
borderlayer="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid832" />
|
||||
</sodipodi:namedview>
|
||||
<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" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-930.51965)">
|
||||
<path
|
||||
style="fill:#1c161b;fill-opacity:1;stroke:none;stroke-width:3.14762044;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 31.950295,959.96696 c 43.876553,8.69094 87.154865,9.20369 127.509105,-0.32554 7.89365,-1.77643 8.66265,2.45107 9.76665,8.1389 l 22.34605,103.84488 c 0,0 0.10261,8.0315 -0.26872,13.0593 -10.89084,1.4332 -181.055533,1.5621 -190.78290754,0 -0.24551432,-4.7122 0.0141647,-12.1647 0.0141647,-12.1669 L 23.378019,968.11152 c 1.011881,-10.09604 4.723823,-9.39183 8.572937,-8.13889 z"
|
||||
id="path4518"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccc"
|
||||
inkscape:export-filename="C:\dofdev\Web Development\dofdev\v2\dof-covers\salishkeyboard.png"
|
||||
inkscape:export-xdpi="256"
|
||||
inkscape:export-ydpi="256" />
|
||||
<path
|
||||
style="fill:#f2e2c8;fill-opacity:1;stroke-width:1.14920998"
|
||||
d="m 97.615778,1000.7522 c -2.570331,-0.022 -5.195887,0.1495 -7.893649,0.5072 -9.29379,1.2326 -14.97792,3.6691 -24.031342,10.3096 -5.486743,4.0244 -11.152758,6.6213 -22.386836,10.2575 -17.945921,5.8086 -20.58188,7.9444 -9.276871,7.5126 2.856277,-0.1087 8.77396,0.1305 13.149924,0.5316 7.344547,0.6734 8.801895,1.2072 18.984084,6.95 12.832991,7.2378 20.042316,9.3802 31.135002,9.2523 10.44938,-0.1195 20.60068,-3.5352 29.13701,-9.7963 8.76773,-6.4311 15.83965,-8.4179 29.95773,-8.4224 17.3159,0 15.20394,-2.2798 -7.30346,-7.8568 -12.54179,-3.1076 -14.65166,-3.932 -19.83861,-7.7645 -10.39837,-7.683 -20.49494,-11.386 -31.632982,-11.4808 z"
|
||||
id="path892"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccscscssc" />
|
||||
<path
|
||||
style="fill:#5a2927;stroke-width:1.16148973"
|
||||
d="m 97.291872,1007.5482 c -18.181882,0.026 -35.947996,10.1211 -29.106612,21.1816 1.890807,3.0566 3.608117,4.2497 9.820261,6.8159 4.141025,1.7107 10.708268,3.3939 14.592148,3.7405 11.821361,1.0551 28.091391,-5.1275 31.414891,-11.9358 2.75289,-5.6394 -0.94597,-12.0604 -9.29523,-16.1363 -5.25722,-2.5663 -11.36484,-3.6745 -17.425458,-3.6659 z"
|
||||
id="path894"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccssc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.9 KiB |
BIN
icons/tap.png
Normal file
After Width: | Height: | Size: 4 KiB |
BIN
icons/tung.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
91
icons/tung.svg
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?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="tongue.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="10.044643"
|
||||
inkscape:cy="14.553571"
|
||||
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="fill:#ffffff;fill-opacity:1;stroke-width:1.44342;stroke-dasharray:none"
|
||||
id="path217"
|
||||
cx="3.315028"
|
||||
cy="1102.2913"
|
||||
r="2.2093179" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.44342;stroke-dasharray:none"
|
||||
id="circle950"
|
||||
cx="28.684973"
|
||||
cy="1102.2913"
|
||||
r="2.2093179" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.44342;stroke-dasharray:none"
|
||||
id="circle952"
|
||||
cx="15.999997"
|
||||
cy="1102.2913"
|
||||
r="2.2093179" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.44342;stroke-dasharray:none"
|
||||
id="circle954"
|
||||
cx="9.6575136"
|
||||
cy="1111.1942"
|
||||
r="2.2093179" />
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.44342;stroke-dasharray:none"
|
||||
id="circle956"
|
||||
cx="22.342487"
|
||||
cy="1111.1942"
|
||||
r="2.2093179" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
57
icons/tungs.svg
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?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="tongues.svg"
|
||||
xml:space="preserve"
|
||||
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.419643"
|
||||
inkscape:cy="14.553571"
|
||||
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" /><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
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.55999;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 4.1490411,1098.2809 H 27.850958"
|
||||
id="path1874" /><path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.55999;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 4.1490411,1106.5197 H 27.850958"
|
||||
id="path1876" /><path
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.55999;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 4.1490411,1114.7585 H 27.850958"
|
||||
id="path1878" /></g></svg>
|
After Width: | Height: | Size: 2.2 KiB |
164
index.html
Normal file
|
@ -0,0 +1,164 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="notranslate" translate="no">
|
||||
<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="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="author" content="Ethan Merchant">
|
||||
<title style="display: none;">tung-tap</title>
|
||||
<link rel="stylesheet" href="style.css?v1">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- <div id="home" style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 20px;
|
||||
padding-top: 20px;
|
||||
background-color: #79394f;
|
||||
">
|
||||
<div style="
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
">
|
||||
<img src="icons/tongue.png" style="
|
||||
width: 32px; height: 32px;
|
||||
transform: translateY(-5px) rotate(-5deg);
|
||||
">
|
||||
<img src="icons/tap.png" style="
|
||||
width: 32px; height: 32px;
|
||||
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> -->
|
||||
|
||||
<div style="display: block; position: relative; background-color: white;">
|
||||
<div hidden="true" id="tung" onclick="layout()" oninput="layout()" contenteditable="true" spellcheck="false" style="
|
||||
user-select: text;
|
||||
touch-action: none;
|
||||
overflow: none;
|
||||
|
||||
|
||||
white-space: pre;
|
||||
width: auto;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
font-family: 'DM Mono', monospace;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
background-color: #ff79a1;
|
||||
color: #79394f;
|
||||
|
||||
|
||||
|
||||
/* display: none; */
|
||||
"></div>
|
||||
<div onclick="copyToClipboard('#tung')" style="
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
"><img class="icon-btn" src="icons/copy.svg" style="mix-blend-mode: difference;"></div>
|
||||
</div>
|
||||
|
||||
<div style="
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 40px; height: 40px;
|
||||
margin: 0 auto;
|
||||
margin-right: 80px;
|
||||
width: 100%;
|
||||
/* background-color: #eb8bb3; */
|
||||
background-color: #ff79a1c0;
|
||||
color: white;
|
||||
user-select: none;
|
||||
line-height: 40px;
|
||||
">
|
||||
<img onclick="$('#nav').toggle()" class="icon-btn" src="icons/tungs.svg">
|
||||
<img onclick="TopToggle()" class="icon-btn" src="icons/tung.svg">
|
||||
</div>
|
||||
|
||||
|
||||
<div style="flex-grow: 1; overflow: hidden; position: relative; background-color: white;">
|
||||
<div id="text" onclick="$('#text').focus()" contenteditable="true" spellcheck="false" style="
|
||||
user-select: text;
|
||||
touch-action: pan-y;
|
||||
overflow-y: scroll;
|
||||
overscroll-behavior: contain;
|
||||
|
||||
|
||||
white-space: pre-wrap;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
background-color: rgb(var(--field));
|
||||
color: rgb(var(--txt));
|
||||
|
||||
|
||||
|
||||
/* padding-bottom: 600px; */
|
||||
"></div>
|
||||
<div onclick="copyToClipboard('#text')" style="
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
">
|
||||
<img class="icon-btn" src="icons/copy.svg" style="mix-blend-mode: difference;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="nav" hidden="true"></div>
|
||||
|
||||
|
||||
<div id="keyboard" onclick="$('#text').focus()"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
TODO
|
||||
migrate to textareas
|
||||
contenteditable divs are a can of worms
|
||||
esp. when it comes to conistent behaviour across devices
|
||||
|
||||
spellcheck toggle~
|
||||
|
||||
|
||||
-->
|
138
inobounce.js
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*! iNoBounce - v0.2.0
|
||||
* https://github.com/lazd/iNoBounce/
|
||||
* Copyright (c) 2013 Larry Davis <lazdnet@gmail.com>; Licensed BSD */
|
||||
(function(global) {
|
||||
// Stores the Y position where the touch started
|
||||
var startY = 0;
|
||||
|
||||
// Store enabled status
|
||||
var enabled = false;
|
||||
|
||||
var supportsPassiveOption = false;
|
||||
try {
|
||||
var opts = Object.defineProperty({}, 'passive', {
|
||||
get: function() {
|
||||
supportsPassiveOption = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener('test', null, opts);
|
||||
} catch (e) {}
|
||||
|
||||
var handleTouchmove = function(evt) {
|
||||
// Get the element that was scrolled upon
|
||||
var el = evt.target;
|
||||
|
||||
// Allow zooming
|
||||
var zoom = window.innerWidth / window.document.documentElement.clientWidth;
|
||||
if (evt.touches.length > 1 || zoom !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check all parent elements for scrollability
|
||||
while (el !== document.body && el !== document) {
|
||||
// Get some style properties
|
||||
var style = window.getComputedStyle(el);
|
||||
|
||||
if (!style) {
|
||||
// If we've encountered an element we can't compute the style for, get out
|
||||
break;
|
||||
}
|
||||
|
||||
// Ignore range input element
|
||||
if (el.nodeName === 'INPUT' && el.getAttribute('type') === 'range') {
|
||||
return;
|
||||
}
|
||||
|
||||
var scrolling = style.getPropertyValue('-webkit-overflow-scrolling');
|
||||
var overflowY = style.getPropertyValue('overflow-y');
|
||||
var height = parseInt(style.getPropertyValue('height'), 10);
|
||||
|
||||
// Determine if the element should scroll
|
||||
var isScrollable = scrolling === 'touch' && (overflowY === 'auto' || overflowY === 'scroll');
|
||||
var canScroll = el.scrollHeight > el.offsetHeight;
|
||||
|
||||
if (isScrollable && canScroll) {
|
||||
// Get the current Y position of the touch
|
||||
var curY = evt.touches ? evt.touches[0].screenY : evt.screenY;
|
||||
|
||||
// Determine if the user is trying to scroll past the top or bottom
|
||||
// In this case, the window will bounce, so we have to prevent scrolling completely
|
||||
var isAtTop = (startY <= curY && el.scrollTop === 0);
|
||||
var isAtBottom = (startY >= curY && el.scrollHeight - el.scrollTop === height);
|
||||
|
||||
// Stop a bounce bug when at the bottom or top of the scrollable element
|
||||
if (isAtTop || isAtBottom) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
// No need to continue up the DOM, we've done our job
|
||||
return;
|
||||
}
|
||||
|
||||
// Test the next parent
|
||||
el = el.parentNode;
|
||||
}
|
||||
|
||||
// Stop the bouncing -- no parents are scrollable
|
||||
evt.preventDefault();
|
||||
};
|
||||
|
||||
var handleTouchstart = function(evt) {
|
||||
// Store the first Y position of the touch
|
||||
startY = evt.touches ? evt.touches[0].screenY : evt.screenY;
|
||||
};
|
||||
|
||||
var enable = function() {
|
||||
// Listen to a couple key touch events
|
||||
window.addEventListener('touchstart', handleTouchstart, supportsPassiveOption ? { passive : false } : false);
|
||||
window.addEventListener('touchmove', handleTouchmove, supportsPassiveOption ? { passive : false } : false);
|
||||
enabled = true;
|
||||
};
|
||||
|
||||
var disable = function() {
|
||||
// Stop listening
|
||||
window.removeEventListener('touchstart', handleTouchstart, false);
|
||||
window.removeEventListener('touchmove', handleTouchmove, false);
|
||||
enabled = false;
|
||||
};
|
||||
|
||||
var isEnabled = function() {
|
||||
return enabled;
|
||||
};
|
||||
|
||||
// Enable by default if the browser supports -webkit-overflow-scrolling
|
||||
// Test this by setting the property with JavaScript on an element that exists in the DOM
|
||||
// Then, see if the property is reflected in the computed style
|
||||
var testDiv = document.createElement('div');
|
||||
document.documentElement.appendChild(testDiv);
|
||||
testDiv.style.WebkitOverflowScrolling = 'touch';
|
||||
var isScrollSupported = 'getComputedStyle' in window && window.getComputedStyle(testDiv)['-webkit-overflow-scrolling'] === 'touch';
|
||||
document.documentElement.removeChild(testDiv);
|
||||
|
||||
if (isScrollSupported) {
|
||||
enable();
|
||||
}
|
||||
|
||||
// A module to support enabling/disabling iNoBounce
|
||||
var iNoBounce = {
|
||||
enable: enable,
|
||||
disable: disable,
|
||||
isEnabled: isEnabled,
|
||||
isScrollSupported: isScrollSupported
|
||||
};
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
// Node.js Support
|
||||
module.exports = iNoBounce;
|
||||
}
|
||||
if (typeof global.define === 'function') {
|
||||
// AMD Support
|
||||
(function(define) {
|
||||
define('iNoBounce', [], function() { return iNoBounce; });
|
||||
}(global.define));
|
||||
}
|
||||
else {
|
||||
// Browser support
|
||||
global.iNoBounce = iNoBounce;
|
||||
}
|
||||
}(this));
|
16
manifest.webmanifest
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"background_color": "#ff79a1",
|
||||
"description": "Augment your keyboard with the symbols you need to type in your language.",
|
||||
"display": "fullscreen",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/tung.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "any"
|
||||
}
|
||||
],
|
||||
"name": "tung-tap.app",
|
||||
"short_name": "tung-tap",
|
||||
"start_url": "/index.html"
|
||||
}
|
410
script.js
Normal file
|
@ -0,0 +1,410 @@
|
|||
var tung = ""
|
||||
|
||||
var topToggle = false
|
||||
function TopToggle(show = null) {
|
||||
topToggle = show === null ? !topToggle : show
|
||||
|
||||
if (topToggle) {
|
||||
$('#tung').show()
|
||||
} else {
|
||||
$('#tung').hide()
|
||||
}
|
||||
layout()
|
||||
}
|
||||
|
||||
const sfx = new Audio('sfx-click.ogg')
|
||||
|
||||
$(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)
|
||||
}
|
||||
else {
|
||||
tung = localStorage.getItem('tung')
|
||||
}
|
||||
$('#tung').html(tung)
|
||||
layout()
|
||||
|
||||
// persistent text
|
||||
if (localStorage.getItem('text') === null || localStorage.getItem('text') == "") {
|
||||
localStorage.setItem('text', "")
|
||||
}
|
||||
else {
|
||||
$('#text').html(localStorage.getItem('text'))
|
||||
}
|
||||
|
||||
|
||||
// $('body').on('keydown', '[contenteditable]', function(e) {
|
||||
// if (e.keyCode === 13) {
|
||||
// e.preventDefault() // prevent the default newline insertion
|
||||
// var range = window.getSelection().getRangeAt(0) // get the current selection range
|
||||
// var newline = document.createTextNode("\n") // create a new text node with the newline character
|
||||
// range.insertNode(newline) // insert the new text node at the current cursor position
|
||||
// range.setStartAfter(newline) // set the cursor after the new text node
|
||||
// range.setEndAfter(newline) // set the end of the selection after the new text node
|
||||
// window.getSelection().removeAllRanges() // remove the old selection
|
||||
// window.getSelection().addRange(range) // set the new selection to the updated range
|
||||
// layout()
|
||||
// }
|
||||
// console.log(e.keyCode)
|
||||
// });
|
||||
|
||||
|
||||
let url = '/tungs.txt'
|
||||
$.get(url, function (data) {
|
||||
lines = data.split('\n')
|
||||
nav()
|
||||
})
|
||||
})
|
||||
|
||||
var lines = null
|
||||
var indexPath = [ 0 ]
|
||||
|
||||
function indentation(line) {
|
||||
let lineIndent = 0
|
||||
while (line.charAt(lineIndent) == '\t') { lineIndent++ }
|
||||
return lineIndent
|
||||
}
|
||||
|
||||
function nav() {
|
||||
let rootIndex = indexPath[indexPath.length - 1]
|
||||
let root = lines[rootIndex]
|
||||
let rootIndent = indentation(root)
|
||||
|
||||
let html = ``
|
||||
for (let i = rootIndex; i < lines.length; i++) {
|
||||
let line = lines[i]
|
||||
let lineIndent = indentation(line)
|
||||
|
||||
if (lineIndent < rootIndent) {
|
||||
break
|
||||
}
|
||||
|
||||
if (lineIndent > rootIndent) {
|
||||
continue
|
||||
}
|
||||
|
||||
let option = line.trim()
|
||||
let pick = false
|
||||
if (option.includes(':')) {
|
||||
option = option.split(':')[0].trim()
|
||||
pick = true
|
||||
}
|
||||
|
||||
let disabled = false
|
||||
// if next line has doesn't have a greater indent, disable the option and make it gray
|
||||
if (!pick && i + 1 < lines.length) {
|
||||
let nextLineIndent = indentation(lines[i + 1])
|
||||
if (nextLineIndent <= rootIndent) {
|
||||
disabled = true
|
||||
}
|
||||
}
|
||||
|
||||
let classes = `class="option
|
||||
${disabled ? 'disabled' : ''}
|
||||
${pick ? 'pick' : ''}
|
||||
${(selected != null && i == selected) ? 'selected' : ''}
|
||||
"`
|
||||
let click = `${disabled ? '' : `onclick="select(${i}, ${pick})"`}`
|
||||
|
||||
html += `<div ${classes} ${click}>${option}</div>`
|
||||
}
|
||||
|
||||
let top = indexPath.length < 2
|
||||
let from = top ? 'tungs' : lines[rootIndex - 1].trim()
|
||||
let back = `
|
||||
<div class="option back" onclick="back()">
|
||||
<div style="">
|
||||
<img class="icon-btn" src="icons/back.svg" style="margin: 0; transform: rotate(${top ? 45 : 0}deg);">
|
||||
<div style="margin-top: 16px; font-size: 24px; font-weight: bold;">${from}</div>
|
||||
</div>
|
||||
<div><a href="https://github.com/spatialfree/tung-tap">contribute</a></div>
|
||||
</div>`
|
||||
|
||||
let head = `
|
||||
<div style="display: flex; justify-content: space-around; align-items: center; padding: 0 10px; height: 36px; background-color: #ffb5dd; color: #fff;">
|
||||
<div style="font-weight: bold;">tung-tap</div>
|
||||
<img onclick="$('#nav').toggle()" class="icon-btn" src="icons/tungs.svg">
|
||||
</div>`
|
||||
|
||||
let links = `
|
||||
<div id="links" style="
|
||||
padding: 10px 20px;
|
||||
margin: 0px;
|
||||
font-size: 14px;
|
||||
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!
|
||||
</div>`
|
||||
|
||||
$('#nav').html(links + back + html)
|
||||
}
|
||||
|
||||
function back() {
|
||||
if (indexPath.length == 1) {
|
||||
$('#nav').toggle()
|
||||
return
|
||||
}
|
||||
indexPath.pop()
|
||||
nav()
|
||||
}
|
||||
|
||||
var selected = null
|
||||
function select(index, pick) {
|
||||
let line = lines[index]
|
||||
if (pick) {
|
||||
$('#tung').html(line.split(':')[1].trim())
|
||||
layout()
|
||||
selected = index
|
||||
} else {
|
||||
indexPath.push(index + 1)
|
||||
}
|
||||
nav()
|
||||
}
|
||||
|
||||
function getLines(divId) {
|
||||
var div = document.getElementById(divId)
|
||||
var lineHeight = parseInt(window.getComputedStyle(div).getPropertyValue('line-height'))
|
||||
var height = div.getBoundingClientRect().height
|
||||
var lineCount = Math.floor(height / lineHeight)
|
||||
var newLines = []
|
||||
for (var i = 0; i < lineCount; i++) {
|
||||
// var lineTop = i * lineHeight
|
||||
// var lineBottom = (i + 1) * lineHeight
|
||||
var lineText = div.innerText.substring(
|
||||
div.getClientRects()[i].left - div.getClientRects()[0].left,
|
||||
div.getClientRects()[i].right - div.getClientRects()[0].left
|
||||
)
|
||||
newLines.push(lineText)
|
||||
}
|
||||
return newLines
|
||||
}
|
||||
|
||||
function layout() {
|
||||
// keymap (tung is the proprietary name)
|
||||
let tungText = $('#tung').html() //.replace('\r\n', '\n')
|
||||
tungText = tungText.replace(/<div>/g, '\n').replace(/<\/div>/g, '')
|
||||
if (tung != tungText) {
|
||||
tung = tungText
|
||||
localStorage.setItem('tung', tung)
|
||||
}
|
||||
|
||||
// console.log(tungText)
|
||||
|
||||
let html = ``
|
||||
let rows = tung.split('\n')
|
||||
rows.forEach(row => {
|
||||
row = row.trim()
|
||||
if (row.length > 0) {
|
||||
html += `<div class="row">\n`
|
||||
let keys = row.split(' ')
|
||||
keys.forEach(key => {
|
||||
// print the newkey string
|
||||
// and the unicode character
|
||||
html += `<div class="key" charcode="${key}" ${topToggle ? `style="position: relative; padding-top: 10px;` : ``}">
|
||||
<span style="
|
||||
font-family: 'DM Mono', monospace;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
position: absolute;
|
||||
top: 2px; left: 0; right: 0;
|
||||
color: #aaa;
|
||||
${topToggle ? `` : `display: none;`}
|
||||
">${key}</span>
|
||||
${String.fromCharCode("0x" + key)}
|
||||
</div>\n`
|
||||
})
|
||||
html += `</div>\n`
|
||||
}
|
||||
})
|
||||
|
||||
$('#keyboard').html(html)
|
||||
|
||||
$('.key').click(key => {
|
||||
// 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()
|
||||
|
||||
// insert key character into contenteditable div $('#text') at cursor position
|
||||
let char = String.fromCharCode("0x" + $(key.target).attr('charcode'))
|
||||
insertTextAtCursor(char)
|
||||
|
||||
|
||||
|
||||
// navigator.vibrate(20);
|
||||
// sfx.play()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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 copyToClipboard(id) {
|
||||
var textEl = $(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)
|
||||
|
||||
if (!navigator.clipboard) {
|
||||
console.error('Clipboard API not supported');
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(textEl.html())
|
||||
.then(() => {
|
||||
console.log('Text copied to clipboard')
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to copy text: ', err)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// const newPosition = toolbar.getBoundingClientRect().top
|
||||
// toolbar.classList.add('down')
|
||||
|
||||
|
||||
function getVisibleHeight() {
|
||||
var pixelRatio = window.devicePixelRatio || 1
|
||||
var viewportHeight = window.visualViewport.height * pixelRatio
|
||||
var windowHeight = window.innerHeight * pixelRatio
|
||||
var keyboardHeight = viewportHeight - windowHeight
|
||||
// $('#tung').html(`viewport ${viewportHeight}px | window ${windowHeight}px | keyboard ${keyboardHeight}px`)
|
||||
|
||||
return Math.abs(keyboardHeight) / pixelRatio || 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
var out = 400;
|
||||
function loop(timestamp) {
|
||||
var delta = timestamp - lastRender
|
||||
time += delta
|
||||
|
||||
let height = getVisibleHeight()
|
||||
|
||||
// use the bottom of the #tung element position to use for the body top
|
||||
// to be able to toggle the top of the page
|
||||
let top = $('#tung').outerHeight(true) //+ $('#links').outerHeight(true) // + $('#home').outerHeight(true)
|
||||
|
||||
if (topToggle)
|
||||
top *= 0
|
||||
|
||||
// lerp out to top
|
||||
if (time > 100) {
|
||||
out = lerp(out, top, 0.01 * delta)
|
||||
}
|
||||
|
||||
|
||||
// 'bottom': height + 'px',
|
||||
// $('body').css({
|
||||
// 'top': -out + 'px'
|
||||
// })
|
||||
|
||||
|
||||
|
||||
|
||||
// $('#keyboard').css({
|
||||
// 'bottom': height + 'px',
|
||||
// })
|
||||
|
||||
|
||||
// check if need to backup the text
|
||||
let text = $('#text').html()
|
||||
if (text != lastText) {
|
||||
localStorage.setItem('text', text)
|
||||
lastText = text
|
||||
}
|
||||
|
||||
|
||||
|
||||
lastRender = timestamp
|
||||
window.requestAnimationFrame(loop)
|
||||
}
|
||||
var lastText = ''
|
||||
var lastRender = 0
|
||||
var time = 0
|
||||
window.requestAnimationFrame(loop)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let ua = navigator.userAgent.toLowerCase()
|
||||
let safari = ua.indexOf('safari') != -1 && !(ua.indexOf('chrome') > -1)
|
||||
|
||||
// dev toggle override
|
||||
// safari = !safari
|
||||
|
||||
$('html').css('--bg', safari ? '214, 216, 221' : '16, 16, 16')
|
||||
$('html').css('--fg', safari ? '214, 216, 221' : '240, 240, 240')
|
||||
$('html').css('--key', safari ? '255, 255, 255' : '48, 48, 48')
|
||||
$('html').css('--key-height', safari ? '40px' : '48px')
|
||||
$('html').css('--key-radius', safari ? '5px' : '8px')
|
||||
$('html').css('--txt', safari ? '0, 0, 0' : '255, 255, 255')
|
||||
$('html').css('--txt-size', safari ? '22px' : '26px')
|
||||
$('html').css('--field', safari ? '255, 255, 255' : '0, 0, 0')
|
||||
$('html').css('--gap', safari ? '6px' : '5px')
|
||||
|
||||
window.addEventListener("beforeinstallprompt", (e) => {
|
||||
console.log('beforeinstallprompt')
|
||||
// // Prevent Chrome 67 and earlier from automatically showing the prompt
|
||||
// e.preventDefault()
|
||||
// // Stash the event so it can be triggered later.
|
||||
// deferredPrompt = e
|
||||
// // // Update UI to notify the user they can add to home screen
|
||||
// // addBtn.style.display = "block"
|
||||
|
||||
// // addBtn.addEventListener("click", (e) => {
|
||||
// // // hide our user interface that shows our A2HS button
|
||||
// // addBtn.style.display = "none"
|
||||
// // })
|
||||
// // Show the prompt
|
||||
// deferredPrompt.prompt()
|
||||
// // Wait for the user to respond to the prompt
|
||||
// deferredPrompt.userChoice.then((choiceResult) => {
|
||||
// if (choiceResult.outcome === "accepted") {
|
||||
// console.log("User accepted the A2HS prompt")
|
||||
// } else {
|
||||
// console.log("User dismissed the A2HS prompt")
|
||||
// }
|
||||
// deferredPrompt = null
|
||||
// })
|
||||
})
|
||||
|
||||
|
||||
|
||||
function lerp(a, b, n) {
|
||||
return (1 - n) * a + n * b
|
||||
}
|
BIN
sfx-click.ogg
Normal file
215
style.css
Normal file
|
@ -0,0 +1,215 @@
|
|||
@import url('https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:ital,wght@0,400;0,700;1,400&family=DM+Mono&display=swap');
|
||||
|
||||
:root {
|
||||
/* --bg: 16, 16, 16;
|
||||
--fg: 240, 240, 240;
|
||||
--key: 32, 32, 32;
|
||||
--txt: 255, 255, 255;
|
||||
--field: 255, 255, 255; */
|
||||
}
|
||||
|
||||
* {
|
||||
/* all: unset; */
|
||||
outline: none;
|
||||
/* box-sizing: border-box; */
|
||||
}
|
||||
|
||||
|
||||
/* *::selection {
|
||||
background-color: rgba(255, 255, 255, 0.333);
|
||||
} */
|
||||
|
||||
/* *::marker {
|
||||
color: rgb(var(--txt));
|
||||
} */
|
||||
|
||||
|
||||
html {
|
||||
/* font-family: sans-serif; */
|
||||
font-family: 'Atkinson Hyperlegible', sans-serif;
|
||||
font-size: 16px;
|
||||
|
||||
background-color: rgb(var(--field));
|
||||
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* start from bottom */
|
||||
justify-content: flex-end;
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background-color: rgb(var(--field));
|
||||
|
||||
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
|
||||
|
||||
overflow: hidden;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
/* hide scrollbar */
|
||||
*::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
button,
|
||||
select,
|
||||
div,
|
||||
a {
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
#nav {
|
||||
background-color: rgb(var(--field));
|
||||
color: rgb(var(--txt));
|
||||
overflow-y: auto;
|
||||
max-height: -webkit-fill-available;
|
||||
/* margin-top: 120px; */
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
|
||||
/* opacity: 0.999; weird fix... */
|
||||
|
||||
padding-bottom: 500px;
|
||||
}
|
||||
|
||||
.option {
|
||||
padding: 12px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background-color: rgb(var(--bg));
|
||||
border-top: 0.5px solid #80808042;
|
||||
}
|
||||
|
||||
.option:nth-child(2n) {
|
||||
background-color: rgb(var(--field));
|
||||
}
|
||||
|
||||
.option.pick {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.option.selected {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.option.disabled {
|
||||
color: rgba(var(--txt), 0.333);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.back {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
/* textarea {
|
||||
font-family: sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
padding: 1.5rem 1rem;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
resize: none;
|
||||
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
height: -webkit-fill-available;
|
||||
|
||||
background-color: rgb(var(--field));
|
||||
color: rgb(var(--txt));
|
||||
} */
|
||||
|
||||
#keyboard {
|
||||
display: block;
|
||||
margin-bottom: 0px;
|
||||
background-color: rgb(var(--bg));
|
||||
z-index: 100;
|
||||
user-select: none;
|
||||
border-top: 0.5px solid rgba(128, 128, 128, 0.333);
|
||||
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
/* position: fixed;
|
||||
bottom: 0; left: 0; right: 0; */
|
||||
}
|
||||
|
||||
/* transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); */
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
gap: var(--gap);
|
||||
margin: 9px 3px;
|
||||
}
|
||||
|
||||
.key {
|
||||
font-family: sans-serif;
|
||||
font-size: var(--txt-size);
|
||||
line-height: var(--key-height);
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
max-width: 64px;
|
||||
height: var(--key-height);
|
||||
text-align: center;
|
||||
|
||||
border-top: 0.5px solid rgba(255, 255, 255, 0);
|
||||
margin-bottom: -0.5px;
|
||||
border-radius: var(--key-radius);
|
||||
background-color: rgba(var(--key));
|
||||
color: rgb(var(--txt));
|
||||
|
||||
box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.333);
|
||||
/* box-shadow: 0 0 0.5rem 0rem rgba(255, 255, 255, 0.0) inset; */
|
||||
transition: 0.1s;
|
||||
transition-timing-function: cubic-bezier(.51,.12,0,-0.27);
|
||||
}
|
||||
|
||||
.key:active {
|
||||
transition: 0.0s;
|
||||
/* transition-timing-function: cubic-bezier(0.1, 1, 0.77, 0.62); */
|
||||
|
||||
border-color: rgba(255, 255, 255, 0.333);
|
||||
box-shadow: 0 7px 4px 0 rgba(0, 0, 0, 0.333);
|
||||
transform: translateY(-6px);
|
||||
/* box-shadow: 0 0px 6px 0 rgba(0, 0, 0, 0.333) inset;
|
||||
transform: translateY(2.0px); */
|
||||
/* flex: 1.2; */
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* #copybtn:active {
|
||||
transition: 0.1s;
|
||||
box-shadow: 0 0 0.5rem 0rem rgba(0, 0, 0, 0.333) inset;
|
||||
} */
|
7
tungs.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
Misc.
|
||||
Test : 201C 2014 00D7 00B0 00B7 2022 221E 00B1 2023 201D
|
||||
Salishan
|
||||
Bella Coola
|
||||
Coast Salish
|
||||
Interior Salish
|
||||
Spokane : 0142 019B 0323 02B7 203F 0301 030C 0294 0295 0313
|