Skip to content
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

Merged
merged 60 commits into from
Nov 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
72320db
Add a development route for the Game Gig page
moosichu Nov 5, 2017
7a65e86
Add Game Gig event content
moosichu Nov 5, 2017
b7e742c
Move reusable components for hackathons to place that make sense
moosichu Nov 5, 2017
293b6bc
Make the clock actually functional!
moosichu Nov 5, 2017
d2b7d1e
Make CurrentTime work on an id basis
moosichu Nov 6, 2017
c7b6695
Add custom CSS mechanism
moosichu Nov 6, 2017
dca8442
Merge branch 'master' of ssh://github.com/hackersatcambridge/hac-webs…
moosichu Nov 6, 2017
74cd5ee
Replace dictionaries with lists of tuples
moosichu Nov 6, 2017
a82c407
Add a functional countdown timer
moosichu Nov 6, 2017
c63a609
Merge branch 'master' of ssh://github.com/hackersatcambridge/hac-webs…
moosichu Nov 6, 2017
4774a7a
Make PostCard Nodeable
moosichu Nov 6, 2017
020ca52
Update code to remove explicit .node cases
moosichu Nov 6, 2017
d675e1f
Implement JavaScript templating in Script.swift
moosichu Nov 6, 2017
f47dec3
Refactor the twitter feed
moosichu Nov 6, 2017
6f72c79
Make CurrentTime.swift use CurrentTime.js
moosichu Nov 6, 2017
45d5ce5
Aim to ensure Date behaviour is correct
moosichu Nov 6, 2017
502bfc6
Clearly label JavaScript string escape location
moosichu Nov 6, 2017
28c410b
Remove hardcoded date objects in CountDownTimer.swift
moosichu Nov 6, 2017
9a621c9
Make CountDownTimer messages configurable
moosichu Nov 6, 2017
129a222
Make the event scheduler use Swift Date objects
moosichu Nov 6, 2017
7aa6208
Cleanup Hackathon protocol
moosichu Nov 7, 2017
41b5125
Move Script.swift to a more central folder
moosichu Nov 7, 2017
2b1e486
Replace usage of 'map' with more sensible for loop
moosichu Nov 7, 2017
5b809a2
Merge branch 'master' of https://github.com/hackersatcambridge/hac-we…
moosichu Nov 7, 2017
452d54c
Merge branch 'master' of github.com:hackersatcambridge/hac-website in…
moosichu Nov 11, 2017
2561af5
Merge branch 'master' of https://github.com/hackersatcambridge/hac-we…
moosichu Nov 16, 2017
d27d9a6
Update Gamegig to use new markdown format
moosichu Nov 16, 2017
0c1f6c0
Make section on rules use multi-line strings and Markdown
moosichu Nov 16, 2017
323c7d1
Make minor GameGig corrections
moosichu Nov 17, 2017
4776fcc
Perform initial styling of the Game Gig 3000
moosichu Nov 17, 2017
4c6d4fd
Highlight important GameGig rules
moosichu Nov 17, 2017
45cdae2
Add cheesy link-hover effect
moosichu Nov 17, 2017
435e0d6
Make Gobo and ES logos links, update Rules
moosichu Nov 17, 2017
616c7d9
Fix typo
moosichu Nov 17, 2017
6e2b1c5
Make corrections based on feedback from Bogdan
moosichu Nov 17, 2017
77631b6
Replace BACKEND_JS_DIR from environment vars with const
moosichu Nov 17, 2017
b05fe5f
Improve styling and remove twitter feed
moosichu Nov 19, 2017
d24ec90
Improve styling of bottom bar
moosichu Nov 19, 2017
42bd916
Merge branch 'master' into feature/game-gig
moosichu Nov 19, 2017
e248f42
Merge branch 'master' into feature/game-gig
moosichu Nov 21, 2017
6bedd71
Add todo for custom .styl files
moosichu Nov 21, 2017
2eee8f9
Update styles
Pinpickle Nov 28, 2017
30c1ff3
Update GameGig event feature and make it point to live event URL
moosichu Nov 28, 2017
bc9c90c
Merge branch 'master' into feature/game-gig
moosichu Nov 28, 2017
9ad9790
Make semicolons in `CountDownTimer.js` consistent
moosichu Nov 29, 2017
403798b
Make semicolons in `CurrentTime.js` consistent
moosichu Nov 29, 2017
a2bd02d
Remove old images
moosichu Nov 29, 2017
aca7ecb
Merge branch 'master' into feature/game-gig
moosichu Nov 29, 2017
a7931aa
Comment on CountDownTimer struct
moosichu Nov 29, 2017
e4e3bfd
Lowercase variable names
moosichu Nov 29, 2017
d4d75a4
Remove traces of twitter feed from game gig
moosichu Nov 29, 2017
3daa214
Link to our custom code of conduct
moosichu Nov 29, 2017
8eb2d00
Improve function for getting gameGigDates
moosichu Nov 29, 2017
68bd026
Add poster link back to the event
moosichu Nov 29, 2017
757c35c
Replace CSS vars with stylus ones
moosichu Nov 29, 2017
100bc45
Rename escapes to definitions
moosichu Nov 29, 2017
8e41e46
Merge branch 'master' into feature/game-gig
moosichu Nov 29, 2017
c86d65e
Add comment to JavaScript protocol
moosichu Nov 29, 2017
5ec4388
Fix error in comments
moosichu Nov 29, 2017
d31a02e
Make links target blank
moosichu Nov 29, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Sources/HaCWebsiteLib/Controllers/HackathonController.swift
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()
}
}
}
38 changes: 38 additions & 0 deletions Sources/HaCWebsiteLib/ViewModels/Hackathons/CountDownTimer.js
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);
46 changes: 46 additions & 0 deletions Sources/HaCWebsiteLib/ViewModels/Hackathons/CountDownTimer.swift
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
Copy link
Contributor

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

