Skip to content

Commit

Permalink
Merge pull request #33 from front-seat/dave/homepage
Browse files Browse the repository at this point in the history
Implement basic homepage
  • Loading branch information
davepeck authored Apr 30, 2024
2 parents e2f24ea + 622bcc8 commit 2e7ca7f
Show file tree
Hide file tree
Showing 9 changed files with 370 additions and 24 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ We spend all our hipster tech tokens for this project to help us build a front-e
- [css-scope-inline](https://github.com/gnat/css-scope-inline)
- [surreal](https://github.com/gnat/surreal?tab=readme-ov-file)

Having never used any of these toys before, we'll see how this pans out.
Having never used any of these toys before, we'll see how this pans out. (Update: so far, I sorta like HTMX but don't love how I've structured everything with the other two. And I hate Django templates as much as I remember.)

(Others under consideration include [django-slippers](https://github.com/mixxorz/slippers), [django-template-partials](https://github.com/carltongibson/django-template-partials), and [django-components](https://github.com/EmilStenstrom/django-components). And don't forget the [django-htmx-patterns](https://github.com/spookylukey/django-htmx-patterns/) documentation.)

Expand Down
26 changes: 13 additions & 13 deletions server/static/img/voter_bowl_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion server/vb/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ def __str__(self):
"""Return the school model's string representation."""
return f"School: {self.name}"

@property
def relative_url(self) -> str:
"""Return the relative URL for the school."""
return reverse("vb:school", args=[self.slug])

@property
def absolute_url(self) -> str:
"""Return the absolute URL for the school."""
return f"{settings.BASE_URL}{self.relative_url}"


class Logo(models.Model):
"""A single logo for a school."""
Expand Down Expand Up @@ -163,7 +173,7 @@ def current(self, when: datetime.datetime | None = None) -> "Contest | None":
class Contest(models.Model):
"""A single contest in the competition."""

objects = ContestManager()
objects: ContestManager = ContestManager()

# For now, we assume that each contest is associated with a single school.
school = models.ForeignKey(
Expand Down
139 changes: 139 additions & 0 deletions server/vb/templates/components/ongoing_contest.dhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<div data-logo-bg-color="{{ contest.school.logo.bg_color }}">
<style>
me {
border: 3px solid black;
color: black;
font-weight: 400;
font-size: 18px;
line-height: 140%;
padding-left: 1em;
padding-right: 1em;
position: relative;
}

me .content {
display: flex;
flex-direction: column;
}

me .logo {
--logo-bg-color: transparent;
border-radius: 100%;
border: 2px solid black;
background-color: var(--logo-bg-color);
overflow: hidden;
width: 60px;
height: 60px;
margin: 1.5em auto 1em auto;
}

me .logo img {
width: 100%;
height: 100%;
object-fit: contain;
}

me .school {
margin: 0;
font-weight: 500;
font-size: 24px;
line-height: 100%;
display: flex;
justify-content: center;
}

me .description {
margin-bottom: 0;
}

me .button-holder {
width: 100%;
}

me .button-holder a {
width: 100%;
}

/* A centered box at the top of the card */
me .box {
position: absolute;
top: -1em;
left: 50%;
transform: translateX(-50%);
border: 3px solid black;
background-color: #cdff64;
font-weight: 600;
line-height: 100%;
letter-spacing: 4%;
min-width: 30%;
padding: 0.25rem;
text-transform: uppercase;
}
</style>
<script>
(function(self) {
onloadAdd(() => {
const logo = self.querySelector(".logo");
logo.style.setProperty("--logo-bg-color", self.dataset.logoBgColor);
});
})(me());
</script>
<div class="content">
<div class="logo">
<img src="{{ contest.school.logo.url }}"
alt="{{ school.short_name }} {{ school.mascot }} logo" />
</div>
<p class="school">{{ contest.school.name }}</p>
<p class="description">
Check your voter registration status
{% if not contest.is_giveaway %}for a 1 in {{ contest.in_n }} chance{% endif %}
to win a ${{ contest.amount }} Amazon gift card.
</p>
<div class="button-holder">
{% include "components/button.dhtml" with text="Visit event" href=contest.school.relative_url bg_color="black" color="white" %}
</div>
</div>
<div class="box" data-end-at="{{ contest.end_at|date:'c' }}">
<script>
(function(self) {
function countdown(self) {
// compute the deadline
const deadline = new Date(self.dataset.endAt);
const deadlineTime = deadline.getTime();

/** Update the countdown. */
function updateCountdown() {
const now = new Date().getTime();
const diff = deadlineTime - now;

if (diff <= 0) {
clearInterval(interval);
self.innerText = "Just ended!";
return;
}

const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);

const h0digit = Math.floor(hours / 10);
const h1digit = hours % 10;
const m0digit = Math.floor(minutes / 10);
const m1digit = minutes % 10;
const s0digit = Math.floor(seconds / 10);
const s1digit = seconds % 10;

const endsIn = `Ends in ${h0digit}${h1digit}:${m0digit}${m1digit}:${s0digit}${s1digit}`;
self.innerText = endsIn;
}

updateCountdown();
const interval = setInterval(updateCountdown, 1000);
}

onloadAdd(() => countdown(self));
})(me());
</script>
Ends in ...
</div>
</div>
54 changes: 54 additions & 0 deletions server/vb/templates/components/upcoming_contest.dhtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<div data-logo-bg-color="{{ contest.school.logo.bg_color }}">
<style>
me {
border: 3px solid black;
padding: 1rem;
color: black;
font-size: 18px;
font-weight: 440;
font-variation-settings: "wght" 440;
line-height: 1;
}

me .content {
display: flex;
align-items: center;
gap: 1em;
}

me .logo {
--logo-bg-color: transparent;
border-radius: 100%;
border: 2px solid black;
background-color: var(--logo-bg-color);
overflow: hidden;
width: 36px;
height: 36px;
}

me .logo img {
width: 100%;
height: 100%;
object-fit: contain;
}

me p {
margin: 0;
}
</style>
<script>
(function(self) {
onloadAdd(() => {
const logo = self.querySelector(".logo");
logo.style.setProperty("--logo-bg-color", self.dataset.logoBgColor);
});
})(me());
</script>
<div class="content">
<div class="logo">
<img src="{{ contest.school.logo.url }}"
alt="{{ school.short_name }} {{ school.mascot }} logo" />
</div>
<p class="school">{{ contest.school.name }}</p>
</div>
</div>
121 changes: 118 additions & 3 deletions server/vb/templates/home.dhtml
Original file line number Diff line number Diff line change
@@ -1,16 +1,131 @@
{% extends "base.dhtml" %}
{% load static %}

{% block title %}
Voter Bowl
{% endblock title %}

{% block body %}
<style>
body {
background-color: #cdff64;
}
</style>
<div>
<style>
me h1 {
font-weight: 200;
me {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
background-color: #cdff64;
color: black;
}

me main {
width: 100%;
text-align: center;
padding: 2rem 0;
}

me main svg {
width: 104px;
margin: 1.5rem 0;
}

@media screen and (min-width: 768px) {
me main svg {
width: 112px;
}
}

me main p {
font-weight: 378;
font-size: 20px;
line-height: 130%;
}

me main h2 {
font-weight: 500;
font-size: 28px;
line-height: 140%;
}

@media screen and (min-width: 768px) {
me main h2 {
font-size: 32px;
}
}

me .faq {
width: 100%;
color: white;
padding: 2rem 0;
}

me .button-holder {
display: flex;
justify-content: center;
margin: 1.5rem 0;
}

me .faq {
background-color: black;
}

me .ongoing {
display: flex;
flex-direction: column;
justify-content: center;
gap: 2rem;
margin: 2rem 0;
}

me .upcoming {
display: flex;
flex-direction: column;
justify-content: center;
gap: 0.5rem;
margin: 0.5rem 0;
}

me .coming-soon {
text-transform: uppercase;
font-weight: bold;
font-size: 20px;
line-height: 130%;
display: flex;
justify-content: center;
margin: 1.5rem 0;
}
</style>
<h1>Voter Bowl</h1>
<main>
<div class="container">
<div class="center">{% include "voter_bowl_logo.svg" %}</div>
<h2>College students win prizes by checking if they are registered to vote.</h2>
{% if ongoing_contests %}
<div class="ongoing">
{% for contest in ongoing_contests %}
{% include "components/ongoing_contest.dhtml" with contest=contest %}
{% endfor %}
</div>
{% endif %}
{% if upcoming_contests %}
<p class="coming-soon">Coming Soon</p>
<div class="upcoming">
{% for contest in upcoming_contests %}
{% include "components/upcoming_contest.dhtml" with contest=contest %}
{% endfor %}
</div>
{% endif %}
{% if not ongoing_contests and not upcoming_contests %}
<p>There are no contests at this time. Check back later!</p>
{% endif %}
</div>
</main>
<div class="faq">
<div class="container">{% include "includes/faq.dhtml" %}</div>
</div>
{% include "includes/footer.dhtml" %}
</div>
{% endblock body %}
Loading

0 comments on commit 2e7ca7f

Please sign in to comment.