Skip to content

Commit 18222ac

Browse files
committed
Merge branch 'dev' into building-pins
2 parents 070bb22 + 0d519b1 commit 18222ac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1642
-289
lines changed

Diff for: README.md

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,33 @@
11
<h1 align="center">
2-
<img src="https://raw.githubusercontent.com/Vacansee/app/vue/src/assets/logo.png" height="128">
2+
<img src="https://raw.githubusercontent.com/Vacansee/app/live/src/assets/logo.png" height="128">
3+
4+
35
<br>
4-
Vacansee
6+
7+
[Vacansee](https://assets-global.website-files.com/6257adef93867e50d84d30e2/636e0a6918e57475a843f59f_icon_clyde_black_RGB.svg)
8+
59
</h1>
6-
<p align="center"><strong>It's Free Real Estate</strong></p>
710

8-
**Vacansee** is a interactive heatmap that shows students what rooms and facilities are/will be available based on data scraped from schedules (SIS), booking services (EMS), and wifi telemetry (`rpi_wpa2`).
11+
<img src="https://img.shields.io/uptimerobot/ratio/7/m795932889-e68ac3da3cf053a05dedaa82?style=flat-square&logo=alwaysdata&logoColor=gray&labelColor=white" height="24">
12+
13+
<img align="right" src="docs/demo-01.png" width="250px">
14+
15+
### What is it?
16+
17+
18+
**Vacansee** is an interactive (heat)map for displaying live stats on rooms/facilities @ RPI.
19+
20+
This includes:
21+
- Expected building occupancy and foot traffic
22+
- Active/upcoming classes & where to find them
23+
- Printer availability
24+
- What dining halls are serving, and for how long
25+
- —and more to come!
26+
27+
We intend to become the de facto one-stop-shop for event discovery, occupancy tracking, and general navigation on campus.
28+
</td><td>
29+
30+
931

1032
<br>
1133

Diff for: docs/demo-01.png

270 KB
Loading

Diff for: docs/demo-02.png

328 KB
Loading

Diff for: package.json

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
},
1010
"dependencies": {
1111
"@vueuse/core": "^9.13.0",
12+
"color.js": "^1.2.0",
1213
"moment": "^2.29.4",
1314
"moment-timezone": "^0.5.43",
1415
"primevue": "^3.37.0",

Diff for: pnpm-lock.yaml

+8-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/App.vue

+110-52
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Basic Imports
33
import { RouterLink, RouterView } from 'vue-router'
44
import Logo from '@/assets/logo.svg?component'
5+
import PollIcon from '@/assets/icons/poll.svg?component'
6+
import GHIcon from '@/assets/icons/github.svg?component'
57
import AutoComplete from 'primevue/autocomplete'
68
import Button from "primevue/button"
79
import Toast from 'primevue/toast'
@@ -10,25 +12,26 @@ import Toast from 'primevue/toast'
1012
<template>
1113
<Toast/>
1214
<!-- HTML For Header -->
13-
<header id="header" v-bind:class="{ 'homePageLogo': $route.path == '/' }">
14-
15-
<div class="left-nav">
16-
<RouterLink to="/"> <Logo class="logo" height="75" width="75"/> </RouterLink>
17-
<div class="search">
18-
<AutoComplete v-model="selection" placeholder="Search for a building or class..." :suggestions="filteredResults" @complete="filterResults" @item-select="searchFunc"></AutoComplete>
19-
</div>
15+
<header id="header">
16+
<div id="left-nav">
17+
<RouterLink to="/"> <Logo class="logo" height="75" width="75"/>
18+
</RouterLink>
2019
</div>
2120

22-
<div class="right-nav">
23-
<a href="mailto:[email protected]"><Button class="nav-btn">
24-
<img src="./assets/icons/poll.svg" height="30" width="30" />
21+
<div id="right-nav">
22+
<a href="https://forms.gle/Tu5xSSjK1MkZDXK69" target="_blank" rel="noopener noreferrer"><Button class="nav-btn" aria-label="Feedback" >
23+
<PollIcon height="25" width="25"/>
2524
</Button></a>
26-
<a href="https://github.com/Vacansee"><Button class="nav-btn">
27-
<img src="./assets/icons/github.svg" height="30" width="30"/>
25+
<a href="https://github.com/Vacansee/app" target="_blank" rel="noopener noreferrer"><Button class="nav-btn" aria-label="GitHub" >
26+
<GHIcon height="25" width="25"/>
2827
</Button></a>
2928
</div>
30-
</header>
31-
29+
</header>
30+
<div id="mobile-nav">
31+
<Teleport to="#left-nav" :disabled="global.aspectRatio > 1.5">
32+
<AutoComplete class="search" :style="{'width':'100%'}" :input-style="{'width': '100%'}" v-model="selection" :placeholder="ex" :suggestions="suggest" @complete="filterRes" @item-select="goTo" @focus.native="searchFocus(true)" @blur.native="searchFocus(false)"></AutoComplete>
33+
</Teleport>
34+
</div>
3235

3336
<RouterView />
3437
</template>
@@ -37,7 +40,14 @@ import Toast from 'primevue/toast'
3740
export default {
3841
data() {
3942
return {
40-
filteredResults: [],
43+
exs: [
44+
"a building: Russell Sage",
45+
"a dept. code: CSCI 1200",
46+
"a room: DCC 308",
47+
"a CRN: 80385"
48+
],
49+
ex: "",
50+
suggest: [],
4151
selection: ""
4252
}
4353
},
@@ -52,81 +62,129 @@ export default {
5262
else
5363
document.getElementById("header").style.opacity = "1";
5464
}
55-
},
56-
'global.error': {
57-
handler() {
58-
if (this.global.error) this.$showToast({title: 'Failed to load data', body: this.global.error})
59-
}
6065
}
6166
},
67+
mounted() {
68+
this.changeEx()
69+
setInterval(this.changeEx, 5000);
70+
},
6271
methods: {
63-
filterResults(event) {
64-
// filter buildings and classes
72+
changeEx() {
73+
const ex = this.exs.shift()
74+
this.ex = `Try ${ex}`; this.exs.push(ex)
75+
},
76+
searchFocus(is) {
77+
this.global.sFocus = is
78+
// console.log("sFocus:", is)
79+
},
80+
filterRes(event) {
81+
// Case & whitespace insensitive, ignore some characters:
82+
const query = event.query.toLowerCase().replace(/\s{2,}/g, ' ').replace(/["#]/g, '')
6583
setTimeout(() => {
66-
this.filteredResults = [];
67-
Object.keys(this.global.data).map((bid) => {
68-
this.filteredResults.push(bid.toString() + " (" + this.global.data[bid].meta.name.toString() + ")");
84+
this.suggest = []
85+
// Transform, sort, filter global.data + global.searchData:
86+
this.suggest = Object.keys(this.global.data).concat(this.global.searchData.flatMap(Object.keys))
87+
.map(key => {
88+
if (key in this.global.data) return `${key.toString()} (${this.global.data[key].meta.name.toString()})`
89+
else return key
6990
})
70-
this.filteredResults.sort();
71-
this.filteredResults = this.filteredResults.map((bid) => {
72-
return bid.replace(/_/g, ' ');
73-
})
74-
.filter((result) => {
75-
return result.toLowerCase().includes(event.query.toLowerCase());
76-
});
77-
}, 250);
91+
.filter(s => s.toLowerCase().includes(query))
92+
.sort()
93+
.map(s => s.replace(/_/g, ' '));
94+
}, 100);
7895
},
79-
searchFunc() {
80-
// select building or class here
81-
this.global.bldg = this.selection.substring(0, this.selection.indexOf("(") - 1);
82-
this.selection = "";
96+
goTo() {
97+
const abbrev = this.selection.substring(0, this.selection.indexOf("(") - 1)
98+
if (abbrev in this.global.data) {
99+
this.global.bldg = abbrev, this.selection = ""
100+
console.log(`Building "${abbrev}" selected`)
101+
return
102+
}
103+
else if (this.selection in this.global.searchData[2]) { // toRoom
104+
const [bldg, room] = this.selection.split(" ")
105+
this.global.floor = parseInt(room[0]) // TODO: non-numerical room #s
106+
this.global.room = room, this.global.bldg = bldg
107+
console.log(`Room "${this.selection}" selected`)
108+
this.selection = ""
109+
return
110+
}
111+
let CRN = ""
112+
if (this.selection in this.global.searchData[1]) { // deptToCRN
113+
CRN = this.global.searchData[1][this.selection]
114+
console.log(`Using dept code "${this.selection}"`)
115+
}
116+
else if (this.selection in this.global.searchData[0]) CRN = this.selection // byCRN
117+
// TODO: show all locations (pins), calc time 'til begin/end
118+
const [bldg, room] = Object.keys(this.global.searchData[0][CRN])[0].split(" ")
119+
this.global.floor = parseInt(room[0])
120+
this.global.room = room, this.global.bldg = bldg, this.selection = ""
121+
console.log(`Room w/ CRN #${CRN} selected`)
83122
}
84123
}
85124
}
86125
</script>
87126
<style scoped>
88127
@import './assets/main.css';
89128
/* Everything from here on in the file is basic css */
90-
.homePageLogo {
91-
position: absolute;
92-
}
93129
94130
header {
95-
z-index: 7;
96-
display: flex;
97-
padding: 1rem;
131+
pointer-events: none;
132+
position: absolute;
133+
z-index: 6;
98134
}
99135
100136
.logo {
101-
display: block;
102-
margin: 0 1rem 0 0;
137+
margin-right: 1rem;
103138
pointer-events: all;
139+
filter: drop-shadow(0px 5px 20px white);
104140
}
105141
106142
.nav-btn {
143+
fill: #205C5B;
107144
margin: .5rem;
145+
width: 3.25rem;
146+
height: 3.25rem;
147+
justify-content: center;
148+
background-color: var(--unusedfill);
149+
border: 2px solid var(--buildbord);
150+
box-shadow: 0px 5px 25px rgba(0, 10, 20, 0.08);
108151
pointer-events: all;
109152
}
110153
111-
.left-nav {
112-
position: fixed;
154+
.nav-btn:hover,
155+
.nav-btn:active {
156+
fill: white;
157+
}
158+
159+
#left-nav {
113160
display: flex;
114-
pointer-events: none;
115161
padding: .5rem 1rem;
116-
top: 0;
117-
left: 0;
118162
}
119163
120164
.search {
165+
width: 250px !important;
166+
border: 2px solid var(--walkpath);
167+
box-shadow: 0px 5px 25px rgba(0, 10, 20, 0.08);
168+
border-radius: 10px;
121169
align-self: center;
122170
pointer-events: all;
123171
}
124172
125-
.right-nav {
173+
#right-nav {
126174
position: fixed;
127-
pointer-events: none;
128175
padding: .8rem 1rem;
129176
top: 0;
130177
right: 0;
131178
}
179+
180+
#mobile-nav {
181+
width: 100%;
182+
display: flex;
183+
justify-content: center;
184+
pointer-events: none;
185+
position: absolute;
186+
bottom: 2vh;
187+
z-index: 6;
188+
}
189+
132190
</style>

Diff for: src/assets/base.css

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
--section-gap: 160px;
3737

3838
--background: #ffffff;
39+
--soft-bg: #eaf2f0;
3940
--title: #1f4045;
4041

4142
--carroad: #d4e5e2;

Diff for: src/assets/floors/Academy1.svg

+31
Loading

Diff for: src/assets/floors/Academy2.svg

+5
Loading

Diff for: src/assets/floors/Academy3.svg

+6
Loading

Diff for: src/assets/floors/Academy4.svg

+5
Loading

0 commit comments

Comments
 (0)