-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the Game Gig event page #113
Changes from all commits
72320db
7a65e86
b7e742c
293b6bc
d2b7d1e
c7b6695
dca8442
74cd5ee
a82c407
c63a609
4774a7a
020ca52
d675e1f
f47dec3
6f72c79
45d5ce5
502bfc6
28c410b
9a621c9
129a222
7aa6208
41b5125
2b1e486
5b809a2
452d54c
2561af5
d27d9a6
0c1f6c0
323c7d1
4776fcc
4c6d4fd
45cdae2
435e0d6
616c7d9
6e2b1c5
77631b6
b05fe5f
d24ec90
42bd916
e248f42
6bedd71
2eee8f9
30c1ff3
bc9c90c
9ad9790
403798b
a2bd02d
aca7ecb
a7931aa
e4e3bfd
d4d75a4
3daa214
8eb2d00
68bd026
757c35c
100bc45
8e41e46
c86d65e
5ec4388
d31a02e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import Foundation | ||
import Kitura | ||
import HaCTML | ||
import LoggerAPI | ||
import HeliumLogger | ||
import DotEnv | ||
import SwiftyJSON | ||
|
||
struct HackathonController { | ||
static func handler(hackathon: Hackathon) -> RouterHandler { | ||
return { request, response, next in | ||
try response.send( | ||
hackathon.node.render() | ||
).end() | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
function updateCountDownTimer() { | ||
const startDate = {{startDate}}; | ||
const endDate = {{endDate}}; | ||
const CountDownTimerId = {{id}}; | ||
const CountDownTimerPreId = {{preId}}; | ||
const beforeEventMessage = {{beforeEventMessage}}; | ||
const duringEventMessage = {{duringEventMessage}}; | ||
const afterEventMessage = {{afterEventMessage}}; | ||
|
||
const current = new Date(); | ||
|
||
let timeLeft = 0; | ||
if(current < startDate) { | ||
document.getElementById(CountDownTimerPreId).innerHTML = beforeEventMessage; | ||
timeLeft = startDate.getTime() - current.getTime(); | ||
} else { | ||
document.getElementById(CountDownTimerPreId).innerHTML = duringEventMessage; | ||
timeLeft = endDate.getTime() - current.getTime(); | ||
} | ||
|
||
// Abort if time is up | ||
if(timeLeft < 0) | ||
{ | ||
document.getElementById(CountDownTimerId).innerHTML = afterEventMessage; | ||
return; | ||
} | ||
|
||
let hours = Math.floor(timeLeft / (1000*60*60)); | ||
let mins = Math.floor(timeLeft/(1000 * 60) - hours * 60); | ||
let secs = Math.floor(timeLeft/1000 - mins * 60 - hours * 60 * 60); | ||
|
||
document.getElementById(CountDownTimerId).innerHTML = | ||
hours + ":" + (mins<10?"0":"") + mins + "<span id=\"seconds\">:" + (secs<10?"0":"") + secs +"</span>"; | ||
} | ||
|
||
updateCountDownTimer(); | ||
|
||
setInterval(updateCountDownTimer,1000); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import HaCTML | ||
import Foundation | ||
|
||
/* | ||
A count down timer for an event alongside a count down message. | ||
|
||
The two necessary things for this are a startDate and and endDate. You can also | ||
set custom messages. They will show different things based on whether the timer | ||
is counting-down to the start of the event, to the end of the event, or if the | ||
event is over. | ||
*/ | ||
struct CountDownTimer : Nodeable { | ||
let startDate : Date | ||
let endDate : Date | ||
let id = "CountDownTimer\(UUID().description)" | ||
|
||
let preId = "CountDownTimerPre\(UUID().description)" // the id of the countdown message | ||
let beforeEventMessage = "Time left to start" | ||
let duringEventMessage = "Time remaining" | ||
let afterEventMessage = "Time's up!" | ||
|
||
var node: Node { | ||
return Fragment( | ||
El.Div[Attr.className => "CountDownTimer"].containing( | ||
El.Div[ | ||
Attr.className => "CountDownTimer__pre", | ||
Attr.id => preId | ||
].containing(""), | ||
El.Div[ | ||
Attr.className => "CountDownTimer_time", | ||
Attr.id => id | ||
].containing("YOU SHOULD SEE THE TIME REMAINING HERE"), | ||
Script( | ||
file: "Hackathons/CountDownTimer.js", | ||
definitions: [ | ||
"startDate": startDate, "endDate": endDate, | ||
"id": id, "preId": preId, | ||
"beforeEventMessage": beforeEventMessage, | ||
"duringEventMessage": duringEventMessage, | ||
"afterEventMessage" : afterEventMessage | ||
] | ||
) | ||
) | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
function updateClock() { | ||
const id = {{id}}; | ||
const current = new Date(); | ||
document.getElementById(id).innerHTML = current.getHours()+":"+(current.getMinutes()<10?"0":"") + current.getMinutes(); | ||
} | ||
|
||
updateClock(); | ||
|
||
setInterval(updateClock,1000); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import HaCTML | ||
import Foundation | ||
|
||
struct CurrentTime : Nodeable { | ||
let id = "CurrentTime\(UUID().description)" | ||
|
||
var node: Node { | ||
return Fragment( | ||
El.Span[Attr.id => id, Attr.className => "CurrentTime"].containing("Current Time"), | ||
Script( | ||
file: "Hackathons/CurrentTime.js", | ||
definitions: ["id": id] | ||
) | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
import HaCTML | ||
import Foundation | ||
|
||
// swiftlint:disable line_length | ||
|
||
|
||
extension String { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! We could move this out to somewhere else. Files for extensions conventionally take the form: e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created issue #171 for this. |
||
func idMangle() -> String { | ||
return self.replacingOccurrences(of: " ", with: "-").lowercased() | ||
} | ||
} | ||
|
||
// TODO: investigate if the information here can be extracted from the landing feature | ||
struct GameGig2017: Hackathon { | ||
let gameEngines = [ | ||
("Unreal Engine", "https://www.unrealengine.com"), | ||
("Unity", "https://unity3d.com/"), | ||
("LÖVE", "https://love2d.org/"), | ||
("GameMaker", "lhttps://www.yoyogames.com/gamemaker"), | ||
("raylib", "http://www.raylib.com/") | ||
] | ||
|
||
let socialMediaLinks = [ | ||
("Facebook Page", "https://www.facebook.com/hackersatcambridge"), | ||
("Facebook Event", "https://www.facebook.com/events/124219834921040/"), | ||
("Twitter", "https://twitter.com/hackersatcam") | ||
] | ||
|
||
let tutorials = [ | ||
("Web Dev with Mozilla", "https://globalgamejam.org/news/dev-web-mozilla") | ||
] | ||
|
||
let goboLogo = El.A[Attr.href => "http://studiogobo.com/", | ||
Attr.target => "_blank" | ||
].containing( | ||
El.Img[ | ||
Attr.src => Assets.publicPath("/images/sponsors/studiogobo-logo.svg"), | ||
Attr.alt => "Studio Gobo" | ||
] | ||
) | ||
|
||
let electricSquareLogo = El.A[Attr.href => "https://www.electricsquare.com/", | ||
Attr.target => "_blank" | ||
].containing( | ||
El.Img[ | ||
Attr.src => Assets.publicPath("/images/sponsors/electricsquare-logo.svg"), | ||
Attr.alt => "Electric Square" | ||
] | ||
) | ||
|
||
/** | ||
Creates a GameGigCard element, the title becomes its id (spaces are replaced with hyphons). | ||
|
||
A GameGigCard is a self-contained element that represents a floating card on a background. It is used for sections. | ||
*/ | ||
func GameGigCard(title: String, content: Nodeable) -> Node { | ||
return El.Div[Attr.className => "GameGigCard"].containing( | ||
El.Span[ | ||
Attr.className => "GameGigCard__title", | ||
Attr.id => title.idMangle() | ||
].containing(title), | ||
content | ||
) | ||
} | ||
|
||
func ListOfLinks(dict: [(String, String)]) -> Nodeable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yip |
||
return El.Ul.containing( | ||
dict.map { (key, value) in | ||
El.Li.containing( | ||
El.A[Attr.href => value, Attr.target => "_blank"].containing(key) | ||
) | ||
} | ||
) | ||
} | ||
|
||
func Rules() -> Nodeable { | ||
return Markdown(""" | ||
The aim of the Hackers at Cambridge Game Gig 3000 is to create a fun, | ||
exciting, original game from scratch in less than 12 hours. | ||
We've created a few simple rules to help the process go smoothly for | ||
everyone. | ||
|
||
- **Please note that Computer Science applicants for the University of | ||
Cambridge are taking CSAT tests in LT1 and LT2, so please be quiet | ||
around them. This is especially important between the hours of | ||
10:00-12:00 and 15:00-17:00 when the actual tests will be taking place. | ||
DO NOT TAKE THEIR REFRESHMENTS, WE HAVE OURS IN FW11.** | ||
|
||
- Also respect and look after the Intel Lab, FW11 and the Computer Lab. | ||
Note that food or drink may only be consumed in FW11, and we will be | ||
checking! | ||
|
||
- You can work on your game in a team of up to four people. | ||
|
||
- Game-making commences at 10:30 and finishes at 20:00. | ||
|
||
- You are free to do whatever you like with your game after the Game Gig. | ||
You own the copyright to all the material you create during the event. | ||
|
||
- You are free to use any tools or libraries available to you to create | ||
your game. You can start with any pre-existing code or content that you | ||
like and you are free to use third-party assets, as long as you let the | ||
judges know what you created yourself and what you didn't. Failure to do | ||
so could risk disqualification. | ||
|
||
- It's your responsibility to make sure that you have the right to use | ||
third-party assets (for example, that they are public domain or | ||
available under an appropriate license). | ||
|
||
- We will be taking lots of photos throughout the event, and publishing | ||
them. You and your content may appear on some of these photos. We aim to | ||
publish photos that show everyone at their best, but there might be a | ||
few that you don’t like. If you see a photo like this, let us know so | ||
that we can try to take it down - but be aware that it is difficult to | ||
completely erase a photo from all media channels. | ||
|
||
- Be kind and considerate to your fellow hackers and our volunteers. | ||
We're all here to have fun! By participating in the hackathon, you agree | ||
to abide by this | ||
[Code of Conduct](https://hackcodeofconduct.org/537-hac_game_gig_3000). | ||
""" | ||
) | ||
} | ||
|
||
func GameGigCardsContainer(content: Nodeable) -> Node { | ||
return El.Div[Attr.className => "GameGigCardsContainer"].containing( | ||
content | ||
) | ||
} | ||
|
||
/** | ||
Not currently used but may be useful for future events | ||
*/ | ||
func NavBar(elements: [(String, Nodeable)]) -> Node { | ||
return El.Div[Attr.className => "GameGigNavBar"].containing( | ||
El.Span[Attr.className => "GameGigNavBar__poweredby"].containing( | ||
"Powered by ", | ||
goboLogo, | ||
" and ", | ||
electricSquareLogo | ||
), | ||
Fragment(elements.map{ title, content in | ||
El.Span[Attr.className => "GameGigNavBar__item"].containing( | ||
El.A[ | ||
Attr.href => "#\(title.idMangle())" | ||
].containing( | ||
title | ||
) | ||
) | ||
}), | ||
El.Span[Attr.className => "GameGigNavBar__time"].containing(CurrentTime()) | ||
) | ||
} | ||
|
||
// Get a Swift Date object for given hour/minute on the GameGig | ||
func gameGigDate(hour: Int, minute: Int) -> Date { | ||
return Date.from(year: 2017, month: 12, day: 1, hour: hour, minute: minute) | ||
} | ||
|
||
var node: Node { | ||
// Define all time related info | ||
let gigStartDate = gameGigDate(hour: 10, minute: 30) | ||
let gigEndDate = gameGigDate(hour: 20, minute: 30) | ||
|
||
|
||
let schedule = [ | ||
("Arrival", gameGigDate(hour: 10, minute: 00)), | ||
("Start Jamming!", gigStartDate), | ||
("Intro to Unity Workshop", gigStartDate), | ||
("Lunch", gameGigDate(hour: 12, minute: 00)), | ||
("Dinner", gameGigDate(hour: 18, minute: 00)), | ||
("Stop Jamming!", gigEndDate), | ||
("LT1 Prizes and wrap-up", gameGigDate(hour: 21, minute: 00)) | ||
] | ||
|
||
// Define the list of game gig "cards" that are displayed as content | ||
let gameGigCards = [ | ||
("Schedule", Schedule(schedule: schedule)), | ||
("Get Involved", ListOfLinks(dict: socialMediaLinks)), | ||
("Tutorials", ListOfLinks(dict: tutorials)), | ||
("Game Engines", ListOfLinks(dict: gameEngines)), | ||
("Rules", Rules()) | ||
] | ||
|
||
return UI.Pages.base( | ||
title: "Hackers at Cambridge Game Gig 80's", | ||
customStylesheets: ["gamegig2017"], | ||
content: Fragment( | ||
El.Div[Attr.className => "GameGigHero"].containing( | ||
El.Img[Attr.className => "GameGigHero__image", Attr.src => Assets.publicPath("/images/gamegig3000/gamegig-foreground.png")] | ||
), | ||
El.Div[Attr.className => "GameGigTopBar"].containing( | ||
electricSquareLogo[Attr.className => "GameGigTopBar__image GameGigTopBar__electricSquare"], | ||
El.Div[Attr.className => "GameGigTopBar__filler"], | ||
goboLogo[Attr.className => "GameGigTopBar__image GameGigTopBar__gobo"] | ||
), | ||
CountDownTimer(startDate: gigStartDate, endDate: gigEndDate), | ||
GameGigCardsContainer(content: Fragment( | ||
gameGigCards.map{ title, content in | ||
GameGigCard(title: title, content: content) | ||
} | ||
)) | ||
) | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import HaCTML | ||
|
||
public protocol Hackathon: Nodeable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because in the future we will have multiple hackathons. TBH I created this when I wasn't sure if there was going to be a set format or not. Shuold I remove? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would maybe be useful if there was any specific data that we needed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think this will become useful once we have properly defined event streams, so I will leave it in. |
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import HaCTML | ||
import Foundation | ||
|
||
// TODO: add the ability to highlight the item in the schedule best on the time! | ||
struct Schedule : Nodeable { | ||
let schedule: [(String, Date)] | ||
|
||
var node: Node { | ||
let formatter = DateFormatter() | ||
formatter.dateFormat = "HH:mm" | ||
formatter.timeZone = TimeZone(identifier: "Europe/London") | ||
formatter.locale = Locale(identifier: "en_GB") | ||
return El.Ul.containing( | ||
schedule.map {event, date in | ||
let timeString = formatter.string(from: date) | ||
return El.Li.containing( | ||
timeString, | ||
" ", | ||
event | ||
) | ||
} | ||
) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't love that we are changing the ID of an element. I expect we can get away without this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have created issue #170 for this, I think fixing this is low priority.