replace nunjucks profile rendering with vue, start listing of recent posts on profiel page, support full IRI object ids in object GET route so that remote origin objects can be fetched from local cache for display in Vue pages
This commit is contained in:
parent
24a5fbeb07
commit
dbd8da4bfc
14 changed files with 1273 additions and 413 deletions
7
index.js
7
index.js
|
@ -5,7 +5,6 @@ const fs = require('fs')
|
|||
const bodyParser = require('body-parser')
|
||||
const cors = require('cors')
|
||||
const https = require('https')
|
||||
const nunjucks = require('nunjucks')
|
||||
const morgan = require('morgan')
|
||||
const history = require('connect-history-api-fallback')
|
||||
|
||||
|
@ -16,11 +15,6 @@ const net = require('./net')
|
|||
const { DOMAIN, KEY_PATH, CERT_PATH, CA_PATH, PORT, PORT_HTTPS, DB_URL, DB_NAME } = require('./config.json')
|
||||
|
||||
const app = express()
|
||||
nunjucks.configure('templates', {
|
||||
autoescape: true,
|
||||
express: app,
|
||||
watch: app.get('env') === 'development'
|
||||
})
|
||||
|
||||
const client = new MongoClient(DB_URL, { useUnifiedTopology: true, useNewUrlParser: true })
|
||||
|
||||
|
@ -56,7 +50,6 @@ app.use('/u/:name/outbox', net.validators.jsonld, routes.outbox)
|
|||
app.use('/u', cors(), routes.user)
|
||||
|
||||
// html/static routes
|
||||
app.use('/', express.static('public/www'))
|
||||
app.use('/f', express.static('public/files'))
|
||||
app.use('/web', express.static('web/dist'))
|
||||
|
||||
|
|
1091
package-lock.json
generated
1091
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -12,7 +12,6 @@
|
|||
"http-signature": "github:wmurphyrd/node-http-signature#9c02eeb",
|
||||
"mongodb": "^3.3.2",
|
||||
"morgan": "^1.9.1",
|
||||
"nunjucks": "^3.2.0",
|
||||
"request": "^2.88.0",
|
||||
"request-promise-native": "^1.0.7"
|
||||
},
|
||||
|
@ -21,6 +20,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"chokidar": "^3.1.1",
|
||||
"nodemon": "^1.19.3",
|
||||
"standard": "^14.3.1",
|
||||
"standardjs": "^1.0.0-alpha"
|
||||
},
|
||||
|
|
|
@ -10,11 +10,20 @@ module.exports = {
|
|||
// find object in local DB or fetch from origin server
|
||||
async function resolveObject (id) {
|
||||
let object
|
||||
let parseCheck
|
||||
if (pubUtils.validateObject(id)) {
|
||||
// already an object
|
||||
object = id
|
||||
} else {
|
||||
// resolve id to local object
|
||||
try {
|
||||
// check if full IRI id or remote id
|
||||
parseCheck = new URL(id)
|
||||
} catch (ignore) {}
|
||||
if (!parseCheck) {
|
||||
// convert bare ObjectId to local IRI id
|
||||
id = pubUtils.objectIdToIRI(id)
|
||||
}
|
||||
object = await store.object.get(id)
|
||||
if (object) {
|
||||
return object
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Guppe Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello</h1>
|
||||
</body>
|
|
@ -1,15 +1,16 @@
|
|||
'use strict'
|
||||
const express = require('express')
|
||||
const router = express.Router()
|
||||
const store = require('../store')
|
||||
const pub = require('../pub')
|
||||
|
||||
router.get('/:name', function (req, res) {
|
||||
const name = req.params.name
|
||||
if (!name) {
|
||||
const id = req.params.name
|
||||
if (!id) {
|
||||
return res.status(400).send('Bad request.')
|
||||
} else {
|
||||
store.object.get(pub.utils.objectIdToIRI(name))
|
||||
// TODO: don't attempt to resolve remote ids if request is cross-origin
|
||||
// (to prevent abuse of guppe server to DDoS other servers)
|
||||
pub.object.resolve(id)
|
||||
.then(obj => {
|
||||
if (obj) {
|
||||
return res.json(pub.utils.toJSONLD(obj))
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ group.preferredUsername }} group</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<style>
|
||||
body {font-family: "Lato", sans-serif}
|
||||
.mySlides {display: none}
|
||||
</style>
|
||||
<script>
|
||||
function doFollow (evt) {
|
||||
let user, acct, username, domain
|
||||
evt.preventDefault();
|
||||
document.getElementById('username-error').classList.add('w3-hide')
|
||||
document.getElementById('finger-error').classList.add('w3-hide')
|
||||
try {
|
||||
user = document.getElementById('handle').value
|
||||
;[acct, username, domain] = /@?([^@]+)@(.+)/.exec(user)
|
||||
} catch (ignore) {
|
||||
document.getElementById('username-error').classList.remove('w3-hide')
|
||||
return
|
||||
}
|
||||
window.fetch(`https://${domain}/.well-known/webfinger?resource=acct:${acct}`, {
|
||||
method: 'get',
|
||||
mode: 'cors'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
const link = json.links.find(l => l.rel === 'http://ostatus.org/schema/1.0/subscribe')
|
||||
window.location.href = link.template.replace('{uri}', '{{ groupAcct }}')
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
document.getElementById('finger-error').classList.remove('w3-hide')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Navbar -->
|
||||
<div class="w3-top">
|
||||
<div class="w3-bar w3-black w3-card">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navbar on small screens (remove the onclick attribute if you want the navbar to always show on top of the content when clicking on the links) -->
|
||||
<div id="navDemo" class="w3-bar-block w3-black w3-hide w3-hide-large w3-hide-medium w3-top" style="margin-top:46px">
|
||||
|
||||
</div>
|
||||
<!-- Page content -->
|
||||
<div class="w3-content" style="max-width:2000px;margin-top:46px">
|
||||
|
||||
|
||||
<div class="w3-container w3-content w3-center w3-padding-64" style="max-width:800px" id="band">
|
||||
<h2 class="w3-wide">{{ group.preferredUsername }}</h2>
|
||||
<p class="w3-opacity"><i>{{ group.summary }}</i></p>
|
||||
<p class="w3-left-align">To join {{ group.preferredUsername }}, enter your handle below and you'll be
|
||||
redirected back to this group's profile in your app where you can follow it.</p>
|
||||
<form class="w3-container">
|
||||
<label>Your account</label>
|
||||
<input id="handle" class="w3-input w3-center" placeholder="user@example.com" type="text">
|
||||
<button class="w3-btn w3-cyan w3-block w3-margin-top" onclick="doFollow(event)">Procced to follow</button>
|
||||
</form>
|
||||
<div id="username-error" class="w3-hide w3-panel w3-pale-red w3-display-container w3-border">
|
||||
<span onclick="this.parentElement.classList.add('w3-hide')" class="w3-button w3-large w3-display-topright">×</span>
|
||||
<h3>Double check that username</h3>
|
||||
<p>e.g. you@yourhost.com</p>
|
||||
</div>
|
||||
<div id="finger-error" class="w3-hide w3-panel w3-pale-red w3-display-container w3-border">
|
||||
<span onclick="this.parentElement.classList.add('w3-hide')" class="w3-button w3-large w3-display-topright">×</span>
|
||||
<h3>Oops</h3>
|
||||
<p>Couldn't connect with your host.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- The Tour Section -->
|
||||
<!-- <div class="w3-black" id="tour">
|
||||
<div class="w3-container w3-content w3-padding-64" style="max-width:800px">
|
||||
<h2 class="w3-wide w3-center">Recent group posts</h2>
|
||||
</div> -->
|
||||
|
||||
<!-- End Page Content -->
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="w3-container w3-padding-64 w3-center w3-opacity w3-light-grey w3-xlarge">
|
||||
<a href="https://github.com/wmurphyrd/guppe"><i class="fa fa-github w3-hover-opacity"></i></a>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
47
web/package-lock.json
generated
47
web/package-lock.json
generated
|
@ -3026,7 +3026,8 @@
|
|||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"coa": {
|
||||
"version": "2.0.2",
|
||||
|
@ -5633,7 +5634,8 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -5654,12 +5656,14 @@
|
|||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -5674,17 +5678,20 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -5801,7 +5808,8 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -5813,6 +5821,7 @@
|
|||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -5827,6 +5836,7 @@
|
|||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -5834,12 +5844,14 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
|
@ -5858,6 +5870,7 @@
|
|||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -5938,7 +5951,8 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
@ -5950,6 +5964,7 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
@ -6035,7 +6050,8 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -6071,6 +6087,7 @@
|
|||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -6090,6 +6107,7 @@
|
|||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -6133,12 +6151,14 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10194,7 +10214,8 @@
|
|||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
|
||||
"integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"rx-lite-aggregates": {
|
||||
"version": "4.0.8",
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"dev": "vue-cli-service build --watch --mode development"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^2.6.5",
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="stylesheet" href="<%= BASE_URL %>w3.css">
|
||||
<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato"> -->
|
||||
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> -->
|
||||
|
||||
<title>web</title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
232
web/public/w3.css
Normal file
232
web/public/w3.css
Normal file
|
@ -0,0 +1,232 @@
|
|||
/* W3.CSS 4.13 June 2019 by Jan Egil and Borge Refsnes */
|
||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item}
|
||||
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
|
||||
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
|
||||
a{background-color:transparent}a:active,a:hover{outline-width:0}
|
||||
abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
|
||||
b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000}
|
||||
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none}
|
||||
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}
|
||||
button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold}
|
||||
button,input{overflow:visible}button,select{text-transform:none}
|
||||
button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}
|
||||
button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}
|
||||
button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}
|
||||
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
|
||||
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
|
||||
[type=checkbox],[type=radio]{padding:0}
|
||||
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
|
||||
[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
|
||||
[type=search]::-webkit-search-decoration{-webkit-appearance:none}
|
||||
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
|
||||
/* End extract */
|
||||
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
|
||||
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}.w3-serif{font-family:serif}
|
||||
h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
|
||||
hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
||||
.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit}
|
||||
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
|
||||
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
|
||||
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
|
||||
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
||||
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
|
||||
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
||||
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
||||
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
||||
.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
|
||||
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
|
||||
.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
|
||||
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
|
||||
.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
|
||||
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
|
||||
.w3-dropdown-hover:hover .w3-dropdown-content{display:block}
|
||||
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1}
|
||||
.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
|
||||
.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
|
||||
.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
|
||||
.w3-main,#main{transition:margin-left .4s}
|
||||
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
|
||||
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
|
||||
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
|
||||
.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0}
|
||||
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
|
||||
.w3-bar .w3-button{white-space:normal}
|
||||
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0}
|
||||
.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
|
||||
.w3-responsive{display:block;overflow-x:auto}
|
||||
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
|
||||
.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
|
||||
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
|
||||
.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%}
|
||||
.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%}
|
||||
.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%}
|
||||
@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}
|
||||
.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%}
|
||||
.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}}
|
||||
@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%}
|
||||
.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%}
|
||||
.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}}
|
||||
.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px}
|
||||
.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px}
|
||||
.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
|
||||
.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
|
||||
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
||||
@media (max-width:1205px){.w3-auto{max-width:95%}}
|
||||
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
||||
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
||||
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
||||
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
||||
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
||||
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
|
||||
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
|
||||
@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}}
|
||||
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
|
||||
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
|
||||
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
|
||||
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
|
||||
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
|
||||
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
|
||||
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
|
||||
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
|
||||
.w3-display-position{position:absolute}
|
||||
.w3-circle{border-radius:50%}
|
||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||
.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
|
||||
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
|
||||
.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
||||
.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
|
||||
.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
||||
.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
||||
.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
||||
.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
|
||||
.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
|
||||
.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
|
||||
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
|
||||
.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
|
||||
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
|
||||
.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
|
||||
.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
|
||||
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
|
||||
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
|
||||
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
|
||||
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
|
||||
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
|
||||
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
|
||||
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
|
||||
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
|
||||
.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
|
||||
.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
|
||||
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
|
||||
.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
|
||||
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
|
||||
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
|
||||
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
|
||||
.w3-left{float:left!important}.w3-right{float:right!important}
|
||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||
.w3-hover-none:hover{box-shadow:none!important}
|
||||
/* Colors */
|
||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
|
||||
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
|
||||
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
|
||||
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
|
||||
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
|
||||
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
|
||||
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
|
||||
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
|
||||
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
|
||||
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
|
||||
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
|
||||
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
|
||||
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
|
||||
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
|
||||
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
|
||||
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
|
||||
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
|
||||
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
|
||||
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
|
||||
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
|
||||
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
|
||||
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
|
||||
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
|
||||
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
|
||||
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
|
||||
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
|
||||
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
|
||||
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
|
||||
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
|
||||
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
|
||||
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
|
||||
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
|
||||
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
|
||||
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
|
||||
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
|
||||
.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
|
||||
.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
|
||||
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
|
||||
.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
|
||||
.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
|
||||
.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
|
||||
.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
|
||||
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
|
||||
.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
|
||||
.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
|
||||
.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
|
||||
.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
|
||||
.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
|
||||
.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
|
||||
.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
|
||||
.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
|
||||
.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
|
||||
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
|
||||
.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
|
||||
.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
|
||||
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
|
||||
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
|
||||
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
|
||||
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
|
||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
|
@ -1,20 +1,32 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<div id="nav">
|
||||
<!-- <div id="nav">
|
||||
<router-link to="/">Home</router-link> |
|
||||
<router-link to="/about">About</router-link>
|
||||
</div> -->
|
||||
<div class="w3-top">
|
||||
<div class="w3-bar w3-black w3-card"> </div>
|
||||
</div>
|
||||
<router-view/>
|
||||
<!-- Navbar on small screens -->
|
||||
<div id="navDemo" class="w3-bar-block w3-black w3-hide w3-hide-large w3-hide-medium w3-top" style="margin-top:46px">
|
||||
|
||||
</div>
|
||||
<div class="w3-content" style="max-width:2000px;margin-top:46px">
|
||||
<router-view/>
|
||||
</div>
|
||||
<footer class="w3-container w3-padding-64 w3-center w3-opacity w3-light-grey w3-xlarge">
|
||||
<a href="https://github.com/wmurphyrd/guppe"><i class="fa fa-github w3-hover-opacity"></i></a>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
/* font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
margin-top: 60px; */
|
||||
}
|
||||
</style>
|
||||
|
|
40
web/src/components/PostCard.vue
Normal file
40
web/src/components/PostCard.vue
Normal file
|
@ -0,0 +1,40 @@
|
|||
<template>
|
||||
<div class="w3-card">
|
||||
<label>{{ post.actor }}</label>
|
||||
<p>{{ post.content }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
activity: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
post: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (typeof this.activity.object === 'string') {
|
||||
window.fetch(`/o/${encodeURIComponent(this.activity.object)}`, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
accept: 'application/activity+json'
|
||||
}
|
||||
}).then(res => res.json())
|
||||
.then(post => {
|
||||
this.post = post
|
||||
})
|
||||
.catch(err => {
|
||||
this.post.content = err.message
|
||||
})
|
||||
} else {
|
||||
this.post = this.activity.object
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,13 +1,44 @@
|
|||
<template>
|
||||
<div class="about">
|
||||
<h1>{{ actor.preferredUsername }} group</h1>
|
||||
<p> {{ actor.summary }}</p>
|
||||
<p v-if="error">{{ error }}</p>
|
||||
<div class="w3-container w3-content w3-center w3-padding-32">
|
||||
<img class="profile-main" :src="groupProfileSrc">
|
||||
<h2 class="w3-wide">{{ actor.preferredUsername }}</h2>
|
||||
<p class="w3-opacity"><i>{{ actor.summary }}</i></p>
|
||||
<p class="w3-left-align">To join {{ actor.preferredUsername }}, enter your handle below and you'll be
|
||||
redirected back to this group's profile in your app where you can follow it.</p>
|
||||
<form class="w3-container">
|
||||
<label>Your account</label>
|
||||
<input v-model="handle" class="w3-input w3-center" placeholder="user@example.com" type="text">
|
||||
<button class="w3-btn w3-cyan w3-block w3-margin-top" @click.prevent="doFollow"
|
||||
:disabled="fetchingRemote">
|
||||
Procced to follow
|
||||
</button>
|
||||
</form>
|
||||
<div v-show="invalidHandle" class="w3-panel w3-pale-red w3-display-container w3-border">
|
||||
<span @click.prevent="invalidHandle = false" class="w3-button w3-large w3-display-topright">×</span>
|
||||
<h3>Double check that username</h3>
|
||||
<p>e.g. you@yourhost.com</p>
|
||||
</div>
|
||||
<div v-show="unreachable" class="w3-panel w3-pale-red w3-display-container w3-border">
|
||||
<span @click.prevent="unreachable = false" class="w3-button w3-large w3-display-topright">×</span>
|
||||
<h3>Oops</h3>
|
||||
<p>Couldn't connect with your host.</p>
|
||||
<p>You could try going back to your app and entering {{ groupHandle }} in the search instead</p>
|
||||
</div>
|
||||
<div class="w3-container w3-content w3-padding-64">
|
||||
<h2 class="w3-wide w3-center">Recent group posts</h2>
|
||||
<div>
|
||||
<post-card v-for="post of stream" :activity="post" :key="post.id"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PostCard from '@/components/PostCard.vue'
|
||||
export default {
|
||||
components: {
|
||||
PostCard
|
||||
},
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
|
@ -17,18 +48,94 @@ export default {
|
|||
data () {
|
||||
return {
|
||||
actor: {},
|
||||
stream: {},
|
||||
error: null,
|
||||
handle: '',
|
||||
invalidHandle: false,
|
||||
unreachable: false,
|
||||
fetchingRemote: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
groupProfileSrc() {
|
||||
return this.actor && this.actor.icon ? this.actor.icon.url : ''
|
||||
},
|
||||
groupHandle() {
|
||||
if (this.actor.id && this.actor.preferredUsername) {
|
||||
const url = new window.URL(this.actor.id)
|
||||
return `@${this.actor.preferredUsername.toLowerCase()}@${url.host}`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doFollow () {
|
||||
let acct, username, domain
|
||||
this.invalidHandle = false;
|
||||
this.unreachable = false;
|
||||
try {
|
||||
[acct, username, domain] = /@?([^@]+)@(.+)/.exec(this.handle)
|
||||
} catch (ignore) {
|
||||
this.invalidHandle = true
|
||||
return
|
||||
}
|
||||
this.fetchingRemote = true;
|
||||
window.fetch(`https://${domain}/.well-known/webfinger?resource=acct:${acct}`, {
|
||||
method: 'get',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
accept: 'application/json'
|
||||
}
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
const link = json.links.find(l => l.rel === 'http://ostatus.org/schema/1.0/subscribe')
|
||||
window.location.href = link.template.replace('{uri}', '{{ groupAcct }}')
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
this.unreachable = true
|
||||
})
|
||||
.then(() => {
|
||||
this.fetchingRemote = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.fetch(`https://localhost/u/${this.name}`, {
|
||||
window.fetch(`/u/${this.name}`, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
accept: 'application/activity+json'
|
||||
}
|
||||
}).then(res => res.json())
|
||||
.then(json => this.actor = json)
|
||||
.then(json => {
|
||||
this.actor = json
|
||||
})
|
||||
.then(() => {
|
||||
return window.fetch(this.actor.outbox, {
|
||||
method: 'get',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
accept: 'application/activity+json'
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(outbox => {
|
||||
this.stream = outbox.orderedItems // || fetch page
|
||||
.filter(act => act.type === 'Announce')
|
||||
})
|
||||
.catch(err => this.error = err.message)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.w3-container.w3-content {
|
||||
max-width:800px;
|
||||
}
|
||||
.profile-main {
|
||||
height: 256px;
|
||||
width: 256px;
|
||||
}
|
||||
</style>
|
Loading…
Reference in a new issue