Skip to content

Instantly share code, notes, and snippets.

@joshuaebowling
Created December 4, 2018 19:33
Show Gist options
  • Save joshuaebowling/3deeb1f5d8ce40ad8a83199c261ae9fe to your computer and use it in GitHub Desktop.
Save joshuaebowling/3deeb1f5d8ce40ad8a83199c261ae9fe to your computer and use it in GitHub Desktop.
teamoji
<script type="text/template" id="tmpl-cell">
<div class="input mb-2">
<input data-bind="value: character, attr: {id: 'clip-'+name(), 'data-clipboard-target':'#clip-'+name(), title: name()}" type="text" class="form-control box1" placeholder="" aria-label="" aria-describedby="basic-addon1">
</div>
</script>
<script type="text/template" id="tmpl-snippet">
<div>
<input class="box3 fsnippet" data-bind="value: value, attr: {id: 'snippet-'+id()}" />
<button class="btn" data-bind="attr: {'data-clipboard-target':'#snippet-'+id()}">
<i class="fa fa-copy"></i>
</button>
<button class="btn" data-bind="click: () => {$parent.remove($parent)}">
<i class="fa fa-minus" ></i>
</button>
</div>
</script>
<script type="text/template" id="tmpl-grid">
<div class="wrapper" data-bind="foreach: collection">
<special-character params="character: character, name: name" />
</div>
</script>
<script type="text/template" id="tmpl-snippets">
<div class="input-group mb-3">
<input class="form-control box2" placeholder="add new snippet" data-bind="value: newSnippetValue"/>
<div class="input-group-append">
<button class="btn btn-outline-secondary"data-bind="click: add">
<i class="fa fa-plus" ></i>
</button>
</div>
</div>
<div data-bind="foreach: collection">
<snippet params="snippetModel: $data" />
</div>
</script>
<div class="py-5 text-center">
<h2>Teamoji</h2>
<p class="lead">an emoji, special character, and snippets app</p>
<p>Click On Any Item to Copy It</p>
</div>
<div id="app" class="container h-100 py-2">
<ul class="nav nav-tabs border-0" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link border border-primary border-bottom-0" id="character-tab" data-toggle="tab" href="#characters" role="tab" aria-controls="home">Characters</a>
</li>
<li class="nav-item">
<a class="nav-link active border border-warning border-bottom-0" id="emoji-tab" data-toggle="tab" href="#emojis" role="tab" aria-controls="emojis" >Emojis</a>
</li>
<li class="nav-item">
<a class="nav-link border border-danger border-bottom-0" id="snippet-tab" data-toggle="tab" href="#snippets" role="tab" aria-controls="snippets" >Snippets</a>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane h-100 p-3 border border-primary" id="characters" role="tabpanel" aria-labelledby="character-tab">
<div class="well">
<div class="wrapper-special-character">
<special-characters />
</div>
</div>
</div>
<div class="tab-pane h-100 p-3 active border border-warning" id="emojis" role="tabpanel" aria-labelledby="emojis-tab">
<div class="well">
<div class="wrapper wrapper-emojis">
<emojis />
</div>
</div>
</div>
<div class="tab-pane h-100 p-3 border border-danger" id="snippets" role="tabpanel" aria-labelledby="snippets-tab">
<div class="well">
<div class="wrapper-snippet">
<snippets />
</div>
</div>
</div>
</div>
</div>
</div>
const chars = _.map(["±", "®", "¶", "§", "µ", "¢", "£", "¤", "¥", "¦", "§", "¨", "©", "«", "¬", "°", "¼", "½", "¿", "×", "√","∑", "∫", "∞"], (character, i) => ({name:`char-${i}`, character}));
const store = new Basil({
namespace: 'teamoji',
storages: ['cookie', 'local'],
storage: 'local',
expireDays: 365
});
const root = {
snippets: ko.observableArray()
};
const Store = (KEY, overrides = {}) => {
const result = {
find: (crit) => {
var items = result.fetch();
return items.find(snip => snip.value === crit || snip.id === crit);
},
createModel: (value = "") => ({value, order: -1, id: -1})
,
update: (snippet) => {
if(snippet.value === "") return;
const snippets = result.fetch();
const found = result.find(snippet.id);
if(!found) {
snippet.id = result.nextId();
snippet.order = snippet.id;
snippets.push(snippet);
} else {
snippets[result.getIndex(snippet)] = snippet;
}
store.set(KEY, snippets);
},
getIndex: (snippet) => result.fetch().map(snip => snip.id).indexOf(snippet.id) + 1
,
remove: (snippet) => {
const snippets = result.fetch();
_.remove(snippets, (snip) => snip.id === snippet.id);
store.set(KEY, snippets);
},
fetch: () => {
const fetched = store.get(KEY) || [];
return _.orderBy(fetched, "order");
},
nextId: () => {
var last = _.last(result.fetch());
return (last ? last['id'] : 0) + 1;
},
reset: () => store.set(KEY, null)
};
return _.assign({}, result, overrides);
};
const charStore = window.charStore = (() => {
const _charStore = {
createModel:(character) => ({character, order: -1, id: -1}),
find: (crit) => {
var items = result.fetch();
return items.find(char => char.character === crit || char.id === crit);
}
}
return Store('special-characters', _charStore);
})();
const snippetStore = Store('snippets');
ko.components.register('special-character', {
template: $('#tmpl-cell').html(),
viewModel: function (props) {
var vm = {
character: ko.observable(props.character),
name: ko.observable(props.name)
};
return vm;
}
});
ko.components.register('snippet', {
template: $('#tmpl-snippet').html(),
viewModel: function (props) {
var vm = {
value: ko.observable(props.snippetModel.value),
id: ko.observable(props.snippetModel.id),
order: ko.observable(props.snippetModel.order)
};
return vm;
}
});
ko.components.register('special-characters', {
template: $('#tmpl-grid').html(),
viewModel: function (props) {
var vm = {
collection: ko.observableArray(chars)
};
return vm;
}
});
ko.components.register('emojis', {
template: $('#tmpl-grid').html(),
viewModel: function (props) {
var vm = {
collection: ko.observableArray(emojis)
};
return vm;
}
});
ko.components.register('snippets', {
template: $('#tmpl-snippets').html(),
viewModel: function (props) {
var vm = {
collection: ko.observable([]),
update: (snippet) => {
snippetStore.update(snippet);
vm.refetch();
},
remove: (snippet) => {
snippetStore.remove(snippet);
vm.refetch();
},
refetch: () => {
vm.collection(fetch());
},
add:() => {
var model = snippetStore.createModel(vm.newSnippetValue());
snippetStore.update(model);
vm.newSnippetValue('');
vm.refetch();
},
newSnippetValue: ko.observable('')
};
const fetch = () => _.map(snippetStore.fetch(), snip => _.assign({remove: vm.remove, update:vm.update}, snip));
vm.collection(fetch());
return vm;
}
});
(($) => {
ko.applyBindings(root, $('#app')[0]);
var clipboard = new ClipboardJS('.box1');
})(jQuery);
const _emojis = {
"hello":"( ͡° ͜ʖ ͡°)"
,"shrug face ":"¯\\_(ツ)_/¯"
,"meh":"¯\\(°_o)/¯"
,"squinty":"( ^_^)"
,"confused ":"¿ⓧ_ⓧﮌ"
,"confused scratch":"(⊙.☉)7"
,"zoned":"(⊙_◎)"
,"crazy":"ミ●﹏☉ミ"
,"seal":"(ᵔᴥᵔ)"
,"Winning!":"(•̀ᴗ•́)و ̑̑"
,"wizard":"(∩`-´)⊃━☆゚.*・。゚"
,"Zombie":"[¬º-°]¬"
,"eh":"゜-゜"
,"innocent face ":"ʘ‿ʘ"
,"cute bear ":"ʕ•ᴥ•ʔ"
,"squinting bear":"ʕᵔᴥᵔʔ"
,"GTFO Bear":"ʕ •`ᴥ•´ʔ"
,"cute face with big eyes ":"(。◕‿◕。)"
,"surprised / loudmouthed ":"( ゚Д゚)"
,"feel perky ":"(`・ω・´)"
//,"angry face":"(╬ ಠ益ಠ)"
,"excited ":"☜(⌒▽⌒)☞"
,"happy face ":"ヽ(´▽`)/"
,"basking in glory ":"ヽ(´ー`)ノ"
,"kitty emote":"ᵒᴥᵒ#"
,"fido":"V•ᴥ•V"
,"meow":"ฅ^•ﻌ•^ฅ"
,"flexing ":"ᕙ(⇀‸↼‶)ᕗ"
,"do you even lift bro?":"ᕦ(ò_óˇ)ᕤ"
,"kirby":"⊂(◉‿◉)つ"
,"tripping out ":"q(❂‿❂)p"
,"discombobulated ":"⊙﹏⊙"
,"sad and confused ":"¯\\_(⊙︿⊙)_/¯"
,"worried":"(´・_・`)"
,"dear god why ":"щ(゚Д゚щ)"
,"staring ":"٩(๏_๏)۶"
,"strut":"ᕕ( ᐛ )ᕗ"
,"angry troll":"ヽ༼ ಠ益ಠ ༽ノ"
,"cry face":"。゚( ゚இ‸இ゚)゚。"
,"cry troll":"༼ ༎ຶ ෴ ༎ຶ༽"
,"TGIF":"“ヽ(´▽`)ノ”"
,"dancing ":"┌(ㆆ㉨ㆆ)ʃ"
,"angry birds":"( ఠൠఠ )ノ"
,"no support ":"乁( ◔ ౪◔)「"
,"shy ":"(๑•́ ₃ •̀๑) "
,"fly away":"⁽⁽ଘ( ˊᵕˋ )ଓ⁾⁾"
,"careless":"◔_◔"
,"Heart":"♥"
,"shark face / jagged mustache":"( ˇ෴ˇ )"
,"emo dance ":"ヾ(-_- )ゞ"
,"dance ":"♪♪ ヽ(ˇ∀ˇ )ゞ"
,"opera":"ヾ(´〇`)ノ♪♪♪"
,"winnie the pooh":"ʕ •́؈•̀)"
,"fight":"(ง'̀-'́)ง"
,"listening to headphones":"◖ᵔᴥᵔ◗ ♪ ♫ "
,"robot":"{•̃_•̃}"
,"questionable / dislike":"(Ծ‸ Ծ)"
,"pointing":"(☞゚ヮ゚)☞"
,"chasing / running away":"''⌐(ಠ۾ಠ)¬'''"
,"whistling / music":"(っ•́。•́)♪♬"
,"injured":"(҂◡_◡) "
,"eye roll":"⥀.⥀"
,"flying":"ح˚௰˚づ "
,"things that can't be unseen":"♨_♨"
,"looking down":"(._.)"
,"yum":"(っ˘ڡ˘ς)"
,"judging":"( ఠ ͟ʖ ఠ)"
,"satisfied":"(◠﹏◠)"
,"sad and crying":"(ᵟຶ︵ ᵟຶ)"
,"chicken":"ʚ(•`"
,"straining":"(⩾﹏⩽)"
,"Happy Hug":"\\(ᵔᵕᵔ)/"
,"doe eyes happy":"◕‿◕"
};
var emojis = _.map(_.keys(_emojis), (k) =>({name:_.camelCase(k), character:_emojis[k]}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.4/clipboard.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/basil.js/0.4.10/basil.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/masonry/4.2.2/masonry.pkgd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/draggable/1.0.0-beta.8/draggable.min.js"></script>
body,html {
height: 100%;
}
#app {
width:350px;
}
/* when not active use specificity to override the !important on border-(color) */
.nav-tabs .nav-link:not(.active) {
border-color: transparent !important;
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 10px;
font-size: 150%;
}
.box:nth-child(even) {
background-color: #ccc;
color: #000;
}
.wrapper {
width: 300px;
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(2, 150px);
height: 500px;
overflow-y: auto;
overflow-x:hidden;
}
.wrapper-special-character {
width: 290px;
display: grid;
grid-gap: 5px;
grid-template-columns: repeat(2, 140px);
}
.wrapper-snippet {
width: 300px;
}
.fa {
font-size:10px;
}
input {
width: 90px;
}
input.snippet {
width: 200px;
}
h1 {
font-size: 25px;
}
h1 > sub {
font-size:10px;
}
.wrapper-special-character input[type=text]:focus {
box-shadow: 0 0 5px rgba(81, 203, 238, 1);
border: 2px solid rgba(81, 203, 238, 1);
}
.wrapper-special-character input[type=text]:hover {
box-shadow: 0 0 5px rgba(81, 203, 238, 1);
border: 2px solid rgba(81, 203, 238, 1);
}
.wrapper-emojis input[type=text]:focus {
box-shadow: 0 0 5px rgb(237, 173, 26);
border: 2px solid rgb(237, 173, 26);
}
.wrapper-emojis input[type=text]:hover {
box-shadow: 0 0 5px rgb(237, 173, 26);
border: 2px solid rgb(237, 173, 26);
}
.box1 {
background-color: #e6e9ef;
color: #000;
border-radius: 5px;
padding: 5px;
font-size: 100%;
width: 140px;
}
.box2 {
background-color: #e6e9ef;
color: #000;
border-radius: 5px;
padding: 5px;
font-size: 100%;
width: 120px;
}
.box3 {
color: #000;
font-size: 100%;
width: 220px;
border: 1px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment