feat: added hero, links, and research page

This commit is contained in:
Rushil Umaretiya 2022-11-07 03:00:28 -05:00
parent 2d50d32fcb
commit 0750ff5efe
27 changed files with 9773 additions and 47 deletions

View File

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import User
from .models import User, Link
@admin.action(description="Mark as Global Student")
def mark_global_student(modeladmin, request, queryset):
@ -15,4 +15,5 @@ class UserAdmin(admin.ModelAdmin):
actions = [mark_global_student, mark_alumni]
admin.site.register(User, UserAdmin)
admin.site.register(User, UserAdmin)
admin.site.register(Link)

View File

@ -0,0 +1,7 @@
from django import forms
from .models import Link
class LinkForm(forms.ModelForm):
class Meta:
model = Link
fields = ['title', 'source', 'description', 'link']

View File

@ -0,0 +1,46 @@
# Generated by Django 4.1.2 on 2022-11-07 07:24
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("base", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="Link",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
("title", models.CharField(max_length=100)),
(
"source",
models.CharField(
choices=[
("website", "Website"),
("book", "Book"),
("article", "Journal Article"),
("video", "Video"),
("podcast", "Podcast"),
("other", "Other"),
],
default="other",
max_length=20,
),
),
("description", models.TextField(max_length=5000)),
("link", models.CharField(max_length=200)),
(
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]

View File

@ -19,4 +19,25 @@ class User(AbstractUser):
return self.social_auth.get(provider="ion")
def __str__(self):
return f"{self.first_name} {self.last_name}"
return f"{self.first_name} {self.last_name}"
class Link(models.Model):
SOURCE_CHOICES = (
('Website', 'Website'),
('Book', 'Book'),
('Article', 'Journal Article'),
('Video', 'Video'),
('Podcast', 'Podcast'),
('Other', 'Other')
)
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
source = models.CharField(max_length=20, choices=SOURCE_CHOICES, default='website')
description = models.TextField(max_length=5000)
link = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return f"{self.title}"

View File

@ -8,5 +8,9 @@ app_name = "base"
urlpatterns = [
path("", views.index, name="index"),
path("login/", views.login, name="login"),
path("logout/", LogoutView.as_view(), name="logout")
]
path("logout/", LogoutView.as_view(), name="logout"),
path("members/", views.members, name="members"),
path("research/", views.research, name="research"),
path("research/add/", views.add_link, name="add-link"),
path("about/", views.about, name="about")
]

View File

@ -1,5 +1,8 @@
from django.shortcuts import render
from .models import User, Link
from .forms import LinkForm
# Create your views here.
def under_construction(request):
return render(request, "base/under_construction.html")
@ -10,3 +13,31 @@ def index(request):
def login(request):
return render(request, "base/login.html")
def members(request):
context = {
"alumni": [(u, None) for u in User.objects.filter(is_alumni=True).order_by("graduation_year", "last_name", "first_name")],
"students": [(u, None) for u in User.objects.filter(is_global_student=True).order_by("last_name", "first_name")],
}
return render(request, "base/members.html", context=context)
def research(request):
context = {
"links": Link.objects.all()
}
return render(request, "base/research.html", context=context)
def add_link(request):
form = LinkForm(request.POST or None)
if form.is_valid():
form.save()
context = {
"form": form
}
return render(request, "base/add_link.html", context=context)
def about(request):
return render(request, "base/about.html")

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ProjectsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "projects"

View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -0,0 +1,9 @@
/* base.css */
nav {
padding: 16px;
}
main {
padding: 1em;
}

View File

@ -0,0 +1,26 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap');
#hero {
overflow: hidden;
cursor: crosshair;
}
#hero h1 {
font-family: 'Roboto Mono', monospace;
position: absolute;
color: white;
top: 20px;
width: 100%;
text-align: center;
z-index: 100;
display: block;
line-height: .75em;
}
#hero span {
font-size: .5em;
}
.content {
padding: 16px;
}

