Create a Django website
63
.gitignore
vendored
|
@ -1,16 +1,26 @@
|
|||
# Remove all development files
|
||||
uploads/
|
||||
### PostgreSQL template
|
||||
postgres
|
||||
|
||||
# remove all PyCharm files
|
||||
### Editors template
|
||||
.idea
|
||||
|
||||
# remove all VSCode files
|
||||
.vscode
|
||||
|
||||
# remove all CSS files
|
||||
static/css/style.css
|
||||
static/css/style.css.map
|
||||
### Django template
|
||||
*.log
|
||||
*.pot
|
||||
*.pyc
|
||||
__pycache__/
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
media
|
||||
CACHE
|
||||
|
||||
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
|
||||
# in your Git repository. Update and uncomment the following line accordingly.
|
||||
# <django-project-name>/staticfiles/
|
||||
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
@ -33,7 +43,6 @@ parts/
|
|||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
|
@ -63,6 +72,7 @@ coverage.xml
|
|||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
@ -85,6 +95,7 @@ instance/
|
|||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
|
@ -95,7 +106,9 @@ profile_default/
|
|||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
|
@ -104,7 +117,22 @@ ipython_config.py
|
|||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
|
@ -140,3 +168,16 @@ dmypy.json
|
|||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
|
205
app.py
|
@ -1,205 +0,0 @@
|
|||
from flask import Flask, render_template, request, jsonify
|
||||
from flask_compress import Compress
|
||||
|
||||
import dotenv
|
||||
|
||||
from random import choice
|
||||
import json
|
||||
import requests
|
||||
|
||||
# Getting color palette from album art
|
||||
import colorthief
|
||||
|
||||
LASTFM_API_KEY = dotenv.get_key('./.env', 'LASTFM')
|
||||
|
||||
app = Flask(__name__)
|
||||
Compress(app)
|
||||
|
||||
|
||||
#
|
||||
# ROUTES
|
||||
#
|
||||
@app.route('/')
|
||||
def index():
|
||||
msg = [
|
||||
'Don\'t cry because it\'s over, smile because it happened',
|
||||
'This could go one of two ways...', 'Gwa Gwa',
|
||||
'It\'s a UNIX system! I know this!', '*internal screaming*',
|
||||
'Don\'t forget to drink water!', 'I wish we were better strangers.',
|
||||
'If I were you, I\'d run now', 'SILICA GEL "DO NOT EAT".',
|
||||
'Gods die too.', 'Eat hotchip and lie'
|
||||
]
|
||||
|
||||
return render_template('index.html', msg=choice(msg))
|
||||
|
||||
|
||||
@app.route('/cretura')
|
||||
def cretura():
|
||||
return render_template('cretura.html')
|
||||
|
||||
|
||||
@app.route('/about')
|
||||
def about():
|
||||
"""
|
||||
Returns a dict with all the languages I know and their level of knowledge
|
||||
0 = Absolute beginner
|
||||
1 = Basics
|
||||
2 = Intermediate
|
||||
3 = Advanced
|
||||
4 = Expert
|
||||
5 = Undefeated
|
||||
"""
|
||||
languages = {
|
||||
'Python': {
|
||||
'level': 3,
|
||||
'since': '2020',
|
||||
'color': '#3776AB',
|
||||
},
|
||||
'HTML': {
|
||||
'level': 4,
|
||||
'since': '2021',
|
||||
'color': '#E34F26',
|
||||
},
|
||||
'CSS': {
|
||||
'level': 3,
|
||||
'since': '2021',
|
||||
'color': '#1572B6',
|
||||
},
|
||||
'JavaScript': {
|
||||
'level': 2,
|
||||
'since': '2022',
|
||||
'color': '#F7DF1E',
|
||||
},
|
||||
'Sass/SCSS': {
|
||||
'level': 4,
|
||||
'since': '2022',
|
||||
'color': '#CC6699',
|
||||
},
|
||||
'PHP': {
|
||||
'level': 2,
|
||||
'since': '2022',
|
||||
'color': '#777BB4',
|
||||
},
|
||||
'SQL': {
|
||||
'level': 1,
|
||||
'since': '2022',
|
||||
'color': '#4479A1',
|
||||
},
|
||||
'Scratch': {
|
||||
'level': 5,
|
||||
'since': '2015',
|
||||
'color': '#FFD500',
|
||||
},
|
||||
'Shell': {
|
||||
'level': 2,
|
||||
'since': '2021',
|
||||
'color': '#89E051',
|
||||
},
|
||||
'Rust': {
|
||||
'level': 0,
|
||||
'since': '2023',
|
||||
'color': '#CE422B',
|
||||
},
|
||||
}
|
||||
|
||||
systems = {
|
||||
'Ubuntu': {
|
||||
'level': 2,
|
||||
'since': '2022',
|
||||
'color': '#E95420',
|
||||
},
|
||||
'Arch': {
|
||||
'level': 3,
|
||||
'since': '2021',
|
||||
'color': '#1793D1',
|
||||
},
|
||||
'Proxmox': {
|
||||
'level': 2,
|
||||
'since': '2021',
|
||||
'color': '#E57000',
|
||||
},
|
||||
'Windows': {
|
||||
'level': 1,
|
||||
'since': '2011',
|
||||
'color': '#0078D6',
|
||||
},
|
||||
}
|
||||
return render_template('about.html', languages=languages, systems=systems)
|
||||
|
||||
|
||||
@app.route('/music', methods=['GET', 'POST'])
|
||||
def music():
|
||||
if request.method == 'POST':
|
||||
current_tracks = requests.get(
|
||||
f'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=Fluffy_Bean_&api_key={LASTFM_API_KEY}&limit=5&format=json'
|
||||
)
|
||||
current_tracks = json.loads(current_tracks.text)
|
||||
|
||||
tracks = []
|
||||
|
||||
for track in current_tracks['recenttracks']['track']:
|
||||
# As django is weird with @attr in json data
|
||||
# I make a new dict with a bool for nowPlaying
|
||||
nowPlaying = False
|
||||
if '@attr' in track:
|
||||
nowPlaying = True
|
||||
|
||||
# Yoink color palette from album art
|
||||
color_thief = colorthief.ColorThief(
|
||||
requests.get(track['image'][2]['#text'], stream=True).raw)
|
||||
palette = color_thief.get_palette()
|
||||
|
||||
tmp_track = {
|
||||
'name': track['name'],
|
||||
'artist': track['artist']['#text'],
|
||||
'album': track['album']['#text'],
|
||||
'url': track['url'],
|
||||
'image': track['image'][2]['#text'],
|
||||
'nowPlaying': nowPlaying,
|
||||
'palette': palette[0]
|
||||
}
|
||||
|
||||
tracks.append(tmp_track)
|
||||
|
||||
return jsonify(tracks)
|
||||
|
||||
# GET request
|
||||
return render_template('music.html')
|
||||
|
||||
|
||||
#
|
||||
# ERROR HANDLERS
|
||||
#
|
||||
@app.errorhandler(405)
|
||||
def method_not_allowed(e):
|
||||
error = '405'
|
||||
msg = 'Method sussy wussy'
|
||||
return render_template('error.html', error=error, msg=msg), 404
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
error = '404'
|
||||
msg = 'Could not find what you need!'
|
||||
return render_template('error.html', error=error, msg=msg), 404
|
||||
|
||||
|
||||
@app.errorhandler(403)
|
||||
def forbidden(e):
|
||||
error = '403'
|
||||
msg = 'Go away! This is no place for you!'
|
||||
return render_template('error.html', error=error, msg=msg), 403
|
||||
|
||||
|
||||
@app.errorhandler(410)
|
||||
def gone(e):
|
||||
error = '410'
|
||||
msg = 'The page is no longer available! *sad face*'
|
||||
return render_template('error.html', error=error, msg=msg), 410
|
||||
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_server_error(e):
|
||||
error = '500'
|
||||
msg = 'Server died inside :c'
|
||||
return render_template('error.html', error=error, msg=msg), 500
|
25
docker-compose.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
version: "3.9"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:alpine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
|
||||
website:
|
||||
build: website
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./media:/website/media
|
||||
- ./logs:/data/logs
|
||||
environment:
|
||||
DJANGO_KEY: ${DJANGO_KEY}
|
||||
DB_HOST: db
|
||||
DB_USER: ${POSTGRES_USER}
|
||||
DB_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
DB_NAME: ${POSTGRES_DB}
|
7
requirements.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
Gunicorn
|
||||
psycopg2-binary
|
||||
pillow
|
||||
django
|
||||
django-libsass
|
||||
django-compressor
|
||||
django-markdownify
|
|
@ -1,36 +0,0 @@
|
|||
.btn
|
||||
margin: 0
|
||||
padding: 0.5rem 1rem
|
||||
|
||||
width: auto
|
||||
height: 2.5rem
|
||||
|
||||
position: relative
|
||||
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
|
||||
border: transparent 0 solid
|
||||
border-radius: 2px
|
||||
|
||||
background: $black
|
||||
color: $white !important
|
||||
|
||||
font-size: 1rem
|
||||
font-weight: 500
|
||||
line-height: 1
|
||||
|
||||
text-decoration: none
|
||||
text-align: center
|
||||
text-transform: uppercase
|
||||
|
||||
cursor: pointer
|
||||
transition: all 0.2s ease-in-out
|
||||
|
||||
&:hover
|
||||
background: $white
|
||||
color: $black !important
|
||||
|
||||
&:focus
|
||||
outline: none
|
|
@ -1,430 +0,0 @@
|
|||
@use 'sass:map'
|
||||
|
||||
$black: #101010
|
||||
$dark: #151515
|
||||
$grey: #808080
|
||||
$white: #e8e3e3
|
||||
$primary: #8C977D
|
||||
|
||||
@font-face
|
||||
font-family: 'jetbrains_monoitalic'
|
||||
src: url('../fonts/jetbrainsmono-italic-variablefont_wght-webfont.woff2') format('woff2'), url('../fonts/jetbrainsmono-italic-variablefont_wght-webfont.woff') format('woff')
|
||||
font-weight: normal
|
||||
font-style: normal
|
||||
font-display: swap
|
||||
@font-face
|
||||
font-family: 'jetbrains_monoregular'
|
||||
src: url('../fonts/jetbrainsmono-variablefont_wght-webfont.woff2') format('woff2'), url('../fonts/jetbrainsmono-variablefont_wght-webfont.woff') format('woff')
|
||||
font-weight: normal
|
||||
font-style: normal
|
||||
font-display: swap
|
||||
|
||||
html
|
||||
margin: 0
|
||||
padding: 0
|
||||
body
|
||||
margin: 0
|
||||
padding: 3rem 1rem 1rem
|
||||
width: 100vw
|
||||
min-height: 100vh
|
||||
|
||||
background-color: $black
|
||||
|
||||
font-family: 'jetbrains_monoregular', sans-serif
|
||||
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
|
||||
overflow-x: hidden
|
||||
box-sizing: border-box
|
||||
|
||||
*
|
||||
box-sizing: border-box
|
||||
|
||||
nav
|
||||
margin: 0
|
||||
padding: 0.5rem 1rem
|
||||
|
||||
width: 100vw
|
||||
height: 3rem
|
||||
|
||||
position: fixed
|
||||
top: 0
|
||||
left: 0
|
||||
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
gap: 1rem
|
||||
|
||||
z-index: 1
|
||||
|
||||
color: $white
|
||||
|
||||
a
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
width: auto
|
||||
height: 2rem
|
||||
|
||||
position: relative
|
||||
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
|
||||
font-size: 1.1rem
|
||||
font-weight: 400
|
||||
line-height: 1
|
||||
|
||||
text-align: left
|
||||
text-decoration: none
|
||||
text-transform: uppercase
|
||||
|
||||
color: $grey
|
||||
|
||||
&:hover
|
||||
color: $white
|
||||
|
||||
a.selected
|
||||
color: $primary
|
||||
|
||||
&:hover
|
||||
color: $white
|
||||
|
||||
span
|
||||
margin: 0 0 0.2rem 0
|
||||
padding: 0
|
||||
|
||||
width: 2px
|
||||
height: 1.25rem
|
||||
|
||||
position: relative
|
||||
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
|
||||
background-color: $grey
|
||||
|
||||
.wrapper
|
||||
margin: 0 auto
|
||||
padding: 1rem
|
||||
|
||||
width: 100%
|
||||
max-width: 621px
|
||||
|
||||
min-height: auto
|
||||
|
||||
position: relative
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 1rem
|
||||
|
||||
background: $dark
|
||||
color: $white
|
||||
border-radius: 2px
|
||||
|
||||
z-index: 2
|
||||
box-sizing: border-box
|
||||
//overflow: hidden
|
||||
|
||||
h1
|
||||
margin: 0 // 0 1rem 0
|
||||
padding: 0
|
||||
|
||||
font-size: 2.25rem
|
||||
font-weight: 600
|
||||
line-height: 1
|
||||
|
||||
text-align: left
|
||||
text-transform: uppercase
|
||||
white-space: break-spaces
|
||||
|
||||
h2
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
font-size: 1.5rem
|
||||
font-weight: 600
|
||||
line-height: 1
|
||||
|
||||
text-align: left
|
||||
text-transform: uppercase
|
||||
|
||||
h3
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
font-size: 1.25rem
|
||||
font-weight: 600
|
||||
line-height: 1
|
||||
|
||||
text-align: left
|
||||
text-transform: uppercase
|
||||
|
||||
p
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
font-size: 1.1rem
|
||||
font-weight: 400
|
||||
line-height: 1.2
|
||||
|
||||
text-align: left
|
||||
|
||||
color: $grey
|
||||
|
||||
a
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
font-size: 1.1rem
|
||||
font-weight: 400
|
||||
line-height: 1.2
|
||||
|
||||
text-align: left
|
||||
|
||||
color: $primary
|
||||
|
||||
&:hover
|
||||
color: $white
|
||||
|
||||
img
|
||||
margin: 0 auto
|
||||
padding: 0
|
||||
|
||||
width: auto
|
||||
max-width: 100%
|
||||
|
||||
position: relative
|
||||
|
||||
display: block
|
||||
|
||||
border-radius: 2px
|
||||
|
||||
object-fit: cover
|
||||
|
||||
z-index: 1
|
||||
|
||||
p.subtitle
|
||||
color: $white
|
||||
text-transform: uppercase
|
||||
|
||||
.content
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: space-between
|
||||
gap: 0.5rem
|
||||
|
||||
//overflow: hidden
|
||||
|
||||
.bar-chart
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
position: relative
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 0.5rem
|
||||
|
||||
.marker
|
||||
width: 2px
|
||||
height: 100%
|
||||
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
|
||||
background-color: rgba($white, 0.1)
|
||||
|
||||
z-index: -2
|
||||
|
||||
.sub_experiance
|
||||
width: 0%
|
||||
height: 1.69rem
|
||||
|
||||
position: relative
|
||||
|
||||
background-color: $primary
|
||||
border-radius: 2px
|
||||
|
||||
transition: width 2s cubic-bezier(.86,0,.07,1)
|
||||
|
||||
.fg
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
position: absolute
|
||||
|
||||
overflow: hidden
|
||||
|
||||
span
|
||||
position: absolute
|
||||
top: 50%
|
||||
left: 1.5rem
|
||||
transform: translateY(-50%)
|
||||
|
||||
font-size: 0.9rem
|
||||
font-weight: 600
|
||||
white-space: nowrap
|
||||
|
||||
color: $black
|
||||
|
||||
.bg
|
||||
position: absolute
|
||||
top: 50%
|
||||
left: 1.5rem
|
||||
transform: translateY(-50%)
|
||||
|
||||
font-size: 0.9rem
|
||||
font-weight: 600
|
||||
white-space: nowrap
|
||||
|
||||
color: $white
|
||||
|
||||
z-index: -1
|
||||
|
||||
@keyframes loader
|
||||
0%
|
||||
width: 0
|
||||
left: 0
|
||||
30%
|
||||
width: 100%
|
||||
left: 0
|
||||
60%
|
||||
width: 100%
|
||||
left: 100%
|
||||
100%
|
||||
width: 100%
|
||||
left: 100%
|
||||
|
||||
.loader
|
||||
margin: 1rem 0
|
||||
|
||||
width: 100%
|
||||
height: 2px
|
||||
|
||||
position: relative
|
||||
|
||||
background-color: $black
|
||||
|
||||
overflow: hidden
|
||||
|
||||
&::after
|
||||
content: ''
|
||||
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
width: 0
|
||||
height: 100%
|
||||
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
|
||||
background-color: $primary
|
||||
|
||||
animation: loader 1s ease-in-out infinite
|
||||
|
||||
.music
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 1rem
|
||||
|
||||
.track
|
||||
display: flex
|
||||
flex-direction: row
|
||||
gap: 1rem
|
||||
|
||||
position: relative
|
||||
|
||||
overflow: hidden
|
||||
|
||||
.track-image
|
||||
padding: 0px
|
||||
|
||||
// Its too late for me to be bothered to fix a bug I have
|
||||
min-width: 5rem
|
||||
width: 5rem
|
||||
max-width: 5rem
|
||||
min-height: 5rem
|
||||
height: 5rem
|
||||
max-height: 5rem
|
||||
|
||||
border-radius: 2px
|
||||
background-color: $black
|
||||
|
||||
transition: all 0.3s cubic-bezier(.86,0,.07,1)
|
||||
|
||||
img
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
width: 100%
|
||||
height: 100%
|
||||
|
||||
display: block
|
||||
float: left
|
||||
|
||||
border-radius: 2px
|
||||
background-color: $dark
|
||||
|
||||
opacity: 1
|
||||
object-fit: cover
|
||||
|
||||
transition: all 0.2s cubic-bezier(.86,0,.07,1)
|
||||
|
||||
.track-info
|
||||
display: flex
|
||||
flex-direction: column
|
||||
//justify-content: space-between
|
||||
gap: 0.5rem
|
||||
|
||||
overflow: hidden
|
||||
|
||||
a
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
font-size: 1.1rem
|
||||
font-weight: 600
|
||||
line-height: 1.2
|
||||
|
||||
text-align: left
|
||||
text-decoration: none
|
||||
|
||||
color: $white
|
||||
|
||||
&:hover
|
||||
color: $primary
|
||||
|
||||
p.track-nowplaying
|
||||
color: $primary
|
||||
|
||||
@import "buttons"
|
||||
@import "toast"
|
||||
|
||||
@media (max-width: 669px)
|
||||
.wrapper
|
||||
max-width: 100%
|
||||
border-radius: 0
|
||||
|
||||
h1
|
||||
font-size: 2rem
|
||||
text-align: center
|
||||
|
||||
p.subtitle
|
||||
text-align: center
|
||||
|
||||
.track-image
|
||||
width: 2px
|
||||
height: auto
|
||||
|
||||
img
|
||||
opacity: 0
|
|
@ -1,89 +0,0 @@
|
|||
@keyframes toastTimeout
|
||||
0%
|
||||
left: -100%
|
||||
100%
|
||||
left: 0%
|
||||
|
||||
.toast-container
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
width: 100%
|
||||
height: auto
|
||||
max-width: 400px
|
||||
|
||||
position: fixed
|
||||
bottom: 0.5rem
|
||||
left: 50%
|
||||
transform: translateX(-50%)
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 0.5rem
|
||||
|
||||
font-size: 1rem
|
||||
font-weight: 500
|
||||
line-height: 1
|
||||
text-align: center
|
||||
|
||||
z-index: 9999
|
||||
|
||||
.toast
|
||||
margin: 0
|
||||
padding: 0.5rem 1rem
|
||||
|
||||
min-height: 2.5rem
|
||||
|
||||
position: relative
|
||||
|
||||
display: flex
|
||||
justify-content: center
|
||||
align-items: center
|
||||
|
||||
transform: scaleY(0)
|
||||
|
||||
color: $white
|
||||
background-color: $dark
|
||||
border-radius: 2px
|
||||
|
||||
opacity: 0
|
||||
|
||||
transition: all 0.3s ease-in-out
|
||||
overflow: hidden
|
||||
|
||||
&:hover
|
||||
cursor: pointer
|
||||
|
||||
.toast-show
|
||||
opacity: 1
|
||||
transform: scaleY(1)
|
||||
|
||||
.toast-hide
|
||||
opacity: 0
|
||||
tansform: translateY(5rem)
|
||||
|
||||
.toast-time
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
width: 100%
|
||||
height: 2px
|
||||
|
||||
position: absolute
|
||||
bottom: 0
|
||||
left: 0%
|
||||
|
||||
background-color: $primary
|
||||
|
||||
animation: toastTimeout 5s linear forwards
|
||||
|
||||
@media (max-width: 669px)
|
||||
.toast-container
|
||||
padding: 0.5rem
|
||||
|
||||
width: 100%
|
||||
max-width: 100%
|
||||
|
||||
bottom: 0
|
||||
left: 0
|
||||
transform: none
|
Before Width: | Height: | Size: 2.4 MiB |
|
@ -1,87 +0,0 @@
|
|||
function addToast(text='Sample toast notification') {
|
||||
var container = document.querySelector('.toast-container');
|
||||
|
||||
// Create notification element
|
||||
var parent = document.createElement('span');
|
||||
parent.classList.add('toast');
|
||||
parent.innerText = text;
|
||||
parent.onclick = function() {
|
||||
if (parent.parentNode) {
|
||||
parent.classList.add('toast-hide');
|
||||
|
||||
setTimeout(function() {
|
||||
container.removeChild(parent);
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
// Create span to show time remaining
|
||||
var timer = document.createElement('span');
|
||||
timer.classList.add('toast-time');
|
||||
parent.appendChild(timer);
|
||||
|
||||
// Append notification to container
|
||||
container.appendChild(parent);
|
||||
setTimeout(function() {
|
||||
parent.classList.add('toast-show');
|
||||
}, 1);
|
||||
|
||||
// Remove notification after 5 seconds
|
||||
setTimeout(function() {
|
||||
if (parent.parentNode) {
|
||||
parent.classList.add('toast-hide');
|
||||
|
||||
setTimeout(function() {
|
||||
container.removeChild(parent);
|
||||
}, 500);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function garble(obj, speed=1) {
|
||||
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_-"
|
||||
|
||||
let interval = null;
|
||||
let iteration = 0;
|
||||
|
||||
clearInterval(interval);
|
||||
|
||||
interval = setInterval(() => {
|
||||
obj.innerText = obj.innerText
|
||||
.split("")
|
||||
.map((letter, index) => {
|
||||
if (index < iteration) {
|
||||
return obj.dataset.value[index];
|
||||
}
|
||||
// 27 as hyphens wrap text that can make page jump a lot
|
||||
return letters[Math.floor(Math.random() * 27)]
|
||||
})
|
||||
.join("");
|
||||
|
||||
if(iteration >= obj.dataset.value.length){
|
||||
clearInterval(interval);
|
||||
}
|
||||
|
||||
iteration += 1 / speed;
|
||||
}, 30);
|
||||
}
|
||||
|
||||
|
||||
// Main title and subtitle, should only be one of each per page
|
||||
if (document.querySelector("h1")) {
|
||||
const title = document.querySelector("h1");
|
||||
garble(title, 1.5);
|
||||
}
|
||||
if (document.querySelector(".subtitle")) {
|
||||
const subtitle = document.querySelector(".subtitle");
|
||||
garble(subtitle);
|
||||
}
|
||||
|
||||
|
||||
// h2 and h3 headers on page, there can be multiple so we need to loop through them
|
||||
if (document.querySelectorAll("h2, h3")) {
|
||||
const headers = document.querySelectorAll("h2, h3");
|
||||
headers.forEach((header) => {
|
||||
garble(header);
|
||||
});
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block nav_about %}selected{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="content">
|
||||
<h1 data-value="About-Me">About-Me</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 data-value="Meeeeeee">Meeeeeee</h2>
|
||||
<p>Hewwo, I'm a 17 year old nerd, who likes to code and tinker with computers!</p>
|
||||
<p>I'm mostly a frontend developer, with some knowlage of the backend. I also enjoy programming for the hell of it</p>
|
||||
<p>Fluffy Bean is a maned wolf, he reflects my personality and is my fursona</p>
|
||||
<p>Refsheet made by mrHDash</p>
|
||||
</div>
|
||||
|
||||
<img src="{{ url_for('static', filename='images/ref.png') }}" alt="Orange maned wolf sneaking under a yellow sheet">
|
||||
|
||||
<div class="content">
|
||||
<h2 data-value="Experiance and Projects">Experiance and Projects</h2>
|
||||
<p>I'm quite well experianced with Python, HTML, CSS/Sass, and Shell Scripting.And have some experiance with JavaScript, PHP, MySQL and a few other languages</p>
|
||||
<p>My main operating system has been Linux for about 1.5 years (Arch btw)</p>
|
||||
<p>Now I have started to learn hardware and been messing around with Pi Picos!</p>
|
||||
<p>Recently I have started working on a gallery, originally written in PHP for my own use before making it public</p>
|
||||
<p>It is now written in Python with Flask and is open source! You can find it on <a href="https://github.com/Fluffy-Bean/onlylegs">GitHub</a>. Or on my self hosted instance of <a href="https://git.leggy.dev/Fluffy/onlylegs">Gitea</a>!</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2 data-value="Level of knowlage">Level of knowlage</h2>
|
||||
<p>My levels of knowlage are based on a scale of 0-5, with 0 being very little experiance and 5 being best in the world, obviously ;3</p>
|
||||
|
||||
<span class="bar-chart">
|
||||
<h3 data-value="Languages">Languages</h3>
|
||||
{% for lang in languages %}
|
||||
<span class="sub_experiance"
|
||||
data-value="{{ languages[lang].level }}"
|
||||
style="background-color: {{ languages[lang].color }};">
|
||||
<span class="fg"><span>{{ lang }} - Since {{ languages[lang].since }}</span></span>
|
||||
<span class="bg">{{ lang }} - Since {{ languages[lang].since }}</span>
|
||||
</span>
|
||||
{% endfor %}
|
||||
|
||||
<h3 data-value="OS'">OS'</h3>
|
||||
{% for os in systems %}
|
||||
<span class="sub_experiance"
|
||||
data-value="{{ systems[os].level }}"
|
||||
style="background-color: {{ systems[os].color }};">
|
||||
<span class="fg"><span>{{ os }} - Since {{ systems[os].since }}</span></span>
|
||||
<span class="bg">{{ os }} - Since {{ systems[os].since }}</span>
|
||||
</span>
|
||||
{% endfor %}
|
||||
|
||||
<span class="marker" data-value="0"></span>
|
||||
<span class="marker" data-value="1"></span>
|
||||
<span class="marker" data-value="2"></span>
|
||||
<span class="marker" data-value="3"></span>
|
||||
<span class="marker" data-value="4"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var bars = document.querySelectorAll(".sub_experiance");
|
||||
|
||||
bars.forEach(bar => {
|
||||
var value = bar.getAttribute("data-value");
|
||||
|
||||
// 0 - 5
|
||||
if (value == 0) {
|
||||
bar.style.width = "20%";
|
||||
} else if (value == 1) {
|
||||
bar.style.width = "40%";
|
||||
} else if (value == 2) {
|
||||
bar.style.width = "60%";
|
||||
} else if (value == 3) {
|
||||
bar.style.width = "80%";
|
||||
} else if (value == 4) {
|
||||
bar.style.width = "100%";
|
||||
} else if (value == 5) {
|
||||
bar.style.width = "621%";
|
||||
}
|
||||
});
|
||||
|
||||
var markers = document.querySelectorAll(".marker");
|
||||
|
||||
markers.forEach(bar => {
|
||||
var value = bar.getAttribute("data-value");
|
||||
|
||||
// 0 - 5
|
||||
if (value == 0) {
|
||||
bar.style.left = "20%";
|
||||
} else if (value == 1) {
|
||||
bar.style.left = "40%";
|
||||
} else if (value == 2) {
|
||||
bar.style.left = "60%";
|
||||
} else if (value == 3) {
|
||||
bar.style.left = "80%";
|
||||
} else if (value == 4) {
|
||||
bar.style.left = "100%";
|
||||
} else if (value == 5) {
|
||||
bar.style.left = "621%";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,23 +0,0 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block nav_cretura %}selected{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 data-value="Cretura">Cretura</h1>
|
||||
<p class="subtitle" data-value="Thanks to these critters!">Thanks to these critters!</p>
|
||||
|
||||
<div class="content" id="about">
|
||||
<p>Jeetix: Helping me with learning how to make websites!</p>
|
||||
<p>Carty: Teaching me how to run servers and the networking!</p>
|
||||
<p>mrHDash: For the Ref Sheet, also my smelly brother</p>
|
||||
<p>Zadok: Silly taidum art on the icon of this page!</p>
|
||||
<!--
|
||||
<p>
|
||||
Shep: Provided free YCH,
|
||||
<a href="https://twitter.com/ShepGoesBlep/status/1563946805062148102?s=20&t=0wVGqoYa74AsjSSnkZbzjA">you can find it here</a>
|
||||
</p>
|
||||
<img src="{{ url_for('static', filename='images/sneak.png') }}" alt="Orange maned wolf sneaking under a yellow sheet" height="200px" style="opacity:0" onload="fadeOnLoad(this)">
|
||||
-->
|
||||
</div>
|
||||
|
||||
<img src="{{url_for('static', filename='images/ny.png')}}">
|
||||
{% endblock %}
|
|
@ -1,7 +0,0 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block content %}
|
||||
<div class="content">
|
||||
<h1 data-value="{{error}}">{{error}}</h1>
|
||||
<p class="subtitle" data-value="{{msg}}">{{msg}}</p>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,28 +0,0 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block nav_home %}selected{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="content">
|
||||
<h1 data-value="Social-Media">Social-Media</h1>
|
||||
<p class="subtitle" data-value="{{msg}}">{{msg}}</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<a href="https://twitter.com/fluffybeanUwU" class="btn" data-value="Twitter">Twitter</a>
|
||||
<a href="https://meow.social/@Fluffy_Bean" class="btn" data-value="Mastodon">Mastodon</a>
|
||||
<a href="https://t.me/Fluffy_Bean" class="btn" data-value="Telegram">Telegram</a>
|
||||
<a href="https://github.com/Fluffy-Bean" class="btn" data-value="Github">Github</a>
|
||||
<button class="btn" data-value="Discord" id="discord">Discord</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById("discord").onclick = function() {
|
||||
try {
|
||||
navigator.clipboard.writeText("Fluffy Bean#5212");
|
||||
addToast("Copied to clipboard");
|
||||
} catch (err) {
|
||||
addToast("Error copying to clipboard, are you on HTTP?");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,27 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Leggy land</title>
|
||||
<meta name="description" content="Fluffy Bean's amazing website">
|
||||
<link rel="icon" href="{{url_for('static', filename='images/taidum.png')}}">
|
||||
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a class="{% block nav_home %}{% endblock %}" href="/">Home</a>
|
||||
<a class="{% block nav_about %}{% endblock %}" href="/about">About</a>
|
||||
<a class="{% block nav_cretura %}{% endblock %}" href="/cretura">Cretura</a>
|
||||
<span class="spacer"></span>
|
||||
<a class="{% block nav_music %}{% endblock %}" href="/music">Music</a>
|
||||
</nav>
|
||||
|
||||
<div class="wrapper">
|
||||
{% block content %} {% endblock %}
|
||||
</div>
|
||||
|
||||
<div class="toast-container"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,103 +0,0 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% block nav_music %}selected{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 data-value="Muuuuuuusic">Muuuuuuusic</h1>
|
||||
|
||||
<div class="music">
|
||||
<span class="loader"></span>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<p>Provided by <a href="http://www.last.fm">Last.fm</a></p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function processMusic(data) {
|
||||
const music = document.querySelector('.music');
|
||||
music.innerHTML = '';
|
||||
|
||||
data = JSON.parse(data);
|
||||
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
// Create track container
|
||||
const track = document.createElement('div');
|
||||
track.classList.add('track');
|
||||
|
||||
// Create track image container
|
||||
const trackImage = document.createElement('span');
|
||||
trackImage.classList.add('track-image');
|
||||
// UUUUUUUUUGHHHHHHHHHH
|
||||
trackImage.style.backgroundColor = `rgb(${value.palette[0]}, ${value.palette[1]}, ${value.palette[2]})`;
|
||||
// Create track image
|
||||
const trackImageImg = document.createElement('img');
|
||||
trackImageImg.src = value.image;
|
||||
trackImage.appendChild(trackImageImg);
|
||||
|
||||
|
||||
// Create track info container
|
||||
const trackInfo = document.createElement('div');
|
||||
trackInfo.classList.add('track-info');
|
||||
|
||||
// Create track title
|
||||
const trackTitle = document.createElement('a');
|
||||
trackTitle.href = value.url;
|
||||
trackTitle.innerHTML = value.name;
|
||||
|
||||
// Create track artist
|
||||
const trackArtist = document.createElement('p');
|
||||
trackArtist.innerHTML = 'by ' + value.artist;
|
||||
|
||||
// If track is now playing, add now playing text
|
||||
// Else add album name
|
||||
if (value.nowPlaying) {
|
||||
const trackNowPlaying = document.createElement('p');
|
||||
trackNowPlaying.classList.add('track-nowplaying');
|
||||
trackNowPlaying.innerHTML = 'Now Playing:';
|
||||
|
||||
// Append now playing and track info to track info
|
||||
trackInfo.appendChild(trackNowPlaying);
|
||||
trackInfo.appendChild(trackTitle);
|
||||
trackInfo.appendChild(trackArtist);
|
||||
} else {
|
||||
const trackAlbum = document.createElement('p');
|
||||
trackAlbum.innerHTML = 'on ' + value.album;
|
||||
|
||||
// Append track title, artist and album to track info
|
||||
trackInfo.appendChild(trackTitle);
|
||||
trackInfo.appendChild(trackArtist);
|
||||
trackInfo.appendChild(trackAlbum);
|
||||
}
|
||||
|
||||
// Append track image and track info to track
|
||||
track.appendChild(trackImage);
|
||||
track.appendChild(trackInfo);
|
||||
|
||||
// Append track to music
|
||||
music.appendChild(track);
|
||||
});
|
||||
}
|
||||
|
||||
// Make POST request with XHR
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/music', true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(JSON.stringify({}));
|
||||
|
||||
// Handle response
|
||||
xhr.onloadend = function () {
|
||||
if (xhr.readyState == XMLHttpRequest.DONE) {
|
||||
// check if no error occurred
|
||||
if (xhr.status == 200) {
|
||||
processMusic(xhr.responseText);
|
||||
} else {
|
||||
const music = document.querySelector('.music');
|
||||
music.innerHTML = '<p>Music data could not be loaded :<</p>';
|
||||
}
|
||||
} else {
|
||||
const music = document.querySelector('.music');
|
||||
music.innerHTML = '<p>Music data could not be loaded :<</p>';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
13
website/Dockerfile
Normal 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", ""]
|
0
website/articles/__init__.py
Normal file
5
website/articles/admin.py
Normal 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
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ArticlesConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "articles"
|
30
website/articles/migrations/0001_initial.py
Normal 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)),
|
||||
],
|
||||
),
|
||||
]
|
17
website/articles/migrations/0002_article_thumb.py
Normal 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=""),
|
||||
),
|
||||
]
|
17
website/articles/migrations/0003_alter_article_thumb.py
Normal 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=""),
|
||||
),
|
||||
]
|
17
website/articles/migrations/0004_article_published.py
Normal 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),
|
||||
),
|
||||
]
|
0
website/articles/migrations/__init__.py
Normal file
13
website/articles/models.py
Normal 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
|
3
website/articles/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
26
website/articles/urls.py
Normal 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
|
@ -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
|
@ -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()
|
BIN
website/static/images/kissing-men.png
Normal file
After Width: | Height: | Size: 256 KiB |
BIN
website/static/images/mood.png
Normal file
After Width: | Height: | Size: 602 KiB |
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
30
website/static/js/navigation.js
Normal 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');
|
||||
}
|
||||
}
|
11
website/static/js/scroll.js
Normal 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(); };
|
||||
}
|
225
website/static/sass/styles.sass
Normal 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
|
34
website/static/sass/styles/art-block.sass
Normal 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
|
53
website/static/sass/styles/button-array.sass
Normal 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
|
28
website/static/sass/styles/footer.sass
Normal 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
|
47
website/static/sass/styles/markdown.sass
Normal 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
|
101
website/static/sass/styles/navigation.sass
Normal 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
|
35
website/static/sass/styles/table.sass
Normal 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
|
34
website/templates/base.html
Normal 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>
|
2
website/templates/footer.html
Normal 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>
|
11
website/templates/navigation.html
Normal 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>
|
23
website/templates/views/article.html
Normal 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 %}
|
10
website/templates/views/articles.html
Normal 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 %}
|
82
website/templates/views/index.html
Normal 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 %}
|
93
website/templates/views/refsheet.html
Normal 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 %}
|
0
website/website/__init__.py
Normal file
16
website/website/asgi.py
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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()
|