Merge pull request #2238 from urbit/mp/os1/launch

launch: os1 home screen
This commit is contained in:
Logan 2020-02-06 11:26:43 -08:00 committed by GitHub
commit 31e9505c76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 465 additions and 138921 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,17 @@
==
=, format
::
|%
::
+$ card card:agent:gall
+$ versioned-state
$% state-zero
==
+$ state-zero [%0 data=json]
--
%+ verb |
=| state-zero
=* state -
^- agent:gall
|_ =bowl:gall
+* this .
@ -17,7 +27,7 @@
++ on-init
^- (quip card:agent:gall _this)
=/ launcha
[%launch-action !>([%clock /tile '/~clock/js/tile.js'])]
[%launch-action !>([%clock /clocktile '/~clock/js/tile.js'])]
:_ this
:~ [%pass / %arvo %e %connect [~ /'~clock'] %clock]
[%pass /clock %agent [our.bowl %launch] %poke launcha]
@ -39,6 +49,9 @@
++ on-poke
|= [=mark =vase]
^- (quip card:agent:gall _this)
|^
?: ?=(%json mark)
(poke-json !<(json vase))
?. ?=(%handle-http-request mark)
(on-poke:def mark vase)
=+ !<([eyre-id=@ta =inbound-request:eyre] vase)
@ -59,15 +72,23 @@
?: =(name 'tile')
(js-response:gen tile-js)
not-found:gen
::
++ poke-json
|= jon=json
^- (quip card:agent:gall _this)
=. data.state jon
:_ this
[%give %fact ~[/clocktile] %json !>(jon)]~
--
::
++ on-watch
|= =path
^- (quip card:agent:gall _this)
?: ?=([%http-response *] path)
`this
?. =(/tile path)
?. =(/clocktile path)
(on-watch:def path)
[[%give %fact ~ %json !>(*json)]~ this]
[[%give %fact ~ %json !>(data.state)]~ this]
::
++ on-leave on-leave:def
++ on-peek on-peek:def

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 B

File diff suppressed because one or more lines are too long

View File

@ -20,62 +20,35 @@ export default class ChatTile extends Component {
});
}
let invSuffix = (inviteNum === 1) ? (
<span>Invite</span>
) : (
<span>Invites</span>
);
let numInvElem = (inviteNum > 0) ? (
<p className="absolute white"
style={{
top: 180,
fontWeight: 600,
fontSize: 16,
lineHeight: '20px'
}}>
<span style={{
color: '#2AA779'
}}>{inviteNum} </span>
{invSuffix}
</p>
) : (
<div />
);
let notificationsNum = inviteNum + msgNum;
let msgSuffix = (msgNum === 1) ? (
<span>New Message</span>
) : (
<span>New Messages</span>
);
let numMsgElem = (msgNum > 0) ? (
<p className="absolute white"
style={{
top: 207,
fontWeight: 600,
fontSize: 16,
lineHeight: '20px'
}}>
<span style={{
color: '#2AA779'
}}>{msgNum} </span>
{msgSuffix}
</p>
) : (
<div />
);
let numNotificationsElem =
notificationsNum > 0 ? (
<p
className="absolute green2"
style={{
bottom: 6,
fontWeight: 400,
fontSize: 12,
lineHeight: "20px"
}}>
{notificationsNum > 99 ? "99+" : notificationsNum}
</p>
) : (
<div />
);
return (
<div className="w-100 h-100 relative" style={{ background: '#1a1a1a' }}>
<div className="w-100 h-100 relative bg-white ba b--black">
<a className="w-100 h-100 db pa2 no-underline" href="/~chat">
<p className="gray label-regular b absolute" style={{left: 8, top: 4}}>Chat</p>
<p className="black gray absolute f9" style={{left: 8, top: 8}}>Messaging</p>
<img
className="absolute"
style={{ left: 68, top: 65 }}
style={{ left: 39, top: 39 }}
src="/~chat/img/Tile.png"
width={106}
height={98} />
{numInvElem}
{numMsgElem}
width={48}
height={48} />
{numNotificationsElem}
</a>
</div>
);

View File

@ -3,8 +3,8 @@ import classnames from 'classnames';
import moment from 'moment'
import SunCalc from 'suncalc'
const outerSize = 234; //tile size
const innerSize = 218; //clock size
const outerSize = 124; //tile size
const innerSize = 124; //clock size
//polar to cartesian
// var ptc = function(r, theta) {
@ -105,17 +105,12 @@ class Clock extends Component {
}
componentDidMount() {
this.canvas = initCanvas(
this.canvasRef,
{ x: innerSize, y: innerSize },
4
);
navigator.geolocation.getCurrentPosition((res) => {
const lat = res.coords.latitude
const lon = res.coords.longitude
initGeolocation() {
if (typeof this.props.data === 'string') {
// console.log(typeof this.props.data)
const latlon = this.props.data.split(',')
const lat = latlon[0]
const lon = latlon[1]
const suncalc = SunCalc.getTimes(new Date(), lat, lon)
@ -137,10 +132,25 @@ class Clock extends Component {
lon,
...convertedSunCalc,
geolocationSuccess: true,
}, (err) => {
if (err) console.log(err);
}, { maximumAge: Infinity, timeout: 10000 });
});
})
}
}
componentDidUpdate(prevProps) {
if (prevProps !== this.props) {
this.initGeolocation()
}
}
componentDidMount() {
this.canvas = initCanvas(
this.canvasRef,
{ x: innerSize, y: innerSize },
4
);
this.initGeolocation()
this.animate()
}
@ -151,7 +161,7 @@ class Clock extends Component {
const { state } = this
const time = new Date();
const ctx = this.canvas.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
ctx.clearRect(0, 0, ctx.width, ctx.height);
ctx.save();
const ctr = innerSize / 2
@ -161,8 +171,8 @@ class Clock extends Component {
var cx = ctr
var cy = ctr
this.angle = degToRad(convert(time, this.referenceTime))
var newX = cx + (ctr - 24) * Math.cos(this.angle);
var newY = cy + (ctr - 24) * Math.sin(this.angle);
var newX = cx + (ctr - 15) * Math.cos(this.angle);
var newY = cy + (ctr - 15) * Math.sin(this.angle);
// Initial background
circle(
@ -239,7 +249,7 @@ class Clock extends Component {
ctx,
newX-1/2,
newY-1/2,
16,
8,
0,
2 * Math.PI,
'#FCC440'
@ -250,7 +260,7 @@ class Clock extends Component {
ctx,
newX-1/2,
newY-1/2,
16,
8,
0,
2 * Math.PI,
'#6792FF',
@ -262,7 +272,7 @@ class Clock extends Component {
ctx,
newX-1/2,
newY-1/2,
16,
8,
0,
2 * Math.PI,
'#FFFFFF'
@ -272,7 +282,7 @@ class Clock extends Component {
ctx,
newX-1/2,
newY-1/2,
16,
8,
0,
2 * Math.PI,
'#000000',
@ -296,13 +306,25 @@ class Clock extends Component {
ctx,
ctr,
ctr,
ctr,
ctr-1,
-1,
2 * Math.PI,
'#000000',
1
);
// Outer borders
circleOutline(
ctx,
ctr,
ctr,
ctr,
-1,
2 * Math.PI,
'#FFFFFF',
1
);
// Center white circle with time and date
circle(
ctx,
@ -311,7 +333,7 @@ class Clock extends Component {
ctr/1.85,
-1,
2 * Math.PI,
'#000000'
'#FFFFFF'
)
// Center white circle border
@ -322,7 +344,7 @@ class Clock extends Component {
ctr/1.85,
-1,
2 * Math.PI,
'rgb(26, 26, 26)',
'#000000',
1
);
@ -332,12 +354,12 @@ class Clock extends Component {
: moment().format('h:mm A')
const dateText = moment().format('MMM Do')
ctx.textAlign = 'center'
ctx.fillStyle = '#FFFFFF'
ctx.font = '16px Inter'
ctx.fillText(timeText, ctr, ctr + 6 - 12)
ctx.fillStyle = '#000000'
ctx.font = '12px Inter'
ctx.fillText(timeText, ctr, ctr + 6 - 7)
ctx.fillStyle = '#B1B1B1'
ctx.font = '16px Inter'
ctx.fillText(dateText, ctr, ctr + 6 + 12)
ctx.font = '12px Inter'
ctx.fillText(dateText, ctr, ctr + 6 + 7)
ctx.restore();
}
@ -359,10 +381,10 @@ export default class ClockTile extends Component {
renderWrapper(child) {
return (
<div className="pa2" style={{
<div className="" style={{
width: outerSize,
height: outerSize,
background: 'rgba(0,0,0,1)'
background: '#fff'
}}>
{child}
</div>
@ -371,9 +393,8 @@ export default class ClockTile extends Component {
render() {
let data = !!this.props.data ? this.props.data : {};
return this.renderWrapper((
<Clock/>
<Clock data={data}/>
));
}

View File

@ -2148,7 +2148,8 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -2172,13 +2173,15 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -2195,19 +2198,22 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -2338,7 +2344,8 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -2352,6 +2359,7 @@
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -2368,6 +2376,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -2376,13 +2385,15 @@
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -2403,6 +2414,7 @@
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -2491,7 +2503,8 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -2505,6 +2518,7 @@
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -2600,7 +2614,8 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -2642,6 +2657,7 @@
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -2663,6 +2679,7 @@
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -2711,13 +2728,15 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"dev": true
"dev": true,
"optional": true
}
}
},

View File

@ -9,19 +9,19 @@ export default class ContactTile extends Component {
const { props } = this;
return (
<div className="w-100 h-100 relative" style={{ background: "#286E55" }}>
<a className="w-100 h-100 db pa2 no-underline" href="/~contacts">
<div className="w-100 h-100 relative bg-white b--black ba">
<a className="w-100 h-100 db pa2 bn" href="/~contacts">
<p
className="white label-regular b absolute"
style={{ left: 8, top: 4 }}>
className="black absolute f9"
style={{ left: 8, top: 8 }}>
Contacts
</p>
<img
className="absolute"
style={{ left: 69, top: 69 }}
style={{ left: 39, top: 39 }}
src="/~contacts/img/Tile.png"
width={96}
height={96}
width={48}
height={48}
/>
</a>
</div>

View File

@ -1106,6 +1106,25 @@
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true
},
"deep-rename-keys": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/deep-rename-keys/-/deep-rename-keys-0.2.1.tgz",
"integrity": "sha1-7eeFN9emaivmFRfir5Vtf1ij8dg=",
"requires": {
"kind-of": "^3.0.2",
"rename-keys": "^1.1.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"default-compare": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
@ -1418,6 +1437,11 @@
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true
},
"eventemitter3": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
"integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo="
},
"expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@ -2371,8 +2395,7 @@
"get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
"integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
"dev": true
"integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
},
"glob": {
"version": "7.1.4",
@ -2916,6 +2939,14 @@
"integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
"dev": true
},
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"requires": {
"loose-envify": "^1.0.0"
}
},
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
@ -2976,8 +3007,7 @@
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"dev": true
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"is-callable": {
"version": "1.1.4",
@ -3130,7 +3160,6 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
"dev": true,
"requires": {
"isobject": "^3.0.1"
}
@ -3218,8 +3247,7 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"js-tokens": {
"version": "4.0.0",
@ -3916,6 +3944,56 @@
"has": "^1.0.3"
}
},
"omit-deep": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/omit-deep/-/omit-deep-0.3.0.tgz",
"integrity": "sha1-IcivNJm8rdKWUaIyy8rLxSRF6+w=",
"requires": {
"is-plain-object": "^2.0.1",
"unset-value": "^0.1.1"
},
"dependencies": {
"has-value": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
"integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
"requires": {
"get-value": "^2.0.3",
"has-values": "^0.1.4",
"isobject": "^2.0.0"
},
"dependencies": {
"isobject": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
"integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
"requires": {
"isarray": "1.0.0"
}
}
}
},
"has-values": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
"integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"unset-value": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-0.1.2.tgz",
"integrity": "sha1-UGgQuGfyfCpabpsEgzYx9t5Y0xA=",
"requires": {
"has-value": "^0.3.1",
"isobject": "^3.0.0"
}
}
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -4709,6 +4787,11 @@
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
"dev": true
},
"rename-keys": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rename-keys/-/rename-keys-1.2.0.tgz",
"integrity": "sha512-U7XpAktpbSgHTRSNRrjKSrjYkZKuhUukfoBlXWXUExCAqhzh1TU3BDRAfJmarcl5voKS+pbKU9MvyLWKZ4UEEg=="
},
"repeat-element": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
@ -5410,6 +5493,16 @@
"util.promisify": "~1.0.0"
}
},
"svgson": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/svgson/-/svgson-4.0.0.tgz",
"integrity": "sha512-4xmo8f7IREKzSimfKLxdFmffWn8ngstS6EYC8Hqoo4twyzLxc1BETdSBz++wx8k9s8EH8hLNi+VoH+7T2pkIgw==",
"requires": {
"deep-rename-keys": "^0.2.1",
"omit-deep": "0.3.0",
"xml-reader": "2.4.3"
}
},
"terser": {
"version": "3.17.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz",
@ -5579,6 +5672,11 @@
"through2": "^2.0.3"
}
},
"transformation-matrix": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.1.1.tgz",
"integrity": "sha512-74MoNHhwLVuzwaPDcAecFjSkOA9vwWqyOdkeB0Be8Jc/IWSS5SNZKapFllqzkTliqZptkvqX5CZnVeDvfhN8cw=="
},
"type": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/type/-/type-1.0.1.tgz",
@ -5720,6 +5818,17 @@
"integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
"dev": true
},
"urbit-sigil-js": {
"version": "1.3.13",
"resolved": "https://registry.npmjs.org/urbit-sigil-js/-/urbit-sigil-js-1.3.13.tgz",
"integrity": "sha512-g6tC7K65O/4rMCd9/Cy+BVyVSzC3GNjfd0R4EaXEl4aXnjRIiIkD0xkZl56yzLwNk6W9bniDQJALcGPxY3IROw==",
"requires": {
"invariant": "^2.2.4",
"react": "^16.8.6",
"svgson": "^4.0.0",
"transformation-matrix": "2.1.1"
}
},
"urix": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
@ -5899,6 +6008,23 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xml-lexer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/xml-lexer/-/xml-lexer-0.2.2.tgz",
"integrity": "sha1-UYGTpKozTVj8fSSLVJB5uJkH4EY=",
"requires": {
"eventemitter3": "^2.0.0"
}
},
"xml-reader": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/xml-reader/-/xml-reader-2.4.3.tgz",
"integrity": "sha1-n4EMr3xCWlqvuEixxFEDyecddTA=",
"requires": {
"eventemitter3": "^2.0.0",
"xml-lexer": "^0.2.2"
}
},
"y18n": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",

View File

@ -31,7 +31,8 @@
"moment": "^2.20.1",
"react": "^16.5.2",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0"
"react-router-dom": "^5.0.0",
"urbit-sigil-js": "^1.3.13"
},
"resolutions": {
"natives": "1.1.3"

View File

@ -1,3 +1,10 @@
body, html {
width: 100%;
height: 100%;
font-family: "Inter", sans-serif;
-webkit-font-smoothing: antialiased;
}
p, h1, h2, h3, h4, h5, h6, a, input, textarea, button {
margin-block-end: unset;
margin-block-start: unset;
@ -12,63 +19,10 @@ a:-webkit-any-link {
textarea, select, input, button { outline: none; }
h2 {
font-size: 32px;
line-height: 48px;
font-weight: bold;
}
.body-regular {
font-size: 16px;
line-height: 24px;
font-weight: 600;
}
.body-large {
font-size: 20px;
line-height: 24px;
}
.label-regular {
font-size: 14px;
line-height: 24px;
}
.label-small {
font-size: 12px;
line-height: 24px;
font-weight: bold;
}
.label-small-mono {
font-size: 12px;
line-height: 24px;
.mono {
font-family: "Source Code Pro", monospace;
}
.body-regular-400 {
font-size: 16px;
line-height: 24px;
font-weight: 400;
}
.plus-font {
font-size: 48px;
line-height: 24px;
}
.fw-bold {
font-weight: bold;
}
.bg-v-light-gray {
background-color: #f9f9f9;
}
.gray-30 {
color: #B1B2B3;
}
.green-medium {
color: #2ED196;
}
.mix-blend-diff {
mix-blend-mode: difference;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
@import 'css/tachyons.css';
@import 'css/indigo-static.css';
@import 'css/fonts.css';
@import 'css/custom.css';

View File

@ -1,46 +0,0 @@
import React, { Component } from 'react';
import { subscription } from '/subscription';
import { api } from '/lib/api';
import classnames from 'classnames';
let style = {
circle: {
width: '2em',
height: '2em',
background: '#000000',
border: '4px solid #333333',
'borderRadius': '2em'
},
triangle: {
width: '0px',
height: '0px',
'borderTop': '8px solid #FFFFFF',
'borderLeft': '8px solid transparent',
'borderRight': '8px solid transparent',
'fontSize': 0,
'lineHeight': 0,
'marginLeft': 'auto',
'marginRight': 'auto',
}
};
export default class Dropdown extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div className="ml2" style={style.circle}>
<div className="mt2" style={style.triangle}></div>
</div>
</div>
);
}
}

View File

@ -1,51 +1,28 @@
import React, { Component } from 'react';
import { subscription } from '/subscription';
import { api } from '/lib/api';
import classnames from 'classnames';
import moment from 'moment';
import Dropdown from '/components/dropdown';
import { Sigil } from './sigil';
export default class Header extends Component {
constructor(props) {
super(props);
this.interval = null;
this.timeout = null;
this.state = {
moment: moment()
};
}
componentDidMount() {
let sec = parseInt(moment().format("s"), 10);
this.timeout = setTimeout(() => {
this.setState({
moment: moment()
});
this.interval = setInterval(() => {
this.setState({
moment: moment()
});
}, 60000);
}, (60 - sec) * 1000);
}
componentWillUnmount() {
clearTimeout(this.timeout);
clearInterval(this.interval);
}
render() {
return (
<header className="w-100 h2 cf">
<div className="fl h2 bg-black">
</div>
<div className="fr h2 bg-black">
<p className="white v-mid h2 sans-serif dtc pr2">{this.state.moment.format("MMM DD")}</p>
<p className="white v-mid h2 sans-serif dtc pr2">{this.state.moment.format("hh:mm a")}</p>
<header
className="bg-white bg-gray0-d w-100 justify-between relative tc pt3"
style={{ height: 40 }}>
<span
className="f9 white-d inter dib"
style={{
verticalAlign: "text-top",
paddingTop: 3
}}>
Home
</span>
<div className="absolute right-1 lh-copy" style={{ top: 12 }}>
<Sigil
ship={"~" + window.ship}
size={16} color={"#000000"}
classes="mix-blend-diff v-mid" />
<span className="mono white-d f9 ml2">
{"~" + window.ship}
</span>
</div>
</header>
);

View File

@ -23,9 +23,11 @@ export default class Home extends Component {
});
return (
<div className="fl w-100 vh-100 bg-black center">
<div className="fl w-100 h-100 bg-white center">
<Header />
<div className="v-mid pa2 dtc">
<div className={"v-mid pa2 dtc-m dtc-l dtc-xl " +
"flex justify-between flex-wrap"}
style={{maxWidth: "40rem"}}>
{tileElems}
</div>
</div>

View File

@ -0,0 +1,31 @@
import React, { Component } from "react";
import { sigil, reactRenderer } from "urbit-sigil-js";
export class Sigil extends Component {
render() {
const { props } = this;
let classes = props.classes || "";
if (props.ship.length > 14) {
return (
<div
className="bg-black dib"
style={{ width: props.size, height: props.size }}></div>
);
} else {
return (
<div
className={"dib " + classes}
style={{ flexBasis: 16, backgroundColor: props.color }}>
{sigil({
patp: props.ship,
renderer: reactRenderer,
size: props.size,
colors: [props.color, "white"]
})}
</div>
);
}
}
}

View File

@ -14,7 +14,7 @@ export default class Tile extends Component {
return (
<div className="fl ma2 bg-white overflow-hidden"
style={{ height: '234px', width: '234px' }}>
style={{ height: '126px', width: '126px' }}>
{ !!SpecificTile ?
<SpecificTile data={this.props.data} />
: <div></div>

View File

@ -9,19 +9,19 @@ export default class LinkTile extends Component {
const { props } = this;
return (
<div className="w-100 h-100 relative ba b--black" style={{ background: "#FFFFFF" }}>
<a className="w-100 h-100 db pa2 no-underline" href="/~link">
<div className="w-100 h-100 relative ba b--black bg-white">
<a className="w-100 h-100 db pa2 bn" href="/~link">
<p
className="label-regular b absolute"
style={{ left: 8, top: 4 }}>
className="f9 black absolute"
style={{ left: 8, top: 8 }}>
Links
</p>
<img
className="absolute"
style={{ left: 69, top: 69 }}
style={{ left: 39, top: 39 }}
src="/~link/img/Tile.png"
width={96}
height={96}
width={48}
height={48}
/>
</a>
</div>

View File

@ -10,22 +10,36 @@ export default class PublishTile extends Component {
render(){
let notificationsNum = this.props.data.notifications;
if (notificationsNum === 0) {
notificationsNum = "";
}
else if (notificationsNum > 99) {
notificationsNum = "99+";
}
else if (isNaN(notificationsNum)) {
notificationsNum = "";
}
return (
<div className="w-100 h-100 relative" style={{background: "#1a1a1a"}}>
<div className="w-100 h-100 relative bg-white ba b--black">
<a className="w-100 h-100 db no-underline" href="/~publish">
<p className="gray label-regular b absolute"
style={{left: 8, top: 4}}>
Publish
<p className="black f9 absolute" style={{ left: 8, top: 8 }}>
Publishing
</p>
<img
className="absolute"
style={{left: 60, top: 66}}
style={{ left: 39, top: 39 }}
src="/~publish/tile.png"
width={113}
height={102} />
<div className="absolute w-100 flex-col body-regular white"
style={{verticalAlign: "bottom", bottom: 8, left: 8}}>
<span className="green-medium">{this.props.data.notifications}</span>
width={48}
height={48}
/>
<div
className="absolute w-100 flex-col f9"
style={{ verticalAlign: "bottom", bottom: 8, left: 8 }}>
<span className="green2">{notificationsNum}</span>
</div>
</a>
</div>

View File

@ -7,15 +7,20 @@ export default class sotoTile extends Component {
render() {
return (
<div className="w-100 h-100 relative" style={{background: "#1a1a1a"}}>
<a className="w-100 h-100 db no-underline" href="/~dojo">
<p className="gray label-regular b absolute"
style={{ left: 8, top: 4 }}>
<div className="w-100 h-100 relative bg-black">
<a className="w-100 h-100 db bn" href="/~dojo">
<p className="white f9 absolute"
style={{ left: 8, top: 8 }}>
Dojo
</p>
<img src="~dojo/img/Tile.png"
className="absolute"
style={{ left: 30, top: 30, height: "174px", width: "174px"}}
style={{
left: 39,
top: 39,
height: 48,
width: 48
}}
/>
</a>
</div>

View File

@ -8,12 +8,7 @@ class IconWithData extends Component {
return (
<div className='mt2'>
<img
src={'/~weather/img/' + props.icon + '.png'}
width={20}
height={20}
className="dib mr2" />
<p className="label-small dib white">{props.text}</p>
<p className="f9 white">{props.text}</p>
</div>
);
}
@ -36,13 +31,13 @@ export default class WeatherTile extends Component {
locationSubmit() {
navigator.geolocation.getCurrentPosition((res) => {
console.log(res);
let latlng = `${res.coords.latitude},${res.coords.longitude}`;
this.setState({
latlng
}, (err) => {
console.log(err);
}, { maximumAge: Infinity, timeout: 10000 });
api.action("clock", "json", latlng);
api.action('weather', 'json', latlng);
});
}
@ -55,6 +50,7 @@ export default class WeatherTile extends Component {
if (latlngParse.test(latlngNoSpace)) {
let latlng = latlngNoSpace;
this.setState({latlng}, (err) => {console.log(err)}, {maximumAge: Infinity, timeout: 10000});
api.action("clock", "json", latlng);
api.action('weather', 'json', latlng);
this.setState({manualEntry: !this.state.manualEntry});
}
@ -73,11 +69,12 @@ export default class WeatherTile extends Component {
renderWrapper(child) {
return (
<div className="pa2 relative" style={{
width: 234,
height: 234,
background: '#1a1a1a'
}}>
<div
className="pa2 relative bg-white b--black ba"
style={{
width: 126,
height: 126,
}}>
{child}
</div>
);
@ -88,53 +85,65 @@ export default class WeatherTile extends Component {
let error;
if (this.state.error === true) {
error = <p
className="label-small red pt1">
className="f9 red2 pt1">
Incorrect latitude/longitude formatting. Please try again. <br/>
(eg. "29.558107, -95.089023")
</p>
}
if (location.protocol === "https:") {
secureCheck = <a
className="label-regular b gray absolute pointer"
style={{right: 8, top: 4}}
onClick={() => this.locationSubmit()}>Detect location -></a>
className="black f9 absolute pointer"
style={{right: 8, top: 8}}
onClick={() => this.locationSubmit()}>Detect -></a>
}
return this.renderWrapper((
return this.renderWrapper(
<div>
<a style={{"color": "white", "cursor": "pointer"}}
onClick={() => this.setState({manualEntry: !this.state.manualEntry})}>
&lt;&#45;
<a
className="f9 black pointer"
onClick={() =>
this.setState({ manualEntry: !this.state.manualEntry })
}>
&lt;&#45;
</a>
{secureCheck}
<p className="label-regular white pt2">
Please enter your <a className="white" href="https://latitudeandlongitude.org/" target="_blank">latitude and longitude</a>.</p>
<p className="f9 black pt2">
Please enter your{" "}
<a
className="white"
href="https://latitudeandlongitude.org/"
target="_blank">
latitude and longitude
</a>
.
</p>
{error}
<form className="flex absolute" style={{"bottom": 0, "left": 8}}>
<input id="gps"
className="white pa1 bg-transparent outline-0 bn bb-ns b--white"
style={{width: "86%"}}
type="text"
placeholder="29.558107, -95.089023"
onKeyDown={this.keyPress.bind(this)}>
</input>
<input className="bg-transparent inter white w-20 outliner-0 bn pointer"
type="submit"
onClick={() => this.manualLocationSubmit()}
value="->">
</input>
</form>
<div className="flex">
<form className="flex absolute" style={{ bottom: 0, left: 8 }}>
<input
id="gps"
className="w-100 black pa1 bg-transparent outline-0 bn bb-ns b--black f9"
type="text"
placeholder="29.558107, -95.089023"
onKeyDown={this.keyPress.bind(this)}></input>
<input
className="bg-transparent black outliner-0 bn pointer f9 flex-shrink-0"
type="submit"
onClick={() => this.manualLocationSubmit()}
value="->"></input>
</form>
</div>
</div>
))
);
}
renderNoData() {
return this.renderWrapper((
<div onClick={() => this.setState({manualEntry: !this.state.manualEntry})}>
<p className="gray label-regular b absolute"
style={{left: 8, top: 4}}>
<p className="black f9 absolute"
style={{left: 8, top: 8}}>
Weather
</p>
<p className="absolute w-100 flex-col body-regular white" style={{verticalAlign: "bottom", bottom: 8, left: 8, cursor: "pointer"}}>-> Set location</p>
<p className="absolute w-100 flex-col f9 black" style={{verticalAlign: "bottom", bottom: 8, left: 8, cursor: "pointer"}}>-> Set location</p>
</div>
));
}
@ -145,58 +154,26 @@ export default class WeatherTile extends Component {
let da = moment.unix(d.sunsetTime).format('h:mm a') || '';
return this.renderWrapper((
return this.renderWrapper(
<div>
<p className="gray label-regular b absolute"
style={{left: 8, top: 4}}>
Weather
</p>
<a className="label-regular b gray absolute pointer"
style={{right: 8, top: 4}}
onClick={() => this.setState({manualEntry: !this.state.manualEntry})}>Update location -></a>
<div className="w-100 mb2 mt2 absolute"
style={{left: 18, top: 28}}>
<img
src={'/~weather/img/' + c.icon + '.png'}
width={64}
height={64}
className="dib" />
<h2
className="dib ml2 white"
style={{
fontSize: 72,
lineHeight: '64px',
fontWeight: 400
}}>
{Math.round(c.temperature)}°</h2>
</div>
<div className="w-100 cf absolute"
style={{ left: 18, top: 118 }}>
<div className="fl w-50">
<IconWithData
icon='winddirection'
text={c.windBearing + '°'} />
<IconWithData
icon='chancerain'
text={(c.precipProbability * 100) + '%'} />
<IconWithData
icon='windspeed'
text={Math.round(c.windSpeed) + ' mph'} />
</div>
<div className="fr w-50">
<IconWithData
icon='sunset'
text={da} />
<IconWithData
icon='low'
text={Math.round(d.temperatureLow) + '°'} />
<IconWithData
icon='high'
text={Math.round(d.temperatureHigh) + '°'} />
</div>
<p className="black f9 absolute" style={{ left: 8, top: 8 }}>
Weather
</p>
<a
className="black f9 absolute pointer"
style={{ right: 8, top: 8 }}
onClick={() =>
this.setState({ manualEntry: !this.state.manualEntry })
}>
->
</a>
<div className="w-100 absolute" style={{ left: 8, bottom: 8 }}>
<p className="f9 black">{c.summary}</p>
<p className="f9 pt1 black">{Math.round(c.temperature)}°</p>
<p className="f9 pt1 black">Sunset at {da}</p>
</div>
</div>
));
);
}
render() {