From e0d2e52c9334c9a6b406f5fbde9b7d5b6a069b79 Mon Sep 17 00:00:00 2001 From: spatialfree Date: Mon, 24 Apr 2023 06:59:47 -0400 Subject: [PATCH] first commit --- icons/back.svg | 55 +++++ icons/copy.svg | 72 ++++++ icons/salish-keyboard-icon.svg | 117 ++++++++++ icons/tap.png | Bin 0 -> 4094 bytes icons/tung.png | Bin 0 -> 2283 bytes icons/tung.svg | 91 ++++++++ icons/tungs.svg | 57 +++++ index.html | 164 +++++++++++++ inobounce.js | 138 +++++++++++ manifest.webmanifest | 16 ++ script.js | 410 +++++++++++++++++++++++++++++++++ sfx-click.ogg | Bin 0 -> 11026 bytes style.css | 215 +++++++++++++++++ tungs.txt | 7 + 14 files changed, 1342 insertions(+) create mode 100644 icons/back.svg create mode 100644 icons/copy.svg create mode 100644 icons/salish-keyboard-icon.svg create mode 100644 icons/tap.png create mode 100644 icons/tung.png create mode 100644 icons/tung.svg create mode 100644 icons/tungs.svg create mode 100644 index.html create mode 100644 inobounce.js create mode 100644 manifest.webmanifest create mode 100644 script.js create mode 100644 sfx-click.ogg create mode 100644 style.css create mode 100644 tungs.txt diff --git a/icons/back.svg b/icons/back.svg new file mode 100644 index 0000000..29246da --- /dev/null +++ b/icons/back.svg @@ -0,0 +1,55 @@ + + + +image/svg+xml diff --git a/icons/copy.svg b/icons/copy.svg new file mode 100644 index 0000000..7741d9f --- /dev/null +++ b/icons/copy.svg @@ -0,0 +1,72 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/icons/salish-keyboard-icon.svg b/icons/salish-keyboard-icon.svg new file mode 100644 index 0000000..ccd7581 --- /dev/null +++ b/icons/salish-keyboard-icon.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/icons/tap.png b/icons/tap.png new file mode 100644 index 0000000000000000000000000000000000000000..1ea906f961ba9340744ec08a3c7a131381cbc181 GIT binary patch literal 4094 zcmZ`+XH=6-)4o$6p-Dgj0s=vi8d|8*3u*olGON4elEOaLHKl&+Tm0Kfm$Uju*;IRMzW2>@!3 z0D#Az+-j~t2VlVlCVDU$BmXHLPM4CcZu$_Tvyr|o@b}+R*in`V0PJ7`UG3}Pvs?ML z-dV1EZ=?JQ!xrJDtSY24V&CK9A1Madd_cg>r&+S(d})bBg%g2E;Qd}We@>uW1wTA< zO)@~qayX4ImN8gm%$}D=*v4qCXirh|l%~-4h3&s1?Mt_l57k3UPfC||MgFpkkB5Ff z8s62~-fiFB&64jOz==qWmL6ciNf zPEJn7R~ZLMU|5z2){vjXxZGV;Q4s_sL`JHW@izI)DW68!HhFUp{pt3hQP|BK9#G%p z#>l-h!r%lz9*n_Y9!!X<2d^POI>a>) zub`l%Vpj+W5XLqnK|hR+l8T+G<6-QaC}@fx>Gf-Ey~}nmI0D=Q?>jj<4B{iePMt+z z;iPsG2_h>2gU)>MuCahl4kj9#eBVVuAiULdz0?0?cm9cpDB5 ztN%GV;6Oofi=s$uWMq_$pP$h5Vh0osDrO)AJ_tG7qdp-Yd|NOgB2bao@deFF^)gL5 z>I^NBS{Tl@Y;b=kNcW?EE&+^lx8nJ_VHmWvXhK)MffW_C)_3QzDl1-S3;Uk|2lq^? zPwBP&*L<996wIov*uE{40|kOYRiit^dA^GTyrFp&yD zaj@+sJfyQ`ijixZm~K`(73D*rRL~&+WMTEWMjFy?*dRwtuWze5Y`KBN<2g{;AVScG z&7-g$W)N<}w}L{UNPDDe z@ag>n!6=X9+FDTjGnalU2*w--R3{5X&-_#xyD(+~m=ME(5=+M9{7>5Y=QyOW4+g~4 zXzV2Usmb|b3KjEhIx`i>1tb7eDa^*!c94wD?B9tNqQV;J!5*Tz4q~E#7Za0}6e=~a z$;ctFv%No#ab@Fug_n`I7>@7+`b}t%XobCk#PV$`KA(M2PelZbwPUG;pkFJQW6p6n9du!&6R*(4WZ+NvsFav)Mjh<4% zmX7k)-3z6WYDmu*OUY~+Xm6^@RywAcHYN#2#1MO2wJB@JgO9QGJlg7m#lVkmQA0++ z-5Vq7+sE%sfH~69O>a>w8I(G(h$A!U706*}z22cpL5%R1;Y#8!{Z~m$_fDe@QZWnXg~WKi8c=nwslDB~=~y1s5K#R+q`Z4C%Wr z@3~+Qt%s>`xsYFWyjtU|x-1O}XMNbjfZ8vJ7WFB)<^Fuq-eE2CB-$GDcx6x+yIZ^0 z14s0S^2C;{sljn%R-+!FX1@X?ik2jBO13-Cdyab|#Oq4n$VhIUZ8-N7Gs4BE-_u5s z$jPLD8ebSXT#BjDp=I%Ci|&0ME^uc{;ov6w>sNQ*Wn*Ix+OGE)J9q6*&#nGf=dPqC zAxTtBzxP7{_0aMv362ca?5|^;pbNirK(x31n5~t5wT10os+MK z{qs|@*I$bjy-iO1F)hTgpvHOOHXmUA_WlZUw)l-3Z^XY&*E9^yb zL*kbvaoFAOZ-tE5uiBdATdxsu4|!R+xbjJLPwz*Oj*czo=?83>czYjT2(( zsJ*>A?5aYnosZqRYPYB?tsvX6_h6PG;wnfl$L5VGtdV2^CFm$@4U`K-|7>30*Vr4q zjKR{JK)S6%AF(6WDyd>F|$Cw#n`9$@PYc;@KK>suT0&y~#0kMwR z{d2TkQAOprW4+*G)98io2b~kOFB*K+!j!|*Ocd#!6zXXh@;1+ToDNPQ1w7`k;;}RY zUIa_D5QoHTAd7y+0;$T?{27cdpb3dghzU%6c)&&3KG!IUyYWR1XmAU4Cokly2+@ui zjhcDB^0sL8ZLw#OFxE~+VY=Gh>gf4-Yo**x#hD+gQsFsD<&3p&;uqg|>&+T&<6 z5tjiJCP)5#MU-^euqVUY0#_yH>RiO4c86V#m&9od?`s>8&l1ctsiX9ycg~pj=pImM z-)1=-ywo!E(YX9zrw#$0E9BGAjdpMdb$inE2YMBbcwu0co0@b4xc1c!p$aDiwUT!H zn!~(5vmne3&j|J#v9N)heM+Mg3Zf5q9WkhIjt{x_iUp_?j|!jcT=uloixI_Ha+Q)S z!&`IBObA&4mUrZf6{fCzi(Pqc&%9_0fWNWSI8+`G@ZGo?K5XBCy-dCuBl z^XZx;B}brCwPbpfbShW26NS}Sz3h*Im%XKKu7kGFSc?!xQ5V?|Lu8eg_eXO_2e7%ak%f%{W5pk#8*5_wV%_k=Aq)O>6`+Jo7 zco{K)bIS^%XTRy%tby)-Bgi;*7LSC*e$+FR{qxAYzNWrTIQlwF9J6Sz!gqifa7JP1@zff*^ zQ8+7~JMmesPjb&MdxxY+-2!E)%0$Mw2=-s><;s;rTo@+i@7no=EOFuM*!U+7(<5u| z-4YW=$eL37g34_?qSekxNJP-ww`s>O6GbhviE3Q34^Anf#FuuVjv3|=HwlZ~q8-(~ z0o|-A&qa5ScpM3bv$K=t&a?NOL#-6Q%+;o+KpkgE97(1H7tiktu64UX^f73jG7SdG zti1DKVN>N!D(l7v_AS6YKXA0KUH{vam-)_4FkQa#=)-q0-#MJC4ikR7DnxKALRxyE zj+QnarUhEk`+^>57l^*7aafRMzPV-q?cGM@#jT->@PgjL3%%i;R~~*e3SzpM^K(}) z#Hn>*TjJ^OIrjqmm!Soumk-{Fm#yy};}?|P?(c;9(S+T#R>+15pSRx0SGE zrFBu>4T+LOw`yT+HGA*2yAgcSioKl_nO#APZEd180blgRF zjU4Ng>uPB}v(n9ID~Pr4LMuHSGSt#kxu(~_w>WIj;Eo>yLR{F~kn^U)qYXRB?<+KP z=WkwCdEJ#SFYpO5(6rF2!FC;Qzg70xd0i8ZNEToVKK@xS`MuOcCv;S?c_%qp7ik*c zI%nsquJLYWlc;-#k({je`>at?D9m*}kiY1~uU+Z&h>Q>6?BE_@*9T;ZLD!Yw+;b%s;klb>B+-S_O7-VQFCheA@qyrQN>PZ#4* z*I!xK@P?f<&ybZuw&j5D$Tb|dVCl_- zC`bz87|f9#Y>5zmWMDP)?Q&nxarpWE`gY$xf_be*y}nwkAPZu=-aF01v)eX|0vf?7 zW{q3|DQO`h!1I546yQl20+&WYEiEYzv|WOnJCrxC$+CDNsrl)Zevhx#@y!b_ESC4E zP*Fc+{a$W0bu@|n>!RvB>$VdNE@H8y+VZqxXa%o&D7=B5`JRHZmIB=!RBvu{SOVxF zLs?srfyXSo+5t?s1VEzlu^OkeW2Xj!=n=B&6>p2>gyNi}CC$>RShEm3FWMUmgt5$i z5;aWqs6IJ2<7uT7KqBz01v9n3gcGG#OOSZ&G?8@=kZ|ro+t7?yKo}VJhn4`Bv&sH( z;>o}7)KtlUXiv44X~Iyv#O#|PHjz|L29Ybop?seHtTSf~F4bhyAFKuq2`GaI>2VHJ zVys9Us7E}G!CL;MKUy4%dv+o6^#8t`NQ1wy$OFInO-_^${eOHRSkF3`;1ukt<`U>i z7XU_1UR7F7SsJ5qU0zWQgHcmbmXecGlasU8=tln^f{!1;(=FovC!n38NOS^Vpl7OE It#dQ(KWRip-T(jq literal 0 HcmV?d00001 diff --git a/icons/tung.png b/icons/tung.png new file mode 100644 index 0000000000000000000000000000000000000000..91fe5a742515245cba1517dd9cc73786c9a85186 GIT binary patch literal 2283 zcmb7FX*AT28vZei-Pn>Q%oJlu!q_LXehnaPLDO%wIw*3f*{ChS@r)4CX?yqoSjGPK)J_RXNU`ZcXIRvIMv(3H0oK`UZ1^8$TZ2AP=Y5)tnzz1)^x(TrC z)d(q3)QJ9_b-Hkby|n`X7&1oII#_2iy|O4XDmFC2qB?8HcEQRV2T(bs@GQa=VL>$I znu8t}IDTruse&5-praNztYg&V_u@cG5ne1cjoZ`C4%hD8`{3EC7BR#>$GJGeRoOo` z4umzTCaFUNRpVEc4w<9-DTVTjbluBmukD<1xKAiVlLzw@|J_Kr(kmqycR1^9=k1-U zk-XuhBOeSMu$JUwmI@WG?1bs0K@uj* z=A=>PYzb_mL5jf>W|m3!fW1pfmZB*DCr7fagVT5>)IH6dp=a8^=hhF0(#8~!cP-ur zlx=V4E)JMw)0fM)R_$76FB;PFr*PlTYGntSr{`G`<#fmL5!`;-K=7DnEQ0vNcv(T0 zpEM9WP$szV(UatBG7&I_OHf|ls*s5EG@8;h4^1u$sS_vX;Jyb$<&4+xxU7uBe^`90 zkxlieKsD7A`)J6?w|D+^flz+oM%|6dje#M%N~UIX^Tycl+mdSmWW|0-wMx2U?XwQV z702c;Kd+~GPD@#f54z;)i{Ly1=Gh-PywQ~P6lRe z2#Yv%kh$|wd^=Qnp%M@ZeEjkRQy}(~X~}g;xq|nUjH#X6feHKiQGPXpX9dv2P*myu zPqP5~t$v^6jrmV7XnhWwSwi8qEL*B^D=~s8PC|0<*8LhQC>gFw^8?bB_mc+}JK@u& zN|HVu&y%69aHGbB54*okN`Af&bNwmZ6+!q;Sys>z6h-q<@$lZq3!4!J46nm2?Y9w3 zt8aIzUZdX807Y#-K6VH`TXmosJHDsnj^L+|gc!l{5bktg+L-myJr7EguEDY8#Juz2 z9MD|?Vj*p4V+%v3u}_chN%Z~>Nctq9m=sSWo*h8WbhFPZAS2Jyc<@~6e~^gNnOX1s zlR9lVKOE?FsyCZWBA0-gnyZJUy8#sfqn%|K&HcqU!7IpFzcS7nHDM#?h1e_Lu!
vG$a?2pErv>*hJ_@P#;#i%2qZ>kS zV|iueqRxP1aQa-r{JZX0($$@Hm~vX2#wb_U3HF8$GUNsFCc&PDnP!VG8AyRYY&Kg_ zV-LaDxt+5!y5#zmFy|`sIl^~myQz#=M9IJ-z@Y)hZWsHe6v{cl3fd5lqzGaQ}_WP08Cq($H520+4>GrE;k{ zthdd^_RW~!qP8UOHGx2Cr%P}s&(Y`VZ9PYSE+G578t*q+*girBL*)Fbeg_n}k4P96 z>Z^yIY4c8?My>H{ncd%QK%e|38GBzyG+Bq(j-4rBX6yR$trlJ&2t~bEIWe;}!&M!{^w+Yp zn09O*=5T~3C**O&g=seLojX9^>wCpn+7_;6z#V9{ur?s-+l)|YE8Fn<=go-?7wCDOmAy2Aq%nSWfDKsH; zxU|)02w1XaEwZimU5nLSl?_f90-!I24^WJG5 zS?rbZGtcVm5=_KTDzEK*W_={Xrs_xPM7GG|L7J2gLZ0ghyGDlCujwHdj5u3zAa{#1 za@~op5Gx%1X#;DEm3nYw=}%ot4Po%j5uDhVT3&5cc-h(+m1<3$Gbo`3=T5bZ zTJ0lNCR6TxC-8QbOXZ2SwoA8Cgt>Z+t9eNhyOv{#-8#r^jyZ_Sh4HmMj{0UAXGqC$ zRnte^&vD3gIeB@DcJ5v)dzt<|=j|EbKMn-4)tkObPc$C=i)DDI2ve5`A5sJv;~h?B z0f1Ij(@|E{Qbub#s;Ohp+88uiNmUi2s;aXpgZVE(aEOn;Z}k5bSkxD%umpgGsWq + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/icons/tungs.svg b/icons/tungs.svg new file mode 100644 index 0000000..40dc468 --- /dev/null +++ b/icons/tungs.svg @@ -0,0 +1,57 @@ + + + +image/svg+xml diff --git a/index.html b/index.html new file mode 100644 index 0000000..a51fafd --- /dev/null +++ b/index.html @@ -0,0 +1,164 @@ + + + + + + + + + + + + + tung-tap + + + + + + + + + + +
+ +
+
+ +
+ + +
+ + +
+
+
+ +
+
+ + + + +
+ + + + + + \ No newline at end of file diff --git a/inobounce.js b/inobounce.js new file mode 100644 index 0000000..38ea515 --- /dev/null +++ b/inobounce.js @@ -0,0 +1,138 @@ +/*! iNoBounce - v0.2.0 +* https://github.com/lazd/iNoBounce/ +* Copyright (c) 2013 Larry Davis ; 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)); \ No newline at end of file diff --git a/manifest.webmanifest b/manifest.webmanifest new file mode 100644 index 0000000..03d5cbd --- /dev/null +++ b/manifest.webmanifest @@ -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" +} \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..857978c --- /dev/null +++ b/script.js @@ -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 += `
${option}
` + } + + let top = indexPath.length < 2 + let from = top ? 'tungs' : lines[rootIndex - 1].trim() + let back = ` +
+
+ +
${from}
+
+ +
` + + let head = ` +
+
tung-tap
+ +
` + + let links = ` + ` + + $('#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(/
/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 += `
\n` + let keys = row.split(' ') + keys.forEach(key => { + // print the newkey string + // and the unicode character + html += `
+ ${key} + ${String.fromCharCode("0x" + key)} +
\n` + }) + html += `
\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 +} \ No newline at end of file diff --git a/sfx-click.ogg b/sfx-click.ogg new file mode 100644 index 0000000000000000000000000000000000000000..f70ae62ce0e1ca24673b7d73bd321ca4dfd64fb5 GIT binary patch literal 11026 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 MMC303WdHg3FTqGhOaK4? literal 0 HcmV?d00001 diff --git a/style.css b/style.css new file mode 100644 index 0000000..e85206c --- /dev/null +++ b/style.css @@ -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; +} */ \ No newline at end of file diff --git a/tungs.txt b/tungs.txt new file mode 100644 index 0000000..4e791f9 --- /dev/null +++ b/tungs.txt @@ -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 \ No newline at end of file