153
global/static/js/hero.js Normal file
View File

@ -0,0 +1,153 @@
var camera;
var scene;
var renderer;
var mesh;
var mouseX = 0;
var mouseY = 0;
var objScale = 40;
var rotateSpeed = 0.005;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var objUrl = "/static/obj/earth.obj";
// var objUrl = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/66496/low-poly-earth.obj';
init();
animate();
function init() {
//---------------------------------------------------------------
// Create and position camera
//---------------------------------------------------------------
camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
1,
1000
);
camera.position.z = 400;
//---------------------------------------------------------------
// Create the scene
//---------------------------------------------------------------
scene = new THREE.Scene();
//---------------------------------------------------------------
// Create the Load Manager
//---------------------------------------------------------------
var manager = new THREE.LoadingManager();
manager.onProgress = function (item, loaded, total) {
console.log(item, loaded, total);
};
var onProgress = function (xhr) {
if (xhr.lengthComputable) {
var percentComplete = (xhr.loaded / xhr.total) * 100;
console.log(Math.round(percentComplete, 2) + "% downloaded");
}
};
var onError = function (xhr) {};
//---------------------------------------------------------------
// Load the object
//---------------------------------------------------------------
var loader = new THREE.OBJLoader(manager);
var material = new THREE.MeshBasicMaterial({
// wireframe: true,
color: 0x0066b2,
polygonOffset: true,
polygonOffsetFactor: 6, // positive value pushes polygon further away
polygonOffsetUnits: 1,
});
loader.load(
objUrl,
function (object) {
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
var helper = new THREE.WireframeHelper(child);
helper.material.color.set(0xffffff);
helper.material.linewidth = 1;
child.material = material;
scene.add(helper);
}
});
mesh = object;
mesh.scale.x = mesh.scale.y = mesh.scale.z = objScale;
scene.add(mesh);
},
onProgress,
onError
);
//---------------------------------------------------------------
// Controls
//---------------------------------------------------------------
document.addEventListener("mousemove", onDocumentMouseMove, false);
document.addEventListener("touchstart", onDocumentTouchStart, false);
document.addEventListener("touchmove", onDocumentTouchMove, false);
//---------------------------------------------------------------
// Create the Renderer
//---------------------------------------------------------------
renderer = new THREE.WebGLRenderer({ antialias: false });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x0066b2, 1);
document.getElementById("hero").appendChild(renderer.domElement);
//---------------------------------------------------------------
// Listen for the window to resize
//---------------------------------------------------------------
window.addEventListener("resize", onWindowResize, false);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function updateCamera() {
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y += (-mouseY - camera.position.y) * 0.05;
camera.lookAt(scene.position);
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart(event) {
if (event.touches.length > 1) {
event.preventDefault();
mouseX = event.touches[0].pageX - windowHalfX;
mouseY = event.touches[0].pageY - windowHalfY;
}
}
function onDocumentTouchMove(event) {
if (event.touches.length == 1) {
event.preventDefault();
mouseX = event.touches[0].pageX - windowHalfX;
mouseY = event.touches[0].pageY - windowHalfY;
}
}
function animate() {
requestAnimationFrame(animate);
if (mesh) mesh.rotation.y += rotateSpeed;
updateCamera();
renderer.render(scene, camera);
}

9189
global/static/obj/earth.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -16,16 +16,15 @@
</head>
<body>
{% block body %}{% endblock %}
<footer class="bg-light">
<footer class="bg-light">
<ul class="nav justify-content-center border-bottom p-3 m-3">
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Home</a></li>
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Features</a></li>
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Pricing</a></li>
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">FAQs</a></li>
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">About</a></li>
<li class="nav-item"><a href="{% url 'base:index' %}" class="nav-link px-2 text-muted">Home</a></li>
<li class="nav-item"><a href="{% url 'base:members' %}" class="nav-link px-2 text-muted">Members</a></li>
<li class="nav-item"><a href="{% url 'base:research' %}" class="nav-link px-2 text-muted">Research</a></li>
<li class="nav-item"><a href="" class="nav-link px-2 text-muted">Projects</a></li>
<li class="nav-item"><a href="{% url 'base:about' %}" class="nav-link px-2 text-muted">About</a></li>
<li class="nav-item"><a href="{% url 'base:login' %}" class="nav-link px-2 text-muted">Login</a></li>
</ul>
</footer>
<footer>
<div class="row border-bottom pb-3 m-3">
<div class="col">
<h2>Contact us!</h2>

View File

@ -0,0 +1,23 @@
{% extends 'base_with_nav.html' %}
{% block head %}
<style>
.main {
text-align: center;
height: 60vh;
}
.login-box {
position: relative;
top: 7vh;
}
</style>
{% endblock %}
{% block main %}
<div class="main">
<div class="login-box">
<h4>About page coming soon.</h4>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% extends "base_with_nav.html" %}
{% load static %}
{% block main %}
<h1 class="primary"><strong>Add Link</strong></h1>
<br>
<form method="post">
{% csrf_token %}
{% for field in form %}
<h6>{{ field.label }}</h6>
<p>{{ field }}</p>
{% endfor %}
<input class="btn q-btn" type="submit" name="button-save" value="Save">
</form>
{% endblock %}