Copy link
Contributor Author

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.

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
]
)
)
)
}
}
9 changes: 9 additions & 0 deletions Sources/HaCWebsiteLib/ViewModels/Hackathons/CurrentTime.js
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);
16 changes: 16 additions & 0 deletions Sources/HaCWebsiteLib/ViewModels/Hackathons/CurrentTime.swift
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 {
Copy link
Contributor

Choose a reason for hiding this comment

The 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. String+idMangle.swift

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use Link from #163 when that ships

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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)
}
))
)
)
}
}
5 changes: 5 additions & 0 deletions Sources/HaCWebsiteLib/ViewModels/Hackathons/Hackathon.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import HaCTML

public protocol Hackathon: Nodeable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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?

Copy link
Contributor

Choose a reason for hiding this comment

The 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 Hackathons to have or thought that we would require Hackathons to do something or expose some data in the future. If you can see a use case then leave it in but otherwise let's ditch

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.


}
24 changes: 24 additions & 0 deletions Sources/HaCWebsiteLib/ViewModels/Hackathons/Schedule.swift
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
)
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ extension LandingFeatures {
duration: 10 * 60 * 60
),
eventLink: "https://www.facebook.com/events/124219834921040/",
liveLink: "/game-gig",
liveLink: "/gamegig",
hero: ImageHero(
background: .image(Assets.publicPath("/images/gamegig-bg.png")),
imagePath: Assets.publicPath("/images/gamegig.svg"),
alternateText: "HaC Game Gig 3000 on the 1st of November"
background: .image(Assets.publicPath("/images/gamegig3000/gamegig-background.jpg")),
imagePath: Assets.publicPath("images/gamegig3000/gamegig-foreground.png"),
alternateText: "HaC Game Gig 3000 on the 1st of December 2017!"
),
textShade: .dark
textShade: .light
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ enum LandingFeatures {
LandingFeatures.programmingInRust,
LandingFeatures.introToProgramming4,
LandingFeatures.binaryExploitation,
LandingFeatures.gamesWithLove
LandingFeatures.gamesWithLove,
LandingFeatures.gameGig
]

/// Gets the most currently appropriate feature
Expand Down
Loading