Compare commits

..

No commits in common. "main" and "8d571d11d4e3eff583c3ce62eb10943396300cfa" have entirely different histories.

13 changed files with 36151 additions and 429 deletions

7
.gitignore vendored
View File

@ -1,7 +1,4 @@
node_modules
elm-stuff
target
js/*
!js/main.min.js
elm/Emoji.elm
emoji.txt
js/main.js
js/main.tmp.js

2
Cargo.lock generated
View File

@ -43,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
[[package]]
name = "emojinput"
name = "elmojinput"
version = "0.1.0"
dependencies = [
"web-view",

View File

@ -1,5 +1,5 @@
[package]
name = "emojinput"
name = "elmojinput"
version = "0.1.0"
edition = "2021"

View File

@ -15,13 +15,13 @@ BUILD_DIR=js
dev: target/debug/elmojinput
release: target/release/elmojinput
js/main.js: elm/** elm/Emoji.elm
js/main.js: elm/**
$(ELM) make elm/Main.elm --output $(BUILD_DIR)/main.js
js/main.min.js: js/main.tmp.js
@$(UGLIFYJS) $(BUILD_DIR)/main.tmp.js --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | $(UGLIFYJS) --mangle > $(BUILD_DIR)/main.min.js
js/main.tmp.js: elm/** elm/Emoji.elm
js/main.tmp.js: elm/**
@$(ELM) make elm/Main.elm --optimize --output $(BUILD_DIR)/main.tmp.js
target/debug/elmojinput: js/main.js src/**
@ -30,11 +30,5 @@ target/debug/elmojinput: js/main.js src/**
target/release/elmojinput: js/main.min.js src/**
cargo build --release
js/emoji.html:
@curl https://unicode.org/emoji/charts/emoji-list.html -o $(BUILD_DIR)/emoji.html
elm/Emoji.elm: js/emoji.html extract.js
@node extract.js > elm/Emoji.elm
clean:
@rm -rf $(BUILD_DIR)/{main.js,main.min.js,emoji.html} elm/Emoji.elm
@rm -rf $(BUILD_DIR)/{main.js,main.min.js}

1525
elm/Emoji.elm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,14 +3,13 @@ port module Main exposing (..)
import Browser
import Element exposing (Element)
import Element.Border as Border
import Element.Font as Font
import Element.Input as Input
import Emoji
import Html
import Html.Attributes
import Html.Events
import Json.Decode as Decode
import Levenshtein exposing (distance)
import Levenshtein
main =
@ -59,17 +58,15 @@ modelEmojis model =
Search s ->
Emoji.categories
|> List.map Emoji.getEmojis
|> List.map (List.filter (\x -> String.contains s x.name || List.any (String.contains s) x.tags))
|> doubleMap (\x -> ( x, distance s x.name ))
|> List.map (List.sortBy Tuple.second)
|> mergeBy Tuple.second
|> List.concatMap Emoji.getEmojis
|> List.map (\x -> ( x, minimum ( Levenshtein.distance s x.name, List.map (\v -> Levenshtein.distance s v + 1) x.tags ) ))
|> List.sortBy Tuple.second
|> List.map Tuple.first
init : () -> ( Model, Cmd Msg )
init _ =
( Category Emoji.Smileys, Cmd.none )
( Category Emoji.Recent, Cmd.none )
type Msg
@ -111,7 +108,7 @@ update msg model =
view : Model -> Html.Html Msg
view model =
[ header model, panel (modelEmojis model) ]
|> Element.column [ Font.size 25, Element.width (Element.px 1024), Element.height (Element.px 768) ]
|> Element.column [ Element.width (Element.px 512), Element.height (Element.px 512) ]
|> Element.layout []
@ -132,7 +129,7 @@ header model =
Border.width 1
, Border.rounded 5
]
{ label = Element.el [ Element.centerX, Element.centerY ] (Element.text (Emoji.categoryEmoji x).unicode)
{ label = Element.el [] (Element.text (Emoji.categoryEmoji x).unicode)
, onPress = Just (CategoryClicked x)
}
)
@ -153,10 +150,10 @@ header model =
panel : List Emoji.Emoji -> Element Msg
panel em =
em
|> regroup 20
|> regroup 10
|> List.map (\x -> List.map maybeEmoji x)
|> List.map (Element.row [ Element.width Element.fill ])
|> Element.column [ Element.width (Element.px 1024), Element.height (Element.px 748), Element.scrollbarY ]
|> Element.column [ Element.width (Element.px 512), Element.height (Element.px 512), Element.scrollbarY ]
emoji : Emoji.Emoji -> Element Msg
@ -204,8 +201,8 @@ port copy : String -> Cmd msg
-- UTILS --
minimum : comparable -> List comparable -> comparable
minimum h t =
minimum : ( comparable, List comparable ) -> comparable
minimum ( h, t ) =
case List.minimum t of
Nothing ->
h
@ -214,8 +211,8 @@ minimum h t =
min h v
maximum : comparable -> List comparable -> comparable
maximum h t =
maximum : ( comparable, List comparable ) -> comparable
maximum ( h, t ) =
case List.maximum t of
Nothing ->
h
@ -239,44 +236,3 @@ onEnter msg =
)
)
)
mergeAux : (a -> comparable) -> List a -> List a -> List a
mergeAux comparator listOne listTwo =
case ( listOne, listTwo ) of
( _, [] ) ->
listOne
( [], _ ) ->
listTwo
( frontOne :: restOne, frontTwo :: restTwo ) ->
if comparator frontOne < comparator frontTwo then
frontOne :: mergeAux comparator restOne listTwo
else
frontTwo :: mergeAux comparator listOne restTwo
mergeBy : (a -> comparable) -> List (List a) -> List a
mergeBy comparator input =
case input of
[] ->
[]
[ [] ] ->
[]
[ a ] ->
a
[ a, b ] ->
mergeAux comparator a b
a :: b :: t ->
mergeBy comparator (mergeAux comparator a b :: t)
doubleMap : (a -> b) -> List (List a) -> List (List b)
doubleMap map input =
List.map (\x -> List.map map x) input

View File

@ -1,121 +0,0 @@
const fs = require('fs');
const decode = require('decode-html');
const { parse } = require('node-html-parser');
function formatEmoji(emoji) {
return (
'{ name = "' + emoji.name +
'", unicode = "' + emoji.unicode +
'", tags = [ ' + emoji.tags.map(x => '"' + x + '"').join(', ') +
' ] }'
);
}
let html = parse(fs.readFileSync('js/emoji.html', 'utf-8'));
let table = html.getElementsByTagName('table')[0];
let emojis = {};
let currentEmojis = null;
for (let element of table.childNodes) {
// Skip text
if (element.nodeType === 3) continue;
if (element.rawTagName === 'tr') {
let cols = element.childNodes.filter(x => x.nodeType !== 3);
let firstCol = cols[0];
if (firstCol.classList.contains('bighead')) {
let name = decode(firstCol.childNodes.filter(x => x.nodeType !== 3)[0].childNodes[0]._rawText)
.split(' ')[0]
.toLowerCase();
currentEmojis = [];
emojis[name] = currentEmojis;
}
if (firstCol.rawTagName === 'td') {
// We're in an emoji line
let name = decode(cols[3].childNodes[0]._rawText);
let tags = decode(cols[4].childNodes[0]._rawText).split('|').map(x => x.trim());
let unicode = cols[2].childNodes[0].childNodes[0].rawAttrs.split("'")[1];
currentEmojis.push({
unicode, name, tags
});
}
}
}
delete(emojis.component);
// Generate elm
console.log('module Emoji exposing (..)');
console.log('\n');
console.log('type alias Emoji =');
console.log(' { name : String');
console.log(' , unicode : String');
console.log(' , tags : List String');
console.log(' }');
console.log('\n');
console.log('type alias Emojis =');
let first = true;
for (let key in emojis) {
console.log(' ' + (first ? '{' : ',') + ' ' + key + ' : List Emoji');
first = false;
}
console.log(' }')
console.log('\n');
console.log('type Category');
first = true;
for (let key in emojis) {
console.log(' ' + (first ? '=' : '|') + ' ' + key[0].toUpperCase() + key.slice(1).toLowerCase());
first = false;
}
console.log('\n');
console.log('categories : List Category');
console.log('categories =');
console.log(' [' + Object.keys(emojis).map(x => x[0].toUpperCase() + x.slice(1).toLowerCase()).join(', ') + ']');
console.log('\n');
console.log('categoryEmoji : Category -> Emoji');
console.log('categoryEmoji category =');
console.log(' case category of');
for (let key in emojis) {
console.log(' ' + key[0].toUpperCase() + key.slice(1).toLowerCase() + ' ->');
console.log(' ' + formatEmoji(emojis[key][0]) + '\n');
}
console.log();
console.log('getEmojis : Category -> List Emoji')
console.log('getEmojis category =');
console.log(' case category of');
for (let key in emojis) {
console.log(' ' + key[0].toUpperCase() + key.slice(1).toLowerCase() + ' ->');
console.log(' emojis.' + key + '\n');
}
console.log();
console.log('emojis : Emojis');
console.log('emojis =');
let first1 = true;
for (let key in emojis) {
console.log(' ' + (first1 ? '{' : ',') + ' ' + key + ' =');
let first2 = true;
for (let emoji of emojis[key]) {
console.log(' ' + (first2 ? '[' : ',') + ' ' + formatEmoji(emoji));
first2 = false;
}
console.log(' ]');
first1 = false;
}
console.log(' }');

17312
js/main.js Normal file

File diff suppressed because it is too large Load Diff

1
js/main.min.js vendored Normal file

File diff suppressed because one or more lines are too long

17289
js/main.tmp.js Normal file

File diff suppressed because it is too large Load Diff

225
package-lock.json generated
View File

@ -1,225 +0,0 @@
{
"name": "emojinput",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"decode-html": "^2.0.0",
"node-html-parser": "^5.2.0"
}
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"node_modules/css-select": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz",
"integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==",
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^5.1.0",
"domhandler": "^4.3.0",
"domutils": "^2.8.0",
"nth-check": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-what": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz",
"integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==",
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/decode-html": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/decode-html/-/decode-html-2.0.0.tgz",
"integrity": "sha1-fQqIfORCgOYJeKcH67f4CB/WHqo="
},
"node_modules/dom-serializer": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
"dependencies": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
]
},
"node_modules/domhandler": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz",
"integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==",
"dependencies": {
"domelementtype": "^2.2.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
"dependencies": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"bin": {
"he": "bin/he"
}
},
"node_modules/node-html-parser": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.2.0.tgz",
"integrity": "sha512-fmiwLfQu+J2A0zjwSEkztSHexAf5qq/WoiL/Hgo1K7JpfEP+OGWY5maG0kGaM+IFVdixF/1QbyXaQ3h4cGfeLw==",
"dependencies": {
"css-select": "^4.1.3",
"he": "1.2.0"
}
},
"node_modules/nth-check": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
"dependencies": {
"boolbase": "^1.0.0"
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
}
},
"dependencies": {
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"css-select": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz",
"integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==",
"requires": {
"boolbase": "^1.0.0",
"css-what": "^5.1.0",
"domhandler": "^4.3.0",
"domutils": "^2.8.0",
"nth-check": "^2.0.1"
}
},
"css-what": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz",
"integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw=="
},
"decode-html": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/decode-html/-/decode-html-2.0.0.tgz",
"integrity": "sha1-fQqIfORCgOYJeKcH67f4CB/WHqo="
},
"dom-serializer": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
}
},
"domelementtype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
},
"domhandler": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz",
"integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==",
"requires": {
"domelementtype": "^2.2.0"
}
},
"domutils": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
"requires": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0"
}
},
"entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"node-html-parser": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.2.0.tgz",
"integrity": "sha512-fmiwLfQu+J2A0zjwSEkztSHexAf5qq/WoiL/Hgo1K7JpfEP+OGWY5maG0kGaM+IFVdixF/1QbyXaQ3h4cGfeLw==",
"requires": {
"css-select": "^4.1.3",
"he": "1.2.0"
}
},
"nth-check": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
"requires": {
"boolbase": "^1.0.0"
}
}
}
}

View File

@ -1,6 +0,0 @@
{
"dependencies": {
"decode-html": "^2.0.0",
"node-html-parser": "^5.2.0"
}
}

View File

@ -5,11 +5,11 @@ use web_view::*;
fn main() {
#[cfg(debug_assertions)]
let js = include_str!("../js/main.js");
let js = include_str!("../../elmoji/js/main.js");
#[cfg(not(debug_assertions))]
let js = include_str!("../js/main.min.js");
let js = include_str!("../../elmoji/js/main.min.js");
let html_content = include_str!("../index.html").replace(
let html_content = include_str!("../../elmoji/index.html").replace(
"<script src=\"js/main.js\"></script>",
&format!("<script>{}</script>", js),
);
@ -17,7 +17,7 @@ fn main() {
web_view::builder()
.title("Elmojinput")
.content(Content::Html(html_content))
.size(1024, 768)
.size(512, 512)
.resizable(false)
.debug(true)
.user_data(())