View File

@ -1,11 +1,59 @@
{% extends 'base.html' %}
{% load static %}
{% block head %}
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap" rel="stylesheet">
<link rel="stylesheet" href="{% static 'css/home.css' %}" />
{% endblock %}
{% block body %}
{% if request.user.is_authenticated %}
<h1>Welcome {{user.username}}!</h1>
{% else %}
<h1>Welcome!</h1>
{% endif %}
<div id="hero">
<h1>global studies<br><span>TJHSST 2022 - 2023</span></h1>
</div>
{% include "nav.html" %}
<div class="content">
<div class="row">
<div class="col-lg-8 col-md-6 col-sm-12">
<p class="mission-text center-text">
Global Studies is a combined AP Government and AP Language section that combines policy and rhetoric to create an environment that generates real changemakers. Every year the students complete a group research project into the world around them and work to solve real-world issues.
</p>
<hr>
<h1 class="primary"><strong>Recently Updated Projects</strong></h1>
{% for project in projects %}
<a href="{% url 'projects:project_detail' project.id %}" class="box card">
<div class="card-body">
<div class="row">
<div class="col-lg-5 col-md-12 text-center title-box">
<p><strong>{{ project.title }}</strong></p>
<p>{{ project.author_string }}</p>
</div>
<div class="col-lg-7 col-md-12">
<p>{{ project.description }}</p>
</div>
</div>
</div>
</a>
{% endfor %}
<br>
</div>
<div class="col-lg-4 col-md-6 col-sm-12">
<div class="twitter">
<a class="twitter-timeline" data-height="1500" href="https://twitter.com/MBourjaily?ref_src=twsrc%5Etfw">
Tweets by Mr. Bourjaily
</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r74/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/66496/OBJLoader.js"></script>
<script type="text/javascript" src="{% static 'js/hero.js' %}"></script>
{% endblock body %}

View File

