mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
Merge branch 'master' of http://github.com/amark/gun
This commit is contained in:
commit
78ae966813
@ -167,7 +167,7 @@ Technically, **GUN is a graph synchronization protocol** with a *lightweight emb
|
||||
|
||||
This would not be possible without **community contributors**, big shout out to:
|
||||
|
||||
**[ajmeyghani](https://github.com/ajmeyghani) ([Learn GUN Basics with Diagrams](https://medium.com/@ajmeyghani/gundb-a-graph-database-in-javascript-3860a08d873c))**; **[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[Lightnet](https://github.com/Lightnet)** ([Awesome Vue User Examples](https://glitch.com/edit/#!/jsvuegunui?path=README.md:1:0) & [User Kitchen Sink Playground](https://gdb-auth-vue-node.glitch.me/)); **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; **[rogowski](https://github.com/rogowski) (AXE)**; [sbeleidy](https://github.com/sbeleidy); **[sbiaudet](https://github.com/sbiaudet) ([C# Port](https://github.com/sbiaudet/cs-gun))**; **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Shadyzpop](https://github.com/Shadyzpop) ([React Native example](https://github.com/amark/gun/tree/master/examples/react-native))**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[xmonader](https://github.com/xmonader) ([Python Port](https://github.com/xmonader/pygundb))**; **[88dev](https://github.com/88dev) ([Database Viewer](https://github.com/88dev/gun-show))**;
|
||||
**[ajmeyghani](https://github.com/ajmeyghani) ([Learn GUN Basics with Diagrams](https://medium.com/@ajmeyghani/gundb-a-graph-database-in-javascript-3860a08d873c))**; **[anywhichway](https://github.com/anywhichway) ([Block Storage](https://github.com/anywhichway/gun-block))**; **[beebase](https://github.com/beebase) ([Quasar](https://github.com/beebase/gun-vuex-quasar))**; **[BrockAtkinson](https://github.com/BrockAtkinson) ([brunch config](https://github.com/BrockAtkinson/brunch-gun))**; **[Brysgo](https://github.com/brysgo) ([GraphQL](https://github.com/brysgo/graphql-gun))**; **[d3x0r](https://github.com/d3x0r) ([SQLite](https://github.com/d3x0r/gun-db))**; **[forrestjt](https://github.com/forrestjt) ([file.js](https://github.com/amark/gun/blob/master/lib/file.js))**; **[hillct](https://github.com/hillct) (Docker)**; **[JosePedroDias](https://github.com/josepedrodias) ([graph visualizer](http://acor.sl.pt:9966))**; **[JuniperChicago](https://github.com/JuniperChicago) ([cycle.js bindings](https://github.com/JuniperChicago/cycle-gun))**; **[jveres](https://github.com/jveres) ([todoMVC](https://github.com/jveres/todomvc))**; **[kristianmandrup](https://github.com/kristianmandrup) ([edge](https://github.com/kristianmandrup/gun-edge))**; **[Lightnet](https://github.com/Lightnet)** ([Awesome Vue User Examples](https://glitch.com/edit/#!/jsvuegunui?path=README.md:1:0) & [User Kitchen Sink Playground](https://gdb-auth-vue-node.glitch.me/)); **[lmangani](https://github.com/lmangani) ([Cytoscape Visualizer](https://github.com/lmangani/gun-scape), [Cassandra](https://github.com/lmangani/gun-cassandra), [Fastify](https://github.com/lmangani/fastify-gundb), [LetsEncrypt](https://github.com/lmangani/polyGun-letsencrypt))**; **[mhelander](https://github.com/mhelander) ([SEA](https://github.com/amark/gun/blob/master/sea.js))**; [omarzion](https://github.com/omarzion) ([Sticky Note App](https://github.com/omarzion/stickies)); [PsychoLlama](https://github.com/PsychoLlama) ([LevelDB](https://github.com/PsychoLlama/gun-level)); **[RangerMauve](https://github.com/RangerMauve) ([schema](https://github.com/gundb/gun-schema))**; **[robertheessels](https://github.com/swifty) ([gun-p2p-auth](https://github.com/swifty/gun-p2p-auth))**; **[rogowski](https://github.com/rogowski) (AXE)**; [sbeleidy](https://github.com/sbeleidy); **[sbiaudet](https://github.com/sbiaudet) ([C# Port](https://github.com/sbiaudet/cs-gun))**; **[Sean Matheson](https://github.com/ctrlplusb) ([Observable/RxJS/Most.js bindings](https://github.com/ctrlplusb/gun-most))**; **[Shadyzpop](https://github.com/Shadyzpop) ([React Native example](https://github.com/amark/gun/tree/master/examples/react-native))**; **[sjones6](https://github.com/sjones6) ([Flint](https://github.com/sjones6/gun-flint))**; **[Stefdv](https://github.com/stefdv) (Polymer/web components)**; **[zrrrzzt](https://github.com/zrrrzzt) ([JWT Auth](https://gist.github.com/zrrrzzt/6f88dc3cedee4ee18588236756d2cfce))**; **[xmonader](https://github.com/xmonader) ([Python Port](https://github.com/xmonader/pygundb))**;
|
||||
|
||||
I am missing many others, apologies, will be adding them soon!
|
||||
|
||||
|
@ -1,156 +1,213 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Converse</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<link href='https://fonts.googleapis.com/css?family=Poiret+One' rel='stylesheet' type='text/css'>
|
||||
<style>
|
||||
#converse {
|
||||
font-size: 16pt;
|
||||
}
|
||||
#converse .box {
|
||||
margin-bottom: 0.2em;
|
||||
padding: 1em;
|
||||
border-radius: 0.1em;
|
||||
}
|
||||
#converse b:after {
|
||||
content: " ";
|
||||
}
|
||||
#converse li .when {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -2em;
|
||||
padding: 0.5em 1em;
|
||||
background: rgba(100%,100%,100%,0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
#converse li:hover .when {
|
||||
opacity: 1;
|
||||
right: 0em;
|
||||
}
|
||||
.poiret {
|
||||
font-family: 'Poiret One', sans-serif;
|
||||
}
|
||||
.large {
|
||||
font-size: 200%;
|
||||
}
|
||||
#converse .what, #converse .who {
|
||||
cursor: text;
|
||||
outline: none;
|
||||
display: inline;
|
||||
min-width: 1em;
|
||||
padding-left: 1px;
|
||||
}
|
||||
[contentEditable=true]:empty:not(:focus):before{
|
||||
content:attr(data-text)
|
||||
}
|
||||
|
||||
#title {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
<head>
|
||||
<title>Converse</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<link href='https://fonts.googleapis.com/css?family=Poiret+One' rel='stylesheet' type='text/css'>
|
||||
<style>
|
||||
.chat__heading {
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.say {
|
||||
margin: 0 0 0.4em 0.4em;
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
.chat__form-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#name-input {
|
||||
margin-top: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.chat__form {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 50px;
|
||||
background-color: white;
|
||||
border: 2px solid white;
|
||||
max-width: 900px;
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#message-input {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="converse" class="hue2 page">
|
||||
<div class="pad">
|
||||
<div id='title' class="poiret large rubric whitet">Have a Conversation...</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li class="none"></li>
|
||||
</ul>
|
||||
.chat__name-input {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
<form class="white huet2 box">
|
||||
<div>
|
||||
<div class="say hue2 right whitet box act">say</div>
|
||||
<b id="name-input" class="jot left who" contenteditable="true" data-text="Name"></b>
|
||||
<p id="message-input" class="jot left what" contenteditable="true" data-text="Write a message..."></p>
|
||||
</div>
|
||||
</form>
|
||||
.chat__message-input {
|
||||
flex: 5;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
<div class="model">
|
||||
<li class="white huet2 box">
|
||||
<b class="who"></b>
|
||||
<p class="what"></p>
|
||||
<span class="sort none">0</span>
|
||||
<div class="when"></div>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
.chat__submit {
|
||||
padding: 10px;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/nts.js"></script>
|
||||
<script>
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
var chat = gun.get('converse/' + location.hash.slice(1));
|
||||
.chat__submit:hover::after {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
$("form .say").on('click', submit);
|
||||
$("form .what").on('keydown', enter);
|
||||
function enter(e){
|
||||
if(e.which !== 13){ return }
|
||||
submit(e);
|
||||
}
|
||||
function submit(e){
|
||||
e.preventDefault();
|
||||
.chat__submit:focus::after {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
var msg = {when: Gun.time.is()};
|
||||
.chat__submit::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 5px;
|
||||
transition: background-color 0.3s;
|
||||
background-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
msg.who = $('form .who').text();
|
||||
if(!msg.who){
|
||||
msg.who = 'user' + Gun.text.random(3);
|
||||
$('form .who').text(msg.who);
|
||||
}
|
||||
.chat__message-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 60px 20px;
|
||||
width: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
msg.what = $('form .what').text();
|
||||
if(!msg.what){ return }
|
||||
.chat__message {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
chat.set(msg);
|
||||
$('form .what').text('');
|
||||
}
|
||||
.chat__name {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
chat.map().val(function(msg, id){
|
||||
if(!msg){ return }
|
||||
var ul = $('ul');
|
||||
var last = sort(msg.when, ul.children('li').last());
|
||||
.chat__when {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 2em;
|
||||
padding: 10px;
|
||||
background: rgba(100%, 100%, 100%, 0.9);
|
||||
opacity: 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
var li = $("#msg-" + id)[0]; // grab if exists
|
||||
if(!li){
|
||||
li = $('.model li').clone(true) // else create it
|
||||
.attr('id', 'msg-' + id)
|
||||
.insertAfter(last);
|
||||
}
|
||||
.chat__message:hover .chat__when {
|
||||
opacity: 1;
|
||||
right: 0em;
|
||||
}
|
||||
|
||||
// bind the message data into the UI
|
||||
li = $(li);
|
||||
li.find('.who').text(msg.who);
|
||||
li.find('.what').text(msg.what);
|
||||
li.find('.sort').text(msg.when);
|
||||
@media (max-width: 567px) {
|
||||
.chat__heading {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
var time = new Date(msg.when);
|
||||
li.find('.when').text(time.toDateString() + ', ' + time.toLocaleTimeString());
|
||||
<body>
|
||||
<div class="chat hue2 page">
|
||||
<h2 id='title' class="chat__heading hue2 whitet">Have a Conversation...</h2>
|
||||
<ul class="chat__message-list">
|
||||
<li class="none"></li>
|
||||
</ul>
|
||||
|
||||
$('html, body').stop(true, true)
|
||||
.animate({scrollTop: ul.height()});
|
||||
});
|
||||
<div class="chat__form-container hue2">
|
||||
<form class="chat__form">
|
||||
<label for="name-input" class="visually-hidden">Name</label>
|
||||
<input id="name-input" class="chat__name-input" placeholder="Name"></input>
|
||||
<label for="message-input" class="visually-hidden">Message</label>
|
||||
<input id="message-input" class="chat__message-input" placeholder="Write a message..."></input>
|
||||
<button class="chat__submit say hue2">say</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
function sort(num, li){ return parseFloat(num) >= parseFloat($(li).find('.sort').text() || -Infinity)? li : sort(num, li.prev()) }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<div class="model">
|
||||
<li class="chat__message white huet2 box">
|
||||
<b class="chat__name"></b>
|
||||
<p class="chat__message-text"></p>
|
||||
<span class="sort none">0</span>
|
||||
<div class="chat__when"></div>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/nts.js"></script>
|
||||
<script>
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
var chat = gun.get('converse/' + location.hash.slice(1));
|
||||
|
||||
$(".chat__submit").on('click', submit);
|
||||
$(".chat_form").on('keydown', enter);
|
||||
function enter(e) {
|
||||
if (e.which !== 13) { return }
|
||||
submit(e);
|
||||
}
|
||||
function submit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var msg = { when: Gun.time.is() };
|
||||
|
||||
msg.who = $('.chat__name-input').val();
|
||||
if (!msg.who) {
|
||||
msg.who = 'user' + Gun.text.random(3);
|
||||
$('.chat__name-input').val(msg.who);
|
||||
}
|
||||
|
||||
msg.what = $('.chat__message-input').val();
|
||||
if (!msg.what) { return }
|
||||
|
||||
chat.set(msg);
|
||||
$('.chat__message-input').val('').focus();
|
||||
}
|
||||
|
||||
chat.map().val(function (msg, id) {
|
||||
if (!msg) { return }
|
||||
var messageList = $('.chat__message-list');
|
||||
var last = sort(msg.when, messageList.children('li').last());
|
||||
|
||||
var li = $("#msg-" + id)[0]; // grab if exists
|
||||
if (!li) {
|
||||
li = $('.model li').clone(true) // else create it
|
||||
.attr('id', 'msg-' + id)
|
||||
.insertAfter(last);
|
||||
}
|
||||
|
||||
// bind the message data into the UI
|
||||
li = $(li);
|
||||
li.find('.chat__name').text(msg.who);
|
||||
li.find('.chat__message-text').text(msg.what);
|
||||
li.find('.sort').text(msg.when);
|
||||
|
||||
var time = new Date(msg.when);
|
||||
li.find('.chat__when').text(time.toDateString() + ', ' + time.toLocaleTimeString());
|
||||
|
||||
$('html, body').stop(true, true)
|
||||
.animate({ scrollTop: messageList.height() });
|
||||
});
|
||||
|
||||
function sort(num, li) { return parseFloat(num) >= parseFloat($(li).find('.sort').text() || -Infinity) ? li : sort(num, li.prev()) }
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -313,4 +313,15 @@ ul, li {
|
||||
} @keyframes joy {
|
||||
0% {background-position: 0 0;}
|
||||
100% {background-position: -2800px 0;}
|
||||
}
|
||||
}
|
||||
|
||||
.visually-hidden {
|
||||
border: 0;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
@ -1,83 +1,151 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Think</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="think" class="hue page">
|
||||
<link href='https://fonts.googleapis.com/css?family=Alegreya+Sans:300italic' rel='stylesheet' type='text/css'>
|
||||
<style>
|
||||
#think {
|
||||
font-size: 24pt;
|
||||
font-size: 6vmin;
|
||||
font-family: 'Alegreya Sans', sans-serif;
|
||||
color: white;
|
||||
}
|
||||
#think li {
|
||||
width: 90%;
|
||||
margin-top: 0.3em;
|
||||
border-bottom: 1px dashed white;
|
||||
}
|
||||
#think .add {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
padding: 0.5em;
|
||||
font-family: Tahoma, arial;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#think ul, #think li {
|
||||
list-style-type: circle;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
</style>
|
||||
<div class="pad whitet" style="width: 75%;">
|
||||
<div style="margin-top: 2%;">
|
||||
<div class="rubric left center">Add a Thought...</div>
|
||||
<a href="#" class="right huet white act add">+</a>
|
||||
</div>
|
||||
<ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/nts.js"></script>
|
||||
<script>
|
||||
// Check out the interactive tutorial
|
||||
// for how to build a simplified version
|
||||
// of this example: https://scrimba.com/c/cW2Vsa
|
||||
var gun = Gun(location.origin+'/gun');
|
||||
var think = gun.get('think/' + location.hash.slice(1));
|
||||
var typing, throttle;
|
||||
$('.add').on('click', function(){
|
||||
$('<li>').attr('contenteditable', true).prependTo('ul');
|
||||
});
|
||||
$(document).on('keyup', "[contenteditable=true]", function(){
|
||||
var li = $(this), id = li.attr('id');
|
||||
if(!id){
|
||||
li.attr('id', id = Gun.text.random());
|
||||
}
|
||||
typing = id;
|
||||
clearTimeout(throttle);
|
||||
throttle = setTimeout(function(){
|
||||
think.get(id).put(li.text());
|
||||
typing = false;
|
||||
},10);
|
||||
});
|
||||
think.map().on(function(thought, id){
|
||||
var li = $('#'+id)[0] || $('<li>').attr('id', id).attr('contenteditable', true).prependTo('ul');
|
||||
if(thought){
|
||||
if(id === typing){ return }
|
||||
$(li).text(thought);
|
||||
} else {
|
||||
$(li).hide();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<head>
|
||||
<title>Think</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<link href='https://fonts.googleapis.com/css?family=Alegreya+Sans:300italic' rel='stylesheet' type='text/css'>
|
||||
<style>
|
||||
.thought {
|
||||
font-family: 'Alegreya Sans', sans-serif;
|
||||
}
|
||||
|
||||
.thought__heading {
|
||||
text-align: center;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.thought__form-container {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.thought__item {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.thought__input {
|
||||
flex: 1;
|
||||
font-family: 'Alegreya Sans', sans-serif;
|
||||
font-size: 25px;
|
||||
font-weight: 500;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.thought__add {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-family: Tahoma, arial;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
background-color: white;
|
||||
font-size: 25px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.thought__add:hover::after {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.thought__add:focus::after {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.thought__add::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-radius: 50%;
|
||||
transition: background-color 0.3s;
|
||||
background-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.thought__list {
|
||||
list-style-type: circle;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 90px 20px;
|
||||
width: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
@media (max-width: 567px) {
|
||||
.thought__heading {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="thought hue page">
|
||||
<div class="thought__form-container hue">
|
||||
<h2 id='title' class="thought__heading hue">Add a thought...</h2>
|
||||
<button class="thought__add say huet">
|
||||
<span aria-hidden="true">+</span>
|
||||
<span class="visually-hidden">Add thought</span>
|
||||
</button>
|
||||
</div>
|
||||
<ul class="thought__list">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/nts.js"></script>
|
||||
<script>
|
||||
// Check out the interactive tutorial
|
||||
// for how to build a simplified version
|
||||
// of this example: https://scrimba.com/c/cW2Vsa
|
||||
var gun = Gun(location.origin + '/gun');
|
||||
var think = gun.get('think/' + location.hash.slice(1));
|
||||
var thoughtItemStr = function(id) { return '<li class="thought__item"><label class="visually-hidden" for="' + id + '">Thought</label><input id="' + id + '" class="thought__input huet"><li/>'}
|
||||
var typing, throttle;
|
||||
$('.thought__add').on('click', function () {
|
||||
$(thoughtItemStr('')).prependTo('.thought__list').find('.thought__input').focus();
|
||||
});
|
||||
$(document).on('keyup', '.thought__input', function () {
|
||||
var input = $(this), id = input.attr('id');
|
||||
if (!id) {
|
||||
input.attr('id', id = Gun.text.random());
|
||||
}
|
||||
typing = id;
|
||||
clearTimeout(throttle);
|
||||
throttle = setTimeout(function () {
|
||||
think.get(id).put(input.val());
|
||||
typing = false;
|
||||
}, 10);
|
||||
});
|
||||
think.map().on(function (thought, id) {
|
||||
var li = $('#' + id).parent()[0] || $(thoughtItemStr(id)).prependTo('.thought__list');
|
||||
if (thought) {
|
||||
if (id === typing) { return }
|
||||
$(li).find('.thought__input').val(thought);
|
||||
} else {
|
||||
$(li).hide();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
124
lib/promise.js
Normal file
124
lib/promise.js
Normal file
@ -0,0 +1,124 @@
|
||||
/* Promise Library v1.0 for GUN DB
|
||||
* Turn any part of a gun chain into a promise, that you can then use
|
||||
* .then().catch() pattern.
|
||||
* In normal gun doing var item = gun.get('someKey'), gun returns a reference
|
||||
* to the someKey synchroneously. Using a reference is quite helpful in making
|
||||
* graph structures, so I have chosen to follow the following paradigm.
|
||||
* Whenever a promise is resolved, gun will return an object of data, I will
|
||||
* wrap that data in an object together with the reference like so:
|
||||
* {ref: gunRef, data: data}.
|
||||
* This code is freely given in the spirit of open source MIT license.
|
||||
* Author: Jachen Duschletta / 2019
|
||||
*/
|
||||
|
||||
/*
|
||||
* Function promOnce
|
||||
* @param limit - due to promises resolving too fast if we do not set a timer
|
||||
* we will not be able receive any data back from gun before returning the promise
|
||||
* works both following a Chain.get and a Chain.map (limit only applies to map)
|
||||
* If no limit is chosen, defaults to 100 ms (quite sufficient to fetch about 2000 nodes or more)
|
||||
* @param opt - option object
|
||||
* @return {ref: gunReference, data: object / string (data), key: string (soulOfData)}
|
||||
*/
|
||||
|
||||
Gun.chain.promOnce = async function (limit, opt) {
|
||||
var gun = this, cat = gun._;
|
||||
if(!limit){limit = 100}
|
||||
if(cat.subs){
|
||||
var array = [];
|
||||
gun.map().once((data, key)=>{
|
||||
var gun = this;
|
||||
array.push(new Promise((res, rej)=>{
|
||||
res({ref: gun, data:data, key:key});
|
||||
})
|
||||
)
|
||||
}, opt);
|
||||
await sleep(limit);
|
||||
return Promise.all(array)
|
||||
} else {
|
||||
return (new Promise((res, rej)=>{
|
||||
gun.once(function (data, key) {
|
||||
var gun = this;
|
||||
res({ref:gun,data:data,key:key});
|
||||
}, opt);
|
||||
}))
|
||||
}
|
||||
var chain = gun.chain();
|
||||
return chain;
|
||||
}
|
||||
|
||||
function sleep (limit) {
|
||||
return (new Promise((res, rej)=>{
|
||||
setTimeout(res, limit);
|
||||
}))
|
||||
}
|
||||
|
||||
/*
|
||||
* Function promPut
|
||||
* @param item (string / object) - item to be put to that key in the chain
|
||||
* @param opt - option object
|
||||
* @return object - Returns an object with the ref to that node that was just
|
||||
* created as well as the 'ack' which acknowledges the put was succesful
|
||||
* object {ref: gunReference, ack: acknowledgmentObject}
|
||||
* If put had an error we can catch the return via .catch
|
||||
*/
|
||||
|
||||
Gun.chain.promPut = async function (item, opt) {
|
||||
var gun = this;
|
||||
return (new Promise((res, rej)=>{
|
||||
gun.put(item, function(ack) {
|
||||
if(ack.err){rej(ack.err)}
|
||||
res({ref:gun, ack:ack});
|
||||
}, opt);
|
||||
}))
|
||||
}
|
||||
|
||||
/*
|
||||
* Function promSet
|
||||
* @param item (string / object) - item to be set into a list at this key
|
||||
* @param opt - option object
|
||||
* @return object - Returns object with the ref to that node that was just
|
||||
* created as well as the 'ack' which acknowledges the set was succesful
|
||||
* object {ref: gunReference, ack: acknowledgmentObject}
|
||||
* If set had an error we can catch the return via .catch
|
||||
*/
|
||||
|
||||
Gun.chain.promSet = async function(item, opt){
|
||||
var gun = this, soul;
|
||||
var cb = cb || function(){};
|
||||
opt = opt || {}; opt.item = opt.item || item;
|
||||
return (new Promise(async function (res,rej) {
|
||||
if(soul = Gun.node.soul(item)){ item = Gun.obj.put({}, soul, Gun.val.link.ify(soul)) }
|
||||
if(!Gun.is(item)){
|
||||
if(Gun.obj.is(item)){;
|
||||
item = await gun.back(-1).get(soul = soul || Gun.node.soul(item) || gun.back('opt.uuid')()).promPut(item);
|
||||
item = item.ref;
|
||||
}
|
||||
res(gun.get(soul || (Gun.state.lex() + Gun.text.random(7))).promPut(item));
|
||||
}
|
||||
item.get(function(soul, o, msg){
|
||||
var ack = {};
|
||||
if(!soul){ rej({ack:{err: Gun.log('Only a node can be linked! Not "' + msg.put + '"!')}} ) }
|
||||
gun.put(Gun.obj.put({}, soul, Gun.val.link.ify(soul)), cb, opt);
|
||||
},true);
|
||||
res({ref:item, ack:{ok:0}});
|
||||
}))
|
||||
}
|
||||
|
||||
/*
|
||||
* Function promOn
|
||||
* @param callback (function) - function to be called upon changes to data
|
||||
* @param option (object) - {change: true} only allow changes to trigger the callback
|
||||
* @return - data and key
|
||||
* subscribes callback to data
|
||||
*/
|
||||
|
||||
Gun.chain.promOn = async function (callback, option) {
|
||||
var gun = this;
|
||||
return (new Promise((res, rej)=>{
|
||||
gun.on(function (data, key){
|
||||
callback(data, key);
|
||||
res(data, key);
|
||||
}, option);
|
||||
}));
|
||||
}
|
@ -55,4 +55,4 @@ Gun.on('opt', function(root){
|
||||
stats.gap = {};
|
||||
}, 1000 * 15);
|
||||
Object.keys = Object.keys || function(o){ return Gun.obj.map(o, function(v,k,t){t(k)}) }
|
||||
});
|
||||
});
|
||||
|
19
lib/then.js
19
lib/then.js
@ -1,16 +1,21 @@
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
|
||||
// Returns a gun reference in a promise and then calls a callback if specified
|
||||
Gun.chain.promise = function(cb) {
|
||||
var gun = this, cb = cb || function(ctx) { return ctx };
|
||||
return (new Promise(function(res, rej) {
|
||||
gun.once(function(data, key){
|
||||
res({put: data, get: key, gun: this});
|
||||
res({put: data, get: key, gun: this}); // gun reference is returned by promise
|
||||
});
|
||||
})).then(cb);
|
||||
})).then(cb); //calling callback with resolved data
|
||||
};
|
||||
|
||||
Gun.chain.then = function(cb) {
|
||||
return this.promise(function(res){
|
||||
return cb? cb(res.put) : res.put;
|
||||
});
|
||||
};
|
||||
// Returns a promise for the data, key of the gun call
|
||||
Gun.chain.then = function() {
|
||||
var gun = this;
|
||||
return (new Promise((res, rej)=>{
|
||||
gun.once(function (data, key) {
|
||||
res(data, key); //call resolve when data is returned
|
||||
})
|
||||
}))
|
||||
};
|
||||
|
@ -13,7 +13,7 @@
|
||||
var epriv = pair.epriv;
|
||||
var ecdhSubtle = shim.ossl || shim.subtle;
|
||||
var pubKeyData = keysToEcdhJwk(pub);
|
||||
var props = Object.assign(S.ecdh, { public: await ecdhSubtle.importKey(...pubKeyData, true, []) });
|
||||
var props = Object.assign({ public: await ecdhSubtle.importKey(...pubKeyData, true, []) },S.ecdh);
|
||||
var privKeyData = keysToEcdhJwk(epub, epriv);
|
||||
var derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']).then(async (privKey) => {
|
||||
// privateKey scope doesn't leak out from here!
|
||||
@ -47,4 +47,4 @@
|
||||
}
|
||||
|
||||
module.exports = SEA.secret;
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user