Converted sample project into an almost working Svelte / Meteor project. Needs to fix the login/logout code, the camera code, and add Chromebook history when the QR Code is scanned.
This commit is contained in:
5
imports/ui/App.css
Normal file
5
imports/ui/App.css
Normal file
@@ -0,0 +1,5 @@
|
||||
nav {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=App.css.map */
|
||||
1
imports/ui/App.css.map
Normal file
1
imports/ui/App.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["App.sass"],"names":[],"mappings":"AAAA;EACC","file":"App.css"}
|
||||
2
imports/ui/App.sass
Normal file
2
imports/ui/App.sass
Normal file
@@ -0,0 +1,2 @@
|
||||
nav
|
||||
font-size: 1.4rem
|
||||
@@ -1,12 +1,159 @@
|
||||
|
||||
<style>
|
||||
nav {
|
||||
font-size: 2rem;
|
||||
}
|
||||
a {
|
||||
display: block;
|
||||
color: green;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: #000121;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
|
||||
}
|
||||
|
||||
/** Forbidden CSS */
|
||||
.maincontainer {
|
||||
position: relative;
|
||||
top: -50px;
|
||||
transform: scale(0.8);
|
||||
background: url("/public/images/forbidden/HauntedHouseBackground.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 700px 600px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
margin: 0px auto;
|
||||
display: grid;
|
||||
}
|
||||
.foregroundimg {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
top: -230px;
|
||||
z-index: 5;
|
||||
}
|
||||
.errorcode {
|
||||
position: relative;
|
||||
top: -200px;
|
||||
font-family: 'Creepster', cursive;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-size: 6em;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.errortext {
|
||||
position: relative;
|
||||
top: -260px;
|
||||
color: #FBD130;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
.bat {
|
||||
opacity: 0;
|
||||
position: relative;
|
||||
transform-origin: center;
|
||||
z-index: 3;
|
||||
}
|
||||
.bat:nth-child(1) {
|
||||
top: 380px;
|
||||
left: 120px;
|
||||
transform: scale(0.5);
|
||||
animation: 13s 1s flyBat1 infinite linear;
|
||||
}
|
||||
.bat:nth-child(2) {
|
||||
top: 280px;
|
||||
left: 80px;
|
||||
transform: scale(0.3);
|
||||
animation: 8s 4s flyBat2 infinite linear;
|
||||
}
|
||||
.bat:nth-child(3) {
|
||||
top: 200px;
|
||||
left: 150px;
|
||||
transform: scale(0.4);
|
||||
animation: 12s 2s flyBat3 infinite linear;
|
||||
}
|
||||
.body {
|
||||
position: relative;
|
||||
width: 50px;
|
||||
top: 12px;
|
||||
}
|
||||
.wing {
|
||||
width: 150px;
|
||||
position: relative;
|
||||
transform-origin: right center;
|
||||
}
|
||||
.leftwing {
|
||||
left: 30px;
|
||||
animation: 0.8s flapLeft infinite ease-in-out;
|
||||
}
|
||||
.rightwing {
|
||||
left: -180px;
|
||||
transform: scaleX(-1);
|
||||
animation: 0.8s flapRight infinite ease-in-out;
|
||||
}
|
||||
@keyframes flapLeft {
|
||||
0% { transform: rotateZ(0); }
|
||||
50% { transform: rotateZ(10deg) rotateY(40deg); }
|
||||
100% { transform: rotateZ(0); }
|
||||
}
|
||||
@keyframes flapRight {
|
||||
0% { transform: scaleX(-1) rotateZ(0); }
|
||||
50% { transform: scaleX(-1) rotateZ(10deg) rotateY(40deg); }
|
||||
100% { transform: scaleX(-1) rotateZ(0); }
|
||||
}
|
||||
@keyframes flyBat1 {
|
||||
0% { opacity: 1; transform: scale(0.5)}
|
||||
25% { opacity: 1; transform: scale(0.5) translate(-400px, -330px) }
|
||||
50% { opacity: 1; transform: scale(0.5) translate(400px, -800px) }
|
||||
75% { opacity: 1; transform: scale(0.5) translate(600px, 100px) }
|
||||
100% { opacity: 1; transform: scale(0.5) translate(100px, 300px) }
|
||||
}
|
||||
@keyframes flyBat2 {
|
||||
0% { opacity: 1; transform: scale(0.3)}
|
||||
25% { opacity: 1; transform: scale(0.3) translate(200px, -330px) }
|
||||
50% { opacity: 1; transform: scale(0.3) translate(-300px, -800px) }
|
||||
75% { opacity: 1; transform: scale(0.3) translate(-400px, 100px) }
|
||||
100% { opacity: 1; transform: scale(0.3) translate(100px, 300px) }
|
||||
}
|
||||
@keyframes flyBat3 {
|
||||
0% { opacity: 1; transform: scale(0.4)}
|
||||
25% { opacity: 1; transform: scale(0.4) translate(-350px, -330px) }
|
||||
50% { opacity: 1; transform: scale(0.4) translate(400px, -800px) }
|
||||
75% { opacity: 1; transform: scale(0.4) translate(-600px, 100px) }
|
||||
100% { opacity: 1; transform: scale(0.4) translate(100px, 300px) }
|
||||
}
|
||||
/*@media only screen and (max-width: 850px) {
|
||||
.maincontainer {
|
||||
transform: scale(0.6);
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
background-size: 600px 400px;
|
||||
}
|
||||
|
||||
.errortext {
|
||||
font-size: 1em;
|
||||
}
|
||||
}*/
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {Meteor} from "meteor/meteor";
|
||||
import {Route} from 'tinro';
|
||||
import {onMount} from 'svelte';
|
||||
import {useTracker} from 'meteor/rdb:svelte-meteor-data';
|
||||
import {Roles} from 'meteor/alanning:roles';
|
||||
import Chromebooks from './Chromebooks.svelte';
|
||||
import {BlazeTemplate} from 'meteor/svelte:blaze-integration';
|
||||
import {Records} from '../api/records.js'
|
||||
import ServiceConfiguration from "meteor/service-configuration";
|
||||
|
||||
let currentUser;
|
||||
//import './imports/ui/App.css';
|
||||
|
||||
//let currentUser;
|
||||
|
||||
onMount(async () => {
|
||||
// Meteor.subscribe('records');
|
||||
@@ -15,6 +162,18 @@
|
||||
// $: incompleteCount = useTracker(() => Tasks.find({checked: {$ne: true}}).count());
|
||||
|
||||
$: currentUser = useTracker(() => Meteor.user());
|
||||
$: isAdmin = useTracker(() => Roles.userIsInRole(currentUser._id, 'laptop-management', 'global'));
|
||||
|
||||
// Tracker.autorun(() => {
|
||||
// let user = Meteor.user();
|
||||
// let isManagement = user ? Roles.userIsInRole(user._id, 'laptop-management', 'global') : 0;
|
||||
//
|
||||
// if(user && isManagement) {
|
||||
// new ProcessLaptops({
|
||||
// target: document.getElementById('appView')
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
// const taskStore = Tasks.find({}, {sort: {createdAt: -1}});
|
||||
// $: {
|
||||
@@ -45,43 +204,66 @@
|
||||
function performLogout() {
|
||||
Meteor.logout();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<header>
|
||||
<!-- <h1>Todo List ({ $incompleteCount })</h1>-->
|
||||
<!-- <label className="hide-completed">-->
|
||||
<!-- <input-->
|
||||
<!-- type="checkbox"-->
|
||||
<!-- bind:checked={hideCompleted}-->
|
||||
<!-- />-->
|
||||
<!-- Hide Completed Tasks-->
|
||||
<!-- </label>-->
|
||||
|
||||
<!-- <BlazeTemplate template="loginButtons"/>-->
|
||||
{#if !$currentUser}
|
||||
<button type="button" on:click={performLogin}>Login</button>
|
||||
{:else}
|
||||
<button type="button" on:click={performLogout}>Logout</button>
|
||||
{/if}
|
||||
|
||||
<!--{#if $currentUser}-->
|
||||
<!-- <form class="new-task" on:submit|preventDefault={handleSubmit}>-->
|
||||
<!-- <input-->
|
||||
<!-- type="text"-->
|
||||
<!-- placeholder="Type to add new tasks"-->
|
||||
<!-- bind:value={newTask}-->
|
||||
<!-- />-->
|
||||
<!-- </form>-->
|
||||
<!--{/if}-->
|
||||
</header>
|
||||
<ul>
|
||||
<!--{#each tasks as task}-->
|
||||
<!-- <Task-->
|
||||
<!-- key={task._id}-->
|
||||
<!-- task={task}-->
|
||||
<!-- />-->
|
||||
<!--{/each}-->
|
||||
</ul>
|
||||
</div>
|
||||
<Route path="/">
|
||||
<div class="container">
|
||||
<header class="row">
|
||||
<nav class="col-12 center">
|
||||
<h1>AVUSD District Central</h1>
|
||||
<a href="/">Home</a>
|
||||
{#if isAdmin}
|
||||
<a href="/chromebooks">Chromebooks</a>
|
||||
{/if}
|
||||
</nav>
|
||||
{#if !$currentUser}
|
||||
<button type="button" on:click={performLogin}>Login</button>
|
||||
{:else}
|
||||
<button type="button" on:click={performLogout}>Logout</button>
|
||||
{/if}
|
||||
</header>
|
||||
</div>
|
||||
</Route>
|
||||
{#if $currentUser}
|
||||
{#if isAdmin}
|
||||
<Route path="/chromebooks/*">
|
||||
<Chromebooks/>
|
||||
</Route>
|
||||
{:else}
|
||||
<Route fallback redirect="/"/>
|
||||
{/if}
|
||||
{:else}
|
||||
<div className="container" style="background-color: #4d4242">
|
||||
<div class="maincontainer row">
|
||||
<div class="bat">
|
||||
<img class="wing leftwing"
|
||||
src="/images/forbidden/bat-wing.png">
|
||||
<img class="body"
|
||||
src="/images/forbidden/bat-body.png" alt="bat">
|
||||
<img class="wing rightwing"
|
||||
src="/images/forbidden/bat-wing.png">
|
||||
</div>
|
||||
<div class="bat">
|
||||
<img class="wing leftwing"
|
||||
src="/images/forbidden/bat-wing.png">
|
||||
<img class="body"
|
||||
src="/images/forbidden/bat-body.png" alt="bat">
|
||||
<img class="wing rightwing"
|
||||
src="/images/forbidden/bat-wing.png">
|
||||
</div>
|
||||
<div class="bat">
|
||||
<img class="wing leftwing"
|
||||
src="/images/forbidden/bat-wing.png">
|
||||
<img class="body"
|
||||
src="/images/forbidden/bat-body.png" alt="bat">
|
||||
<img class="wing rightwing"
|
||||
src="/images/forbidden/bat-wing.png">
|
||||
</div>
|
||||
<img class="foregroundimg" src="/images/forbidden/HauntedHouseForeground.png" alt="haunted house">
|
||||
|
||||
</div>
|
||||
<h1 class="errorcode">ERROR 403</h1>
|
||||
<div class="errortext">This area is forbidden. Turn back now!</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
41
imports/ui/ChromebookScan.svelte
Normal file
41
imports/ui/ChromebookScan.svelte
Normal file
@@ -0,0 +1,41 @@
|
||||
<style>
|
||||
.error {
|
||||
color: darkred;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import {Html5QrcodeScanner} from "html5-qrcode";
|
||||
|
||||
function onScanSuccess(decodedText, decodedResult) {
|
||||
console.log('Code matched ' + decodedResult);
|
||||
document.getElementById("log").prepend(decodedText);
|
||||
}
|
||||
|
||||
function onScanFailure(error) {
|
||||
}
|
||||
|
||||
function scanner() {
|
||||
let html5QrcodeScanner = new Html5QrcodeScanner("reader", {
|
||||
fps: 10,
|
||||
qrbox: {width: 250, height: 250}
|
||||
}, /* verbose */ false);
|
||||
|
||||
html5QrcodeScanner.render(onScanSuccess, onScanFailure);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div className="container">
|
||||
<div class="row">
|
||||
Hello World!
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div use:scanner id="reader" width="300px"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div id="log" class="col-12">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
34
imports/ui/Chromebooks.svelte
Normal file
34
imports/ui/Chromebooks.svelte
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
<style>
|
||||
nav {
|
||||
font-size: 2rem;
|
||||
}
|
||||
a {
|
||||
display: block;
|
||||
color: green;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import {Route} from 'tinro';
|
||||
import ChromebookScan from './ChromebookScan.svelte';
|
||||
</script>
|
||||
|
||||
<Route path="/">
|
||||
<div className="container">
|
||||
<div class="row">
|
||||
<nav class="col-12 center">
|
||||
<h1>Chromebook Management</h1>
|
||||
<a href="chromebooks/scan">Scan A Chromebook</a>
|
||||
<a href="chromebooks/byStudent">Chromebook History By Student</a>
|
||||
<a href="chromebooks/byChromebook">Chromebook History By Chromebook</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</Route>
|
||||
<Route path="/scan">
|
||||
<ChromebookScan/>
|
||||
</Route>
|
||||
<Route path="/byStudent">TODO: Use student email to look up Chromebook history</Route>
|
||||
<Route path="/byChromebook">TODO: Use chromebook ID (or picture of ID) to look up Chromebook history</Route>
|
||||
12
imports/ui/ProcessLaptops.svelte
Normal file
12
imports/ui/ProcessLaptops.svelte
Normal file
@@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import {Meteor} from "meteor/meteor";
|
||||
import {onMount} from 'svelte';
|
||||
|
||||
onMount(async () => {
|
||||
// Meteor.subscribe('records');
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<h1>Process Laptops</h1>
|
||||
</div>
|
||||
Reference in New Issue
Block a user