@ -1,4 +1,4 @@
{% extends 'base.html' %}
{% extends 'base_with_nav.html' %}
{% block head %}
<style>
@ -14,15 +14,14 @@
</style>
{% endblock %}
{% block body %}
<h1>bruh</h1>
<div class="main">
<div class="login-box">
<h4>To access this application, you must <b>log in with your Intranet account.</b></h4>
<form action="{% url 'social:begin' 'ion' %}{% if request.GET.next %}?next={{ request.GET.next|urlencode }}{% endif %}" method="post">
{% csrf_token %}
<input class="q-btn" type="submit" value="Login with Ion">
</form>
</div>
{% block main %}
<div class="main">
<div class="login-box">
<h4>To access this application, you must <b>log in with your Intranet account.</b></h4>
<form action="{% url 'social:begin' 'ion' %}{% if request.GET.next %}?next={{ request.GET.next|urlencode }}{% endif %}" method="post">
{% csrf_token %}
<input class="q-btn" type="submit" value="Login with Ion">
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,72 @@
{% extends "base_with_nav.html" %}
{% load static %}
{% block head %}
<style>
.box {
padding: 15px;
margin: 5px;
border: solid 3px var(--blue);
height: 90% !important;
}
.img {
width: 60%;
}
</style>
{% endblock %}
{% block main %}
<div>
<h1 class="primary"><strong>Current Members</strong></h1>
<div class="row center-text">
{% for student, projects in students %}
<div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-1">
<div class="box card">
<div class="card-body">
<p><strong>
{{ student.first_name }} {{ student.last_name }}{% if student.graduation_year %} ({{ student.graduation_year }}){% endif %}
</strong></p>
{% for project in projects %}
<p><a href="{% url 'projects:project_detail' project.id %}">{{ project }}</a></p>
{% endfor %}
{% if not projects %}
<p>Project coming soon!</p>
{% endif %}
{% if student.college %}<p>{{ student.college }}</p>{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<br><hr><br>
<div>
<h1 class="primary"><strong>Alumni</strong></h1>
<div class="row center-text">
{% for student, projects in alumni %}
<div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-1">
<div class="box card">
<div class="card-body">
{% if student.picture %}
<img class="img" src="{{ student.picture.url }}" />
{% else %}
<img class="img" src="{% static 'img/moose/moose.jpeg' %}" />
{% endif %}
<br><br>
<p><strong>{{ student.first_name }} {{ student.last_name }} ({{ student.graduation_year }})</strong></p>
{% for project in projects %}
<p><a href="{% url 'projects:project_detail' project.id %}">{{ project }}</a></p>
{% endfor %}
{% if not projects %}
<p>Project coming soon!</p>
{% endif %}
{% if student.college %}<p>{{ student.college }}</p>{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends 'base_with_nav.html' %}
{% block head %}
<style>
.main {
text-align: center;
height: 60vh;
}
.login-box {
position: relative;
top: 7vh;
}
</style>
{% endblock %}
{% block main %}
<div>
<h1>Research <a href="{% url 'base:add-link' %}"><button type="button" class="btn btn-primary float-end"><i class="bi bi-plus"></i> Add Link</button></a></h1>
</div>
<div class="cards">
{% for link in links %}
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title">{{ link.title }}</h4>
<h5 class="card-link mb-2 text-muted">{{ link.source }}</h5>
<h6 class="card-link mb-1">Posted by: {{ link.author.first_name }} {{ link.author.last_name }}</h6>
<h6 class="card-link mb-1">{{ link.author.project }}</h6>
<p class="card-text">{{ link.description | truncatechars:1000 }}</p>
</div>
</div>
{% endfor %}
</div>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% load static %}
{% block body %}
{% include "nav.html" %}
<main>
{% block main %}{% endblock %}
</main>
{% endblock %}

29
global/templates/nav.html Normal file
View File

@ -0,0 +1,29 @@
{% load static %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="{% url 'base:index' %}">Global Studies 2022</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="{% url 'base:index' %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'base:members' %}">Members</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'base:research' %}">Research</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Projects</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'base:about' %}">About</a>
</li>
</ul>
</div>
<form class="form-inline" action="{% url 'base:login' %}">
<button class="btn btn-outline-success my-2 my-sm-0">Login</button>
</form>
</nav>

View File

@ -1,23 +1,13 @@
"""global URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
urlpatterns = ([
path('admin/', admin.site.urls),
path('', include('social_django.urls', namespace='social')),
path('', include('global.apps.base.urls'))
]
path('', include('global.apps.base.urls', namespace='base'))
]
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
)