Create a Django website

This commit is contained in:
Michał Gdula 2023-06-18 18:06:01 +00:00
parent 69170f19fb
commit a71584ef98
60 changed files with 1344 additions and 1150 deletions

13
website/Dockerfile Normal file
View file

@ -0,0 +1,13 @@
# syntax=docker/dockerfile:1
FROM alpine:latest
EXPOSE 8000
WORKDIR /website
COPY requirements.txt requirements.txt
COPY ./website ./website
RUN apk update && apk add python3 py3-pip
RUN pip install -r requirements.txt
CMD ["python3", "manage.py", "runserver", ""]

View file

View file

@ -0,0 +1,5 @@
from django.contrib import admin
from articles.models import Article
admin.site.register(Article)

6
website/articles/apps.py Normal file
View file

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

View file

@ -0,0 +1,30 @@
# Generated by Django 4.2.2 on 2023-06-17 12:01
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="Article",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=255)),
("slug", models.SlugField()),
("body", models.TextField()),
("date", models.DateTimeField(auto_now_add=True)),
],
),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 4.2.2 on 2023-06-17 14:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("articles", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="article",
name="thumb",
field=models.ImageField(blank=True, default="default.png", upload_to=""),
),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 4.2.2 on 2023-06-17 14:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("articles", "0002_article_thumb"),
]
operations = [
migrations.AlterField(
model_name="article",
name="thumb",
field=models.ImageField(blank=True, default="default.jpg", upload_to=""),
),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 4.2.2 on 2023-06-18 17:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("articles", "0003_alter_article_thumb"),
]
operations = [
migrations.AddField(
model_name="article",
name="published",
field=models.BooleanField(default=False),
),
]

View file

View file

@ -0,0 +1,13 @@
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
thumb = models.ImageField(default="default.jpg", blank=True)
published = models.BooleanField(default=False)
def __str__(self):
return self.title

View file

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

26
website/articles/urls.py Normal file
View file

@ -0,0 +1,26 @@
"""
URL configuration for website project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/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.urls import path
from articles import views
app_name = "articles"
urlpatterns = [
path("", views.article_list, name="list"),
path("<slug:slug>/", views.article_detail, name="detail"),
]

17
website/articles/views.py Normal file
View file

@ -0,0 +1,17 @@
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from articles.models import Article
def article_list(request):
articles = Article.objects.filter(published=True).order_by("-date").all()
return render(request, "views/articles.html", {"articles": articles})
def article_detail(request, slug):
article = get_object_or_404(Article, slug=slug)
if not article.published:
return HttpResponse("Not found")
return render(request, "views/article.html", {"article": article})

22
website/manage.py Normal file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "website.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View file

@ -0,0 +1,30 @@
let navRotate = 0;
let increment = 45;
function toggleNav() {
let nav = document.querySelector('nav');
let button = document.querySelector('.nav-toggle');
navRotate += increment;
button.style.transform = `rotate(${navRotate}deg)`;
if (nav.classList.contains('open')) {
document.querySelector('body').style.overflow = 'auto';
nav.classList.remove('open');
setTimeout(() => {
nav.style.display = 'none';
}, 100);
button.classList.remove('open');
} else {
document.querySelector('body').style.overflow = 'hidden';
nav.style.display = 'flex';
setTimeout(() => {
nav.classList.add('open');
}, 3);
button.classList.add('open');
}
}

View file

@ -0,0 +1,11 @@
const scroll = document.querySelector('.scroll');
function setScroll() {
let scrollPercentage = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
scroll.style.width = scrollPercentage + '%';
}
if (scroll) {
setScroll();
window.onscroll = () => { setScroll(); };
}

View file

@ -0,0 +1,225 @@
$dark: #261f1b
$light: #f0e7e4
$accent: #f2672c
$radius: 2px
$font: 'DM Serif Display', serif
$font-mono: 'IBM Plex Mono', monospace
@import "styles/navigation"
@import "styles/footer"
@import "styles/markdown"
@import "styles/table"
@import "styles/art-block"
@import "styles/button-array"
*
font-family: $font
box-sizing: border-box
-ms-overflow-style: none // for Internet Explorer, Edge
scrollbar-width: none // for Firefox
&::-webkit-scrollbar
display: none // for Chrome, Safari, and Opera
html
font-size: 1rem
background-color: $light
body
margin: 0
padding: 0
min-height: 100vh
display: flex
flex-direction: column
color: $dark
.back
padding: 0
width: 3rem
height: 3rem
display: flex
justify-content: center
align-items: center
position: fixed
right: 1.3rem
bottom: 1.3rem
border: 0 solid transparent
border-radius: 50%
background: $dark
box-shadow: 0 0 0.35rem rgba(0, 0, 0, 0.4)
cursor: pointer
z-index: 10
svg
display: block
width: 1.4rem
height: 1.4rem
color: $light
&:hover
text-decoration: none
.scroll
width: 0
height: 0.3rem
position: fixed
bottom: 0
left: 0
background: $accent
z-index: 4
header
width: 100%
height: 20rem
position: relative
display: flex
flex-direction: column
justify-content: center
align-items: center
background-color: $dark
color: $light
box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.2)
z-index: 2
overflow: hidden
img
width: 100%
height: 100%
position: absolute
inset: 0
object-fit: cover
h1
margin: 0 0 0.5rem 0
padding: 0 1rem
position: relative
font-size: 4rem
text-align: center
background: inherit
color: inherit
border-radius: $radius
z-index: +1
p
margin: 0
padding: 0.3rem 1rem
position: relative
text-align: center
background: inherit
color: inherit
border-radius: $radius
z-index: +1
@media (max-width: 900px)
header
height: 13rem
h1
font-size: 3rem
main
margin: 0 auto
padding: 1rem 1rem 0 1rem
font-size: 1.1rem
flex-grow: 1
width: 100%
max-width: 900px
height: 100%
img
max-width: 100%
object-fit: cover
border-radius: $radius
h1
margin: 0 0 0.5rem 0
font-size: 2.5rem
color: $accent
a
color: $accent
text-decoration: none
&:hover
text-decoration: underline
.article
margin: 0 0 0.5rem 0
display: flex
justify-content: space-between
align-items: baseline
position: relative
text-decoration: none
background: $light
color: $dark
h2
margin: 0 0.5rem 0.2rem 0
padding-right: 0.75rem
font-size: 1.69rem
white-space: nowrap
text-overflow: ellipsis
background: inherit
color: inherit
overflow: hidden
transition: color 0.1s ease-in-out
z-index: +1
p
margin: 0
padding-left: 0.75rem
font-size: 1rem
white-space: nowrap
background: inherit
color: inherit
transition: color 0.1s ease-in-out
z-index: +1
&::after
content: ""
width: 100%
display: block
position: absolute
top: 50%
left: 0
border-top: 1px $dark dotted
opacity: 0.5
transition: background 0.1s ease-in-out
&:hover
color: $accent
text-decoration: none
@media (max-width: 600px)
.article
h2
font-size: 1.4rem
@media (max-width: 400px)
.article
h2
font-size: 1.1rem

View file

@ -0,0 +1,34 @@
.art-block
height: auto
display: grid
grid-template-columns: repeat(3, 1fr)
gap: 0.5rem
.art
display: flex
flex-direction: column
span
margin-bottom: 0.2rem
width: 100%
height: 100%
position: relative
background: $light
border-radius: $radius
img
max-width: 100%
max-height: 100%
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
@media (max-width: 621px)
.art-block
grid-template-columns: 1fr 1fr
grid-template-rows: 1fr 1fr
@media (max-width: 420px)
.art-block
grid-template-columns: 1fr
grid-template-rows: 1fr

View file

@ -0,0 +1,53 @@
.button-array
display: flex
flex-wrap: wrap
justify-content: start
p
margin: 0 0.2rem 0 0
padding: 0 0.5rem
height: 2rem
display: flex
align-items: center
font-size: 0.9rem
font-family: $font-mono
background: $dark
color: $light
border-radius: $radius
button, a
margin: 0 0.2rem 0.2rem 0
padding: 0
width: 2rem
height: 2rem
display: flex
justify-content: center
align-items: center
font-size: 0.9rem
font-family: $font-mono
text-decoration: none
background-color: $accent
color: $dark
border: 0 solid transparent
border-radius: $radius
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out
svg
width: 1.1rem
height: 1.1rem
color: inherit
&:hover, &:focus-visible
text-decoration: none
background-color: $dark
color: $light
outline: none

View file

@ -0,0 +1,28 @@
footer
width: 100%
height: 5.6rem
display: flex
flex-direction: column
justify-content: center
align-items: center
background-color: $light
color: $dark
p
margin: 0
font-size: 0.9rem
text-align: center
color: inherit
a
margin: 0
font-size: 0.9rem
text-decoration: none
color: $accent
cursor: pointer
&:hover
text-decoration: underline

View file

@ -0,0 +1,47 @@
.markdown
a
text-decoration: none
color: $accent
transition: all 0.1s ease-in-out
&:hover
text-decoration: underline
hr
margin: 1rem 0
border: 0
border-top: 1px solid $dark
code
padding: 0.2rem
font-family: $font-mono
font-size: 0.8rem
background-color: $dark
color: $light
border-radius: $radius
overflow-x: auto
pre
margin: 0
padding: 0.6rem
white-space: pre-wrap
word-wrap: break-word
font-family: $font-mono
background-color: $dark
border-radius: $radius
overflow-x: scroll
> code
padding: 0
blockquote
margin: 1rem 0 1rem 1.5rem
padding: 0 0.6rem
font-style: italic
border-left: 0.2rem solid $accent

View file

@ -0,0 +1,101 @@
nav
padding-bottom: 1rem
position: fixed
right: 0
left: 0
width: 100%
height: calc(100vh + 1rem)
display: none
flex-direction: column
justify-content: center
align-items: center
border-radius: 0
background-color: $dark
color: $light
opacity: 0
transform: translateY(-1rem)
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out
z-index: 9998
a
margin: 0 0 1rem 0
padding: 0.3rem 1rem
position: relative
text-decoration: none
font-weight: bold
font-size: 1.5rem
color: $light
transition: color 0.1s ease-in-out
&::before
content: ""
display: block
position: absolute
bottom: 0
left: 0
width: 100%
height: 0
background-color: $accent
border-radius: $radius
z-index: -1
transition: height 0.1s ease-in-out
&:hover, &:focus-visible
color: $dark
border: 0 solid transparent
outline: 0 solid transparent
&::before
height: 100%
&.open
opacity: 1
transform: translateY(0)
.nav-toggle
margin: 0
padding: 0
position: fixed
left: 1.3rem
bottom: 1.3rem
display: flex
justify-content: center
align-items: center
width: 3rem
height: 3rem
border: 0 solid transparent
border-radius: 50%
background: $dark
color: $light
box-shadow: 0 0 0.35rem rgba(0, 0, 0, 0.4)
transition: all 0.2s ease-in-out
cursor: pointer
z-index: 9999
svg
display: block
width: 1.4rem
height: 1.4rem
color: inherit
&.open
background: $light
color: $dark

View file

@ -0,0 +1,35 @@
.table
width: 100%
border-radius: $radius
overflow: hidden
border: 1px solid $dark
table
border: none
border-collapse: collapse
width: 100%
tr
border: none
border-bottom: 1px solid $dark
&:last-child
border: none
th, td
padding: 0.5rem
text-align: left
vertical-align: top
border-right: 1px solid $dark
&:last-child
border: none
th
background: $dark
color: $light
@media (max-width: 768px)
.table table
th, td
padding: 0.25rem

View file

@ -0,0 +1,34 @@
{% load static %}
{% load compress %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}Leggy Land{% endblock %}</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="{% block description %}Fluffy's mid-ass page{% endblock %}">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=IBM+Plex+Mono&display=swap" rel="stylesheet">
{% compress css %}
<link type="text/x-sass" href="{% static 'sass/styles.sass' %}" rel="stylesheet" media="screen">
{% endcompress %}
</head>
<body>
{% block navigation %}{% include 'navigation.html' %}{% endblock %}
{% block header %}{% endblock %}
<main>{% block content %}{% endblock %}</main>
<footer>{% block footer %}{% include 'footer.html' %}{% endblock %}</footer>
</body>
{% block scripts %}{% endblock %}
{% compress js %}
<script src="{% static 'js/navigation.js' %}" defer></script>
<script src="{% static 'js/scroll.js' %}" defer></script>
{% endcompress %}
</html>

View file

@ -0,0 +1,2 @@
<a href="https://github.com/Fluffy-Bean/Fluffys-website">Website source</a>
<p style="margin-left: 0.5rem">Designed by meeee</p>

View file

@ -0,0 +1,11 @@
<nav>
<a href="{% url 'index' %}">Index</a>
<a href="{% url 'refsheet' %}">Refsheet</a>
<a href="{% url 'articles:list' %}">Articles</a>
</nav>
<button class="nav-toggle" onclick="toggleNav();" aria-label="Open Navigation tab">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"></path>
</svg>
</button>

View file

@ -0,0 +1,23 @@
{% extends 'base.html' %}
{% load markdownify %}
{% block title %}{{ article.title }}{% endblock %}
{% block header %}
<span class="scroll"></span>
<header>
<img src="{{ article.thumb.url }}" alt="{{ article.title }}">
<h1>{{ article.title }}</h1>
<p>{{ article.date }}</p>
</header>
{% endblock %}
{% block content %}
<div class="markdown">{{ article.body|markdownify }}</div>
<a href="{% url 'articles:list' %}" class="back" aria-label="Back to article list">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M232,144a64.07,64.07,0,0,1-64,64H80a8,8,0,0,1,0-16h88a48,48,0,0,0,0-96H51.31l34.35,34.34a8,8,0,0,1-11.32,11.32l-48-48a8,8,0,0,1,0-11.32l48-48A8,8,0,0,1,85.66,45.66L51.31,80H168A64.07,64.07,0,0,1,232,144Z"></path>
</svg>
</a>
{% endblock %}

View file

@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% block content %}
<h1>Articles</h1>
{% for article in articles %}
<a href="{% url 'articles:detail' slug=article.slug %}" class="article">
<h2>{{ article.title }}</h2>
<p>{{ article.date|date:"jS M, Y" }}</p>
</a>
{% endfor %}
{% endblock %}

View file

@ -0,0 +1,82 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h1>Hello, stranger!</h1>
<h2>About Meeeeee</h2>
<p>My name is Fluffy, I'm an 18-year-old nerd, who likes to code and tinker with computers!</p>
<img src="{% static 'images/sneak.png' %}" alt="FluffyBean" style="width:11rem;float:right;" width="178" height="126">
<p>I specialise in Front-End development, but also enjoy working with the back end.
My Favorite framework currently is Flask, but this website runs on Django, lol</p>
<p>My favorite language is Python, but I also know how to use PHP, HTML, CSS/Sass, JavaScript,
Docker, SQL, Shell Scripting, and a little bit of Rust.</p>
<p>I also have experience in a few different systems, mainly Arch, Ubuntu and Proxmox.</p>
<h2>Projects</h2>
<p>I'm currently working on a few projects, including</p>
<div class="table">
<table>
<tr>
<th>Name</th>
<th>Language</th>
<th>Framework</th>
</tr>
<tr>
<td><a href="https://github.com/Derpy-Leggies/OnlyLegs">OnlyLegs</a></td>
<td>Python</td>
<td>Flask</td>
</tr>
<tr>
<td>Lynxie</td>
<td>Rust</td>
<td>Senerity</td>
</tr>
<tr>
<td>TheFrontRooms</td>
<td>C# & Python</td>
<td>Unity & Flask</td>
</tr>
</table>
</div>
<p>And some of my past project include</p>
<div class="table">
<table>
<tr>
<th>Name</th>
<th>Language</th>
<th>Framework</th>
</tr>
<tr>
<td><a href="https://github.com/Fluffy-Bean/image-gallery">OnlyLegs</a></td>
<td>PHP</td>
<td>I hate myself</td>
</tr>
<tr>
<td><a href="https://github.com/Fluffy-Bean/Joe_The_Bot">Joe The Bot</a></td>
<td>Python</td>
<td>discord.py</td>
</tr>
<tr>
<td>Twitter Archive Parser</td>
<td>PHP and Python</td>
<td>Raw Dogging</td>
</tr>
</table>
</div>
<h2>My Socials</h2>
<p>Here are my socials, if you want to stalk me</p>
<div class="button-array">
<a style="width: auto; padding:0.5rem 0.7rem" href="https://twitter.com/fluffybeanUwU">Twitter</a>
<a style="width: auto; padding:0.5rem 0.7rem" href="https://meow.social/@Fluffy_Bean">Mastodon</a>
<a style="width: auto; padding:0.5rem 0.7rem" href="https://t.me/Fluffy_Bean">Telegram</a>
<a style="width: auto; padding:0.5rem 0.7rem" href="https://github.com/Fluffy-Bean">Github</a>
<a style="width: auto; padding:0.5rem 0.7rem" href="https://www.last.fm/user/Fluffy_Bean_">LastFM</a>
</div>
<p style="margin-bottom: 0">Please don't message me with a "hi" or "hello, how are you". Start a meaningful conversation,
chances of me responding will be slim otherwise!</p>
{% endblock %}

View file

@ -0,0 +1,93 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h1>Fluffeeeeee</h1>
<h2>Refsheet</h2>
<img src="{% static 'images/ref.png' %}" alt="FluffyBean">
<div class="button-array">
<p>mrHDash</p>
<a href="https://twitter.com/mrHDash">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M247.39,68.94A8,8,0,0,0,240,64H209.57A48.66,48.66,0,0,0,168.1,40a46.91,46.91,0,0,0-33.75,13.7A47.9,47.9,0,0,0,120,88v6.09C79.74,83.47,46.81,50.72,46.46,50.37a8,8,0,0,0-13.65,4.92c-4.31,47.79,9.57,79.77,22,98.18a110.93,110.93,0,0,0,21.88,24.2c-15.23,17.53-39.21,26.74-39.47,26.84a8,8,0,0,0-3.85,11.93c.75,1.12,3.75,5.05,11.08,8.72C53.51,229.7,65.48,232,80,232c70.67,0,129.72-54.42,135.75-124.44l29.91-29.9A8,8,0,0,0,247.39,68.94Zm-45,29.41a8,8,0,0,0-2.32,5.14C196,166.58,143.28,216,80,216c-10.56,0-18-1.4-23.22-3.08,11.51-6.25,27.56-17,37.88-32.48A8,8,0,0,0,92,169.08c-.47-.27-43.91-26.34-44-96,16,13,45.25,33.17,78.67,38.79A8,8,0,0,0,136,104V88a32,32,0,0,1,9.6-22.92A30.94,30.94,0,0,1,167.9,56c12.66.16,24.49,7.88,29.44,19.21A8,8,0,0,0,204.67,80h16Z"></path>
</svg>
</a>
<a href="https://instagram.com/mrhdash_arts">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M128,80a48,48,0,1,0,48,48A48.05,48.05,0,0,0,128,80Zm0,80a32,32,0,1,1,32-32A32,32,0,0,1,128,160ZM176,24H80A56.06,56.06,0,0,0,24,80v96a56.06,56.06,0,0,0,56,56h96a56.06,56.06,0,0,0,56-56V80A56.06,56.06,0,0,0,176,24Zm40,152a40,40,0,0,1-40,40H80a40,40,0,0,1-40-40V80A40,40,0,0,1,80,40h96a40,40,0,0,1,40,40ZM192,76a12,12,0,1,1-12-12A12,12,0,0,1,192,76Z"></path>
</svg>
</a>
</div>
<h2>Art</h2>
<div class="art-block">
<div class="art">
<span><img src="{% static 'images/sneak.png' %}" alt="FluffyBean"></span>
<div class="button-array">
<p>Shep</p>
<a href="https://twitter.com/ShepGoesBlep">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M247.39,68.94A8,8,0,0,0,240,64H209.57A48.66,48.66,0,0,0,168.1,40a46.91,46.91,0,0,0-33.75,13.7A47.9,47.9,0,0,0,120,88v6.09C79.74,83.47,46.81,50.72,46.46,50.37a8,8,0,0,0-13.65,4.92c-4.31,47.79,9.57,79.77,22,98.18a110.93,110.93,0,0,0,21.88,24.2c-15.23,17.53-39.21,26.74-39.47,26.84a8,8,0,0,0-3.85,11.93c.75,1.12,3.75,5.05,11.08,8.72C53.51,229.7,65.48,232,80,232c70.67,0,129.72-54.42,135.75-124.44l29.91-29.9A8,8,0,0,0,247.39,68.94Zm-45,29.41a8,8,0,0,0-2.32,5.14C196,166.58,143.28,216,80,216c-10.56,0-18-1.4-23.22-3.08,11.51-6.25,27.56-17,37.88-32.48A8,8,0,0,0,92,169.08c-.47-.27-43.91-26.34-44-96,16,13,45.25,33.17,78.67,38.79A8,8,0,0,0,136,104V88a32,32,0,0,1,9.6-22.92A30.94,30.94,0,0,1,167.9,56c12.66.16,24.49,7.88,29.44,19.21A8,8,0,0,0,204.67,80h16Z"></path>
</svg>
</a>
</div>
</div>
<div class="art">
<span><img src="{% static 'images/taidum.png' %}" alt="FluffyBean"></span>
<div class="button-array">
<p>Zadok</p>
</div>
</div>
<div class="art">
<span><img src="{% static 'images/kissing-men.png' %}" alt="FluffyBean"></span>
<div class="button-array">
<p>LordPulex</p>
<a href="https://twitter.com/LordPulex">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M247.39,68.94A8,8,0,0,0,240,64H209.57A48.66,48.66,0,0,0,168.1,40a46.91,46.91,0,0,0-33.75,13.7A47.9,47.9,0,0,0,120,88v6.09C79.74,83.47,46.81,50.72,46.46,50.37a8,8,0,0,0-13.65,4.92c-4.31,47.79,9.57,79.77,22,98.18a110.93,110.93,0,0,0,21.88,24.2c-15.23,17.53-39.21,26.74-39.47,26.84a8,8,0,0,0-3.85,11.93c.75,1.12,3.75,5.05,11.08,8.72C53.51,229.7,65.48,232,80,232c70.67,0,129.72-54.42,135.75-124.44l29.91-29.9A8,8,0,0,0,247.39,68.94Zm-45,29.41a8,8,0,0,0-2.32,5.14C196,166.58,143.28,216,80,216c-10.56,0-18-1.4-23.22-3.08,11.51-6.25,27.56-17,37.88-32.48A8,8,0,0,0,92,169.08c-.47-.27-43.91-26.34-44-96,16,13,45.25,33.17,78.67,38.79A8,8,0,0,0,136,104V88a32,32,0,0,1,9.6-22.92A30.94,30.94,0,0,1,167.9,56c12.66.16,24.49,7.88,29.44,19.21A8,8,0,0,0,204.67,80h16Z"></path>
</svg>
</a>
<a href="https://pulex.carrd.co/">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24ZM101.63,168h52.74C149,186.34,140,202.87,128,215.89,116,202.87,107,186.34,101.63,168ZM98,152a145.72,145.72,0,0,1,0-48h60a145.72,145.72,0,0,1,0,48ZM40,128a87.61,87.61,0,0,1,3.33-24H81.79a161.79,161.79,0,0,0,0,48H43.33A87.61,87.61,0,0,1,40,128ZM154.37,88H101.63C107,69.66,116,53.13,128,40.11,140,53.13,149,69.66,154.37,88Zm19.84,16h38.46a88.15,88.15,0,0,1,0,48H174.21a161.79,161.79,0,0,0,0-48Zm32.16-16H170.94a142.39,142.39,0,0,0-20.26-45A88.37,88.37,0,0,1,206.37,88ZM105.32,43A142.39,142.39,0,0,0,85.06,88H49.63A88.37,88.37,0,0,1,105.32,43ZM49.63,168H85.06a142.39,142.39,0,0,0,20.26,45A88.37,88.37,0,0,1,49.63,168Zm101.05,45a142.39,142.39,0,0,0,20.26-45h35.43A88.37,88.37,0,0,1,150.68,213Z"></path>
</svg>
</a>
</div>
</div>
<div class="art">
<span><img src="{% static 'images/mood.png' %}" alt="FluffyBean"></span>
<div class="button-array">
<p>OggyTheFox</p>
<a href="https://twitter.com/OggyOsbourne">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M247.39,68.94A8,8,0,0,0,240,64H209.57A48.66,48.66,0,0,0,168.1,40a46.91,46.91,0,0,0-33.75,13.7A47.9,47.9,0,0,0,120,88v6.09C79.74,83.47,46.81,50.72,46.46,50.37a8,8,0,0,0-13.65,4.92c-4.31,47.79,9.57,79.77,22,98.18a110.93,110.93,0,0,0,21.88,24.2c-15.23,17.53-39.21,26.74-39.47,26.84a8,8,0,0,0-3.85,11.93c.75,1.12,3.75,5.05,11.08,8.72C53.51,229.7,65.48,232,80,232c70.67,0,129.72-54.42,135.75-124.44l29.91-29.9A8,8,0,0,0,247.39,68.94Zm-45,29.41a8,8,0,0,0-2.32,5.14C196,166.58,143.28,216,80,216c-10.56,0-18-1.4-23.22-3.08,11.51-6.25,27.56-17,37.88-32.48A8,8,0,0,0,92,169.08c-.47-.27-43.91-26.34-44-96,16,13,45.25,33.17,78.67,38.79A8,8,0,0,0,136,104V88a32,32,0,0,1,9.6-22.92A30.94,30.94,0,0,1,167.9,56c12.66.16,24.49,7.88,29.44,19.21A8,8,0,0,0,204.67,80h16Z"></path>
</svg>
</a>
<a href="https://oggy123.eu/">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256">
<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24ZM101.63,168h52.74C149,186.34,140,202.87,128,215.89,116,202.87,107,186.34,101.63,168ZM98,152a145.72,145.72,0,0,1,0-48h60a145.72,145.72,0,0,1,0,48ZM40,128a87.61,87.61,0,0,1,3.33-24H81.79a161.79,161.79,0,0,0,0,48H43.33A87.61,87.61,0,0,1,40,128ZM154.37,88H101.63C107,69.66,116,53.13,128,40.11,140,53.13,149,69.66,154.37,88Zm19.84,16h38.46a88.15,88.15,0,0,1,0,48H174.21a161.79,161.79,0,0,0,0-48Zm32.16-16H170.94a142.39,142.39,0,0,0-20.26-45A88.37,88.37,0,0,1,206.37,88ZM105.32,43A142.39,142.39,0,0,0,85.06,88H49.63A88.37,88.37,0,0,1,105.32,43ZM49.63,168H85.06a142.39,142.39,0,0,0,20.26,45A88.37,88.37,0,0,1,49.63,168Zm101.05,45a142.39,142.39,0,0,0,20.26-45h35.43A88.37,88.37,0,0,1,150.68,213Z"></path>
</svg>
</a>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
const art = document.querySelectorAll('.art');
art.forEach((art) => {
art.style.height = art.clientWidth + 'px';
});
window.onresize = () => {
art.forEach((art) => {
art.style.height = art.clientWidth + 'px';
});
}
</script>
{% endblock %}

View file

16
website/website/asgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
ASGI config for website project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "website.settings")
application = get_asgi_application()

182
website/website/settings.py Normal file
View file

@ -0,0 +1,182 @@
"""Leggy Land is a website for the Leggy Land community.
Django settings for website project.
Generated by 'django-admin startproject' using Django 4.2.2.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
from pathlib import Path
from os.path import join
from os import getenv
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = getenv("DJANGO_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"articles",
"compressor",
"markdownify.apps.MarkdownifyConfig",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "website.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "website.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
# DATABASES = {
# "default": {
# "ENGINE": "django.db.backends.sqlite3",
# "NAME": BASE_DIR / "db.sqlite3",
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': getenv('POSTGRES_DB'),
'USER': getenv('POSTGRES_USER'),
'PASSWORD': getenv('POSTGRES_PASSWORD'),
'HOST': getenv('POSTGRES_HOST'),
'PORT': 5432,
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = "en-gb"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "static/"
STATICFILES_DIRS = (join(BASE_DIR, "static"),)
STATICFILES_FINDERS = [
"compressor.finders.CompressorFinder",
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
]
MEDIA_URL = "media/"
MEDIA_ROOT = join(BASE_DIR, "media")
COMPRESS_ROOT = join(BASE_DIR, "static/")
COMPRESS_PRECOMPILERS = (("text/x-sass", "django_libsass.SassCompiler"),)
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
MARKDOWNIFY = {
"default": {
"WHITELIST_TAGS": [
"a",
"p",
"h2",
"h3",
"h4",
"h5",
"h6",
"strong",
"em",
"ul",
"ol",
"li",
"blockquote",
"img",
"pre",
"code",
"hr",
"br",
"table",
"thead",
"tbody",
"tr",
"th",
"td",
],
},
}

32
website/website/urls.py Normal file
View file

@ -0,0 +1,32 @@
"""
URL configuration for website project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/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.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.conf.urls.static import static
from django.conf import settings
from django.contrib import admin
from django.urls import path, include
from website import views
urlpatterns = [
path("admin/", admin.site.urls),
path("", views.index, name="index"),
path("refsheet/", views.refsheet, name="refsheet"),
path("articles/", include("articles.urls")),
]
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

9
website/website/views.py Normal file
View file

@ -0,0 +1,9 @@
from django.shortcuts import render
def index(request):
return render(request, "views/index.html")
def refsheet(request):
return render(request, "views/refsheet.html")

16
website/website/wsgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
WSGI config for website project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "website.settings")
application = get_wsgi_application()