Merge pull request 'django' (#1) from django into master
Reviewed-on: #1
207
.gitignore
vendored
Normal file
|
@ -0,0 +1,207 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[codz]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# 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.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# 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
|
||||
#poetry.toml
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||
#pdm.lock
|
||||
#pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# pixi
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||
#pixi.lock
|
||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||
.pixi
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.envrc
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
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/
|
||||
|
||||
# Abstra
|
||||
# Abstra is an AI-powered process automation framework.
|
||||
# Ignore directories containing user credentials, local state, and settings.
|
||||
# Learn more at https://abstra.io/docs
|
||||
.abstra/
|
||||
|
||||
# Visual Studio Code
|
||||
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||
# you could uncomment the following to ignore the entire vscode folder
|
||||
# .vscode/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Cursor
|
||||
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
||||
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
||||
# refer to https://docs.cursor.com/context/ignore-files
|
||||
.cursorignore
|
||||
.cursorindexingignore
|
||||
|
||||
# Marimo
|
||||
marimo/_static/
|
||||
marimo/_lsp/
|
||||
__marimo__/
|
BIN
db.sqlite3
Normal file
22
manage.py
Executable 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', 'shrinkinminkin.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()
|
137
requirements.txt
Normal file
|
@ -0,0 +1,137 @@
|
|||
appdirs==1.4.4
|
||||
argcomplete==3.1.4
|
||||
attrs==23.2.0
|
||||
beautifulsoup4==4.12.3
|
||||
blinker==1.7.0
|
||||
bottle==0.12.25
|
||||
Brlapi==0.8.5
|
||||
Brotli==1.1.0
|
||||
certifi==2023.11.17
|
||||
chardet==5.2.0
|
||||
click==8.1.6
|
||||
colorama==0.4.6
|
||||
command-not-found==0.3
|
||||
configobj==5.0.8
|
||||
contourpy==1.0.7
|
||||
cryptography==41.0.7
|
||||
cupshelpers==1.0
|
||||
cycler==0.11.0
|
||||
dbus-python==1.3.2
|
||||
decorator==5.1.1
|
||||
defer==1.0.6
|
||||
defusedxml==0.7.1
|
||||
deprecation==2.0.7
|
||||
dill==0.3.8
|
||||
distro==1.9.0
|
||||
docker==5.0.3
|
||||
eyed3==0.9.7
|
||||
filelock==3.13.1
|
||||
filetype==1.2.0
|
||||
fonttools==4.46.0
|
||||
fs==2.4.16
|
||||
Glances==3.4.0.3
|
||||
gyp==0.1
|
||||
html2text==2024.2.26
|
||||
httplib2==0.20.4
|
||||
idna==3.6
|
||||
ifaddr==0.2.0
|
||||
IMDbPY==2021.4.18
|
||||
influxdb==5.3.1
|
||||
kiwisolver==0.0.0
|
||||
launchpadlib==1.11.0
|
||||
lazr.restfulclient==0.14.6
|
||||
lazr.uri==1.0.6
|
||||
libevdev==0.5
|
||||
libvirt-python==10.0.0
|
||||
louis==3.29.0
|
||||
lxml==5.2.1
|
||||
lz4==4.0.2+dfsg
|
||||
Mako==1.3.2.dev0
|
||||
Markdown==3.5.2
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==2.1.5
|
||||
matplotlib==3.6.3
|
||||
mdurl==0.1.2
|
||||
mpmath==0.0.0
|
||||
msgpack==1.0.3
|
||||
multiprocess==0.70.16
|
||||
mutagen==1.46.0
|
||||
nemo-emblems==6.4.0
|
||||
netaddr==0.8.0
|
||||
netifaces==0.11.0
|
||||
nicotine-plus==3.2.9
|
||||
numpy==1.26.4
|
||||
oauthlib==3.2.2
|
||||
onboard==1.4.1
|
||||
packaging==24.0
|
||||
PAM==0.4.2
|
||||
pexpect==4.9.0
|
||||
pillow==10.2.0
|
||||
pipx==1.4.3
|
||||
platformdirs==4.2.0
|
||||
ply==3.11
|
||||
psutil==5.9.8
|
||||
ptyprocess==0.7.0
|
||||
pulsemixer==1.5.1
|
||||
pyasn1==0.4.8
|
||||
pyasyncore==1.0.2
|
||||
pycairo==1.25.1
|
||||
pycryptodomex==3.20.0
|
||||
pycups==2.0.1
|
||||
pycurl==7.45.3
|
||||
pyelftools==0.30
|
||||
Pygments==2.17.2
|
||||
PyGObject==3.48.2
|
||||
PyICU==2.12
|
||||
pyinotify==0.9.6
|
||||
PyJWT==2.7.0
|
||||
PyNaCl==1.5.0
|
||||
pyparsing==3.1.1
|
||||
pyparted==3.12.0
|
||||
pypng==0.20231004.0
|
||||
pysmi==0.3.4
|
||||
pysnmp==4.4.12
|
||||
pystache==0.6.0
|
||||
python-apt==2.7.7+ubuntu4
|
||||
python-dateutil==2.8.2
|
||||
python-debian==0.1.49+ubuntu2
|
||||
python-gnupg==0.5.2
|
||||
python-magic==0.4.27
|
||||
python-xlib==0.33
|
||||
pytz==2024.1
|
||||
pyudev==0.24.0
|
||||
pyxdg==0.28
|
||||
PyYAML==6.0.1
|
||||
qrcode==7.4.2
|
||||
ranger-fm==1.9.3
|
||||
repolib==2.2.1
|
||||
requests==2.31.0
|
||||
requests-file==1.5.1
|
||||
rich==13.7.1
|
||||
SciPy==1.11.4
|
||||
setproctitle==1.3.3
|
||||
setuptools==68.1.2
|
||||
six==1.16.0
|
||||
soupsieve==2.5
|
||||
sympy==1.12
|
||||
systemd-python==235
|
||||
tinycss2==1.2.1
|
||||
tldextract==3.1.2
|
||||
typing_extensions==4.10.0
|
||||
ubuntu-drivers-common==0.0.0
|
||||
ufoLib2==0.16.0
|
||||
ufw==0.36.2
|
||||
ujson==5.9.0
|
||||
unicodedata2==15.1.0
|
||||
Unidecode==1.3.8
|
||||
urllib3==2.0.7
|
||||
userpath==1.9.1
|
||||
wadllib==1.3.6
|
||||
webencodings==0.5.1
|
||||
websocket-client==1.7.0
|
||||
websockets==10.4
|
||||
wheel==0.42.0
|
||||
xdg==5
|
||||
xkit==0.0.0
|
||||
xlrd==2.0.1
|
||||
yt-dlp==2024.4.9
|
0
shrinkinminkin/__init__.py
Normal file
16
shrinkinminkin/asgi.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
ASGI config for shrinkinminkin 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/5.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shrinkinminkin.settings')
|
||||
|
||||
application = get_asgi_application()
|
130
shrinkinminkin/settings.py
Normal file
|
@ -0,0 +1,130 @@
|
|||
"""
|
||||
Django settings for shrinkinminkin project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 5.2.3.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/5.2/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# 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/5.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'django-insecure-)z5-$t&%njx^$4wrsq4+@#oybrssf_z*1(p9t(^o2v!2nkybab'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['localhost', 'localhost:8000', '127.0.0.1']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'web',
|
||||
]
|
||||
|
||||
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 = 'shrinkinminkin.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'shrinkinminkin.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/5.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/5.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||
STATICFILES_DIRS = [BASE_DIR / 'static',]
|
||||
STORAGES = {
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
|
||||
},
|
||||
}
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
13
shrinkinminkin/urls.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from web.views import index, album, socials, mailing_list
|
||||
|
||||
urlpatterns = [
|
||||
path('', index, name='index'),
|
||||
path('album/', album, name='album'),
|
||||
path('album.html/', album, name='album'),
|
||||
path('socials/', socials, name='socials'),
|
||||
path('socials.html/', socials, name='socials'),
|
||||
path('mailing_list/', mailing_list, name='mailing_list'),
|
||||
path('admin/', admin.site.urls),
|
||||
]
|
16
shrinkinminkin/wsgi.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for shrinkinminkin 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/5.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shrinkinminkin.settings')
|
||||
|
||||
application = get_wsgi_application()
|
7
static/css/bootstrap.min.css
vendored
Normal file
70
static/css/style.css
Normal file
|
@ -0,0 +1,70 @@
|
|||
@font-face { font-family: Virgo; src: url('../fonts/virgo.ttf'); }
|
||||
|
||||
body {
|
||||
background-color: #189ccf;
|
||||
font-family: Virgo, monospace;
|
||||
}
|
||||
|
||||
.header-img {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
width: 150px;
|
||||
padding-right: 10px;
|
||||
display: inline;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 45px;
|
||||
}
|
||||
|
||||
#band-img-1 {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
|
||||
}
|
||||
|
||||
.responsive-iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.navi-link {
|
||||
color: #ff0000;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.navi-link:hover {
|
||||
opacity: 70%;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.contact-container {
|
||||
color: #20d582;
|
||||
background-color: #8220d5;
|
||||
}
|
||||
|
||||
.footer-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
BIN
static/fonts/nabla.ttf
Normal file
BIN
static/fonts/virgo.ttf
Normal file
BIN
static/img/album_release_header.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/img/band_1.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
static/img/band_banner.jpg
Normal file
After Width: | Height: | Size: 145 KiB |
BIN
static/img/bugman_sticker.png
Normal file
After Width: | Height: | Size: 242 KiB |
BIN
static/img/members.png
Normal file
After Width: | Height: | Size: 5.7 MiB |
BIN
static/img/shrinkin_minkin_album_header.png
Normal file
After Width: | Height: | Size: 47 KiB |
7
static/js/bootstrap.min.js
vendored
Normal file
2
static/js/p5.min.js
vendored
Normal file
230
static/js/sketch.js
Normal file
|
@ -0,0 +1,230 @@
|
|||
let myFont;
|
||||
function preload() {
|
||||
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||
}
|
||||
|
||||
function setup() {
|
||||
if (windowWidth <= 480) {
|
||||
var canvas = createCanvas(windowWidth, 200);
|
||||
} else {
|
||||
var canvas = createCanvas(windowWidth, 300);
|
||||
}
|
||||
canvas.parent('shrinkin-sketch')
|
||||
}
|
||||
|
||||
function windowResized() {
|
||||
if (windowWidth <= 480) {
|
||||
var canvas = resizeCanvas(windowWidth, 200);
|
||||
} else {
|
||||
var canvas = resizeCanvas(windowWidth, 300);
|
||||
}
|
||||
}
|
||||
|
||||
class Ball {
|
||||
constructor(x, y, r) {
|
||||
this.position = new p5.Vector(x, y);
|
||||
this.velocity = p5.Vector.random2D();
|
||||
this.velocity.mult(3);
|
||||
this.r = r;
|
||||
this.m = r * 0.1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
this.position.add(this.velocity);
|
||||
}
|
||||
|
||||
checkBoundaryCollision() {
|
||||
if (this.position.x > width - this.r) {
|
||||
this.position.x = width - this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.x < this.r) {
|
||||
this.position.x = this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.y > height - this.r) {
|
||||
this.position.y = height - this.r;
|
||||
this.velocity.y *= -1;
|
||||
} else if (this.position.y < this.r) {
|
||||
this.position.y = this.r;
|
||||
this.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
checkCollision(other) {
|
||||
// Get distances between the balls components
|
||||
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||
|
||||
// Calculate magnitude of the vector separating the balls
|
||||
let distanceVectMag = distanceVect.mag();
|
||||
|
||||
// Minimum distance before they are touching
|
||||
let minDistance = this.r + other.r;
|
||||
|
||||
if (distanceVectMag < minDistance) {
|
||||
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||
let d = distanceVect.copy();
|
||||
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||
other.position.add(correctionVector);
|
||||
this.position.sub(correctionVector);
|
||||
|
||||
// get angle of distanceVect
|
||||
let theta = distanceVect.heading();
|
||||
// precalculate trig values
|
||||
let sine = sin(theta);
|
||||
let cosine = cos(theta);
|
||||
|
||||
/* bTemp will hold rotated ball this.positions. You
|
||||
just need to worry about bTemp[1] this.position*/
|
||||
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
/* this ball's this.position is relative to the other
|
||||
so you can use the vector between them (bVect) as the
|
||||
reference point in the rotation expressions.
|
||||
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||
automatically to 0.0, which is what you want
|
||||
since b[1] will rotate around b[0] */
|
||||
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||
|
||||
// rotate Temporary velocities
|
||||
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||
|
||||
/* Now that velocities are rotated, you can use 1D
|
||||
conservation of momentum equations to calculate
|
||||
the final this.velocity along the x-axis. */
|
||||
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[0].x =
|
||||
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[0].y = vTemp[0].y;
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[1].x =
|
||||
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[1].y = vTemp[1].y;
|
||||
|
||||
// hack to avoid clumping
|
||||
bTemp[0].x += vFinal[0].x;
|
||||
bTemp[1].x += vFinal[1].x;
|
||||
|
||||
/* Rotate ball this.positions and velocities back
|
||||
Reverse signs in trig expressions to rotate
|
||||
in the opposite direction */
|
||||
// rotate balls
|
||||
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||
|
||||
// update balls to screen this.position
|
||||
other.position.x = this.position.x + bFinal[1].x;
|
||||
other.position.y = this.position.y + bFinal[1].y;
|
||||
|
||||
this.position.add(bFinal[0]);
|
||||
|
||||
// update velocities
|
||||
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||
}
|
||||
}
|
||||
|
||||
display(friend1, friend2) {
|
||||
this.update()
|
||||
noStroke();
|
||||
fill('#ff0000');
|
||||
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||
this.checkBoundaryCollision()
|
||||
this.checkCollision(friend1)
|
||||
this.checkCollision(friend2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Logo {
|
||||
constructor() {
|
||||
this.yOffset = 0
|
||||
this.up = false
|
||||
this.textSize = 36
|
||||
this.bounceDepth = 10
|
||||
this.speed = 0.2
|
||||
}
|
||||
|
||||
display() {
|
||||
fill('#20d582');
|
||||
textFont(myFont);
|
||||
|
||||
if (windowWidth/6 > 120) {
|
||||
textSize(120);
|
||||
} else {
|
||||
textSize(windowWidth/6)
|
||||
}
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||
} else {
|
||||
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||
}
|
||||
|
||||
this.bounce()
|
||||
}
|
||||
|
||||
bounce() {
|
||||
if (!this.up) {
|
||||
if (this.yOffset <= this.bounceDepth) {
|
||||
this.yOffset = this.yOffset + this.speed
|
||||
}
|
||||
if (this.yOffset > this.bounceDepth) {
|
||||
this.up = true
|
||||
}
|
||||
} else {
|
||||
if (this.yOffset > 0) {
|
||||
this.yOffset = this.yOffset - this.speed
|
||||
}
|
||||
if (this.yOffset < 0) {
|
||||
this.up = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let ball1 = new Ball(100, 400, 20)
|
||||
let ball2 = new Ball(700, 400, 80)
|
||||
let ball3 = new Ball(0, 200, 60)
|
||||
let logo = new Logo()
|
||||
|
||||
|
||||
function draw() {
|
||||
background('#209bd0');
|
||||
|
||||
|
||||
ball1.display(ball2, ball3)
|
||||
ball2.display(ball1, ball3)
|
||||
ball3.display(ball1, ball2)
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
ball2.r = 40;
|
||||
ball3.r = 30;
|
||||
} else {
|
||||
ball2.r = 80;
|
||||
ball3.r = 60;
|
||||
}
|
||||
|
||||
logo.display()
|
||||
|
||||
}
|
227
static/js/sketch_export.js
Normal file
|
@ -0,0 +1,227 @@
|
|||
let myFont;
|
||||
function preload() {
|
||||
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var canvas = createCanvas(1200, 400);
|
||||
canvas.parent('shrinkin-sketch')
|
||||
createLoop({duration:120, gif:true})
|
||||
}
|
||||
|
||||
function windowResized() {
|
||||
if (windowWidth <= 480) {
|
||||
var canvas = resizeCanvas(windowWidth, 200);
|
||||
} else {
|
||||
var canvas = resizeCanvas(windowWidth, 300);
|
||||
}
|
||||
}
|
||||
|
||||
class Ball {
|
||||
constructor(x, y, r) {
|
||||
this.position = new p5.Vector(x, y);
|
||||
this.velocity = p5.Vector.random2D();
|
||||
this.velocity.mult(3);
|
||||
this.r = r;
|
||||
this.m = r * 0.1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
this.position.add(this.velocity);
|
||||
}
|
||||
|
||||
checkBoundaryCollision() {
|
||||
if (this.position.x > width - this.r) {
|
||||
this.position.x = width - this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.x < this.r) {
|
||||
this.position.x = this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.y > height - this.r) {
|
||||
this.position.y = height - this.r;
|
||||
this.velocity.y *= -1;
|
||||
} else if (this.position.y < this.r) {
|
||||
this.position.y = this.r;
|
||||
this.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
checkCollision(other) {
|
||||
// Get distances between the balls components
|
||||
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||
|
||||
// Calculate magnitude of the vector separating the balls
|
||||
let distanceVectMag = distanceVect.mag();
|
||||
|
||||
// Minimum distance before they are touching
|
||||
let minDistance = this.r + other.r;
|
||||
|
||||
if (distanceVectMag < minDistance) {
|
||||
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||
let d = distanceVect.copy();
|
||||
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||
other.position.add(correctionVector);
|
||||
this.position.sub(correctionVector);
|
||||
|
||||
// get angle of distanceVect
|
||||
let theta = distanceVect.heading();
|
||||
// precalculate trig values
|
||||
let sine = sin(theta);
|
||||
let cosine = cos(theta);
|
||||
|
||||
/* bTemp will hold rotated ball this.positions. You
|
||||
just need to worry about bTemp[1] this.position*/
|
||||
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
/* this ball's this.position is relative to the other
|
||||
so you can use the vector between them (bVect) as the
|
||||
reference point in the rotation expressions.
|
||||
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||
automatically to 0.0, which is what you want
|
||||
since b[1] will rotate around b[0] */
|
||||
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||
|
||||
// rotate Temporary velocities
|
||||
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||
|
||||
/* Now that velocities are rotated, you can use 1D
|
||||
conservation of momentum equations to calculate
|
||||
the final this.velocity along the x-axis. */
|
||||
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[0].x =
|
||||
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[0].y = vTemp[0].y;
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[1].x =
|
||||
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[1].y = vTemp[1].y;
|
||||
|
||||
// hack to avoid clumping
|
||||
bTemp[0].x += vFinal[0].x;
|
||||
bTemp[1].x += vFinal[1].x;
|
||||
|
||||
/* Rotate ball this.positions and velocities back
|
||||
Reverse signs in trig expressions to rotate
|
||||
in the opposite direction */
|
||||
// rotate balls
|
||||
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||
|
||||
// update balls to screen this.position
|
||||
other.position.x = this.position.x + bFinal[1].x;
|
||||
other.position.y = this.position.y + bFinal[1].y;
|
||||
|
||||
this.position.add(bFinal[0]);
|
||||
|
||||
// update velocities
|
||||
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||
}
|
||||
}
|
||||
|
||||
display(friend1, friend2) {
|
||||
this.update()
|
||||
noStroke();
|
||||
fill('#ff0000');
|
||||
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||
this.checkBoundaryCollision()
|
||||
this.checkCollision(friend1)
|
||||
this.checkCollision(friend2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Logo {
|
||||
constructor() {
|
||||
this.yOffset = 0
|
||||
this.up = false
|
||||
this.textSize = 36
|
||||
this.bounceDepth = 10
|
||||
this.speed = 0.2
|
||||
}
|
||||
|
||||
display() {
|
||||
fill('#20d582');
|
||||
textFont(myFont);
|
||||
|
||||
if (windowWidth/6 > 120) {
|
||||
textSize(120);
|
||||
} else {
|
||||
textSize(windowWidth/6)
|
||||
}
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||
} else {
|
||||
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||
}
|
||||
|
||||
this.bounce()
|
||||
}
|
||||
|
||||
bounce() {
|
||||
if (!this.up) {
|
||||
if (this.yOffset <= this.bounceDepth) {
|
||||
this.yOffset = this.yOffset + this.speed
|
||||
}
|
||||
if (this.yOffset > this.bounceDepth) {
|
||||
this.up = true
|
||||
}
|
||||
} else {
|
||||
if (this.yOffset > 0) {
|
||||
this.yOffset = this.yOffset - this.speed
|
||||
}
|
||||
if (this.yOffset < 0) {
|
||||
this.up = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let ball1 = new Ball(100, 400, 20)
|
||||
let ball2 = new Ball(700, 400, 80)
|
||||
let ball3 = new Ball(0, 200, 60)
|
||||
let logo = new Logo()
|
||||
|
||||
|
||||
function draw() {
|
||||
background('#209bd0');
|
||||
|
||||
|
||||
ball1.display(ball2, ball3)
|
||||
ball2.display(ball1, ball3)
|
||||
ball3.display(ball1, ball2)
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
ball2.r = 40;
|
||||
ball3.r = 30;
|
||||
} else {
|
||||
ball2.r = 80;
|
||||
ball3.r = 60;
|
||||
}
|
||||
|
||||
logo.display()
|
||||
|
||||
}
|
0
web/__init__.py
Normal file
6
web/admin.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.contrib import admin
|
||||
from web.models import MailingList
|
||||
|
||||
admin.site.register(MailingList)
|
||||
|
||||
# Register your models here.
|
6
web/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WebConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'web'
|
27
web/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Generated by Django 5.2.3 on 2025-06-29 21:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='MailingList',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, null=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True, null=True)),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
0
web/migrations/__init__.py
Normal file
BIN
web/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
web/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
14
web/models.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
|
||||
updated_at = models.DateTimeField(blank=True, null=True, auto_now=True)
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class MailingList(BaseModel):
|
||||
email = models.EmailField(max_length=254, blank=False, null=False)
|
7
web/static/css/bootstrap.min.css
vendored
Normal file
69
web/static/css/style.css
Normal file
|
@ -0,0 +1,69 @@
|
|||
@font-face { font-family: Virgo; src: url('../fonts/virgo.ttf'); }
|
||||
|
||||
body {
|
||||
background-color: #189ccf;
|
||||
font-family: Virgo, sans-serif;
|
||||
}
|
||||
|
||||
.header-img {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
width: 150px;
|
||||
padding-right: 10px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 45px;
|
||||
}
|
||||
|
||||
#band-img-1 {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
|
||||
}
|
||||
|
||||
.responsive-iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.navi-link {
|
||||
color: #ff0000;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.navi-link:hover {
|
||||
opacity: 70%;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.contact-container {
|
||||
color: #20d582;
|
||||
background-color: #8220d5;
|
||||
}
|
||||
|
||||
.footer-image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
BIN
web/static/fonts/nabla.ttf
Normal file
BIN
web/static/fonts/virgo.ttf
Normal file
BIN
web/static/img/album_release_header.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
web/static/img/band_1.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
BIN
web/static/img/band_banner.jpg
Normal file
After Width: | Height: | Size: 145 KiB |
BIN
web/static/img/bugman_sticker.png
Normal file
After Width: | Height: | Size: 242 KiB |
BIN
web/static/img/members.png
Normal file
After Width: | Height: | Size: 5.7 MiB |
BIN
web/static/img/shrinkin_minkin_album_header.png
Normal file
After Width: | Height: | Size: 47 KiB |
7
web/static/js/bootstrap.min.js
vendored
Normal file
2
web/static/js/p5.min.js
vendored
Normal file
230
web/static/js/sketch.js
Normal file
|
@ -0,0 +1,230 @@
|
|||
let myFont;
|
||||
function preload() {
|
||||
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||
}
|
||||
|
||||
function setup() {
|
||||
if (windowWidth <= 480) {
|
||||
var canvas = createCanvas(windowWidth, 200);
|
||||
} else {
|
||||
var canvas = createCanvas(windowWidth, 300);
|
||||
}
|
||||
canvas.parent('shrinkin-sketch')
|
||||
}
|
||||
|
||||
function windowResized() {
|
||||
if (windowWidth <= 480) {
|
||||
var canvas = resizeCanvas(windowWidth, 200);
|
||||
} else {
|
||||
var canvas = resizeCanvas(windowWidth, 300);
|
||||
}
|
||||
}
|
||||
|
||||
class Ball {
|
||||
constructor(x, y, r) {
|
||||
this.position = new p5.Vector(x, y);
|
||||
this.velocity = p5.Vector.random2D();
|
||||
this.velocity.mult(3);
|
||||
this.r = r;
|
||||
this.m = r * 0.1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
this.position.add(this.velocity);
|
||||
}
|
||||
|
||||
checkBoundaryCollision() {
|
||||
if (this.position.x > width - this.r) {
|
||||
this.position.x = width - this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.x < this.r) {
|
||||
this.position.x = this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.y > height - this.r) {
|
||||
this.position.y = height - this.r;
|
||||
this.velocity.y *= -1;
|
||||
} else if (this.position.y < this.r) {
|
||||
this.position.y = this.r;
|
||||
this.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
checkCollision(other) {
|
||||
// Get distances between the balls components
|
||||
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||
|
||||
// Calculate magnitude of the vector separating the balls
|
||||
let distanceVectMag = distanceVect.mag();
|
||||
|
||||
// Minimum distance before they are touching
|
||||
let minDistance = this.r + other.r;
|
||||
|
||||
if (distanceVectMag < minDistance) {
|
||||
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||
let d = distanceVect.copy();
|
||||
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||
other.position.add(correctionVector);
|
||||
this.position.sub(correctionVector);
|
||||
|
||||
// get angle of distanceVect
|
||||
let theta = distanceVect.heading();
|
||||
// precalculate trig values
|
||||
let sine = sin(theta);
|
||||
let cosine = cos(theta);
|
||||
|
||||
/* bTemp will hold rotated ball this.positions. You
|
||||
just need to worry about bTemp[1] this.position*/
|
||||
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
/* this ball's this.position is relative to the other
|
||||
so you can use the vector between them (bVect) as the
|
||||
reference point in the rotation expressions.
|
||||
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||
automatically to 0.0, which is what you want
|
||||
since b[1] will rotate around b[0] */
|
||||
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||
|
||||
// rotate Temporary velocities
|
||||
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||
|
||||
/* Now that velocities are rotated, you can use 1D
|
||||
conservation of momentum equations to calculate
|
||||
the final this.velocity along the x-axis. */
|
||||
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[0].x =
|
||||
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[0].y = vTemp[0].y;
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[1].x =
|
||||
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[1].y = vTemp[1].y;
|
||||
|
||||
// hack to avoid clumping
|
||||
bTemp[0].x += vFinal[0].x;
|
||||
bTemp[1].x += vFinal[1].x;
|
||||
|
||||
/* Rotate ball this.positions and velocities back
|
||||
Reverse signs in trig expressions to rotate
|
||||
in the opposite direction */
|
||||
// rotate balls
|
||||
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||
|
||||
// update balls to screen this.position
|
||||
other.position.x = this.position.x + bFinal[1].x;
|
||||
other.position.y = this.position.y + bFinal[1].y;
|
||||
|
||||
this.position.add(bFinal[0]);
|
||||
|
||||
// update velocities
|
||||
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||
}
|
||||
}
|
||||
|
||||
display(friend1, friend2) {
|
||||
this.update()
|
||||
noStroke();
|
||||
fill('#ff0000');
|
||||
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||
this.checkBoundaryCollision()
|
||||
this.checkCollision(friend1)
|
||||
this.checkCollision(friend2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Logo {
|
||||
constructor() {
|
||||
this.yOffset = 0
|
||||
this.up = false
|
||||
this.textSize = 36
|
||||
this.bounceDepth = 10
|
||||
this.speed = 0.2
|
||||
}
|
||||
|
||||
display() {
|
||||
fill('#20d582');
|
||||
textFont(myFont);
|
||||
|
||||
if (windowWidth/6 > 120) {
|
||||
textSize(120);
|
||||
} else {
|
||||
textSize(windowWidth/6)
|
||||
}
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||
} else {
|
||||
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||
}
|
||||
|
||||
this.bounce()
|
||||
}
|
||||
|
||||
bounce() {
|
||||
if (!this.up) {
|
||||
if (this.yOffset <= this.bounceDepth) {
|
||||
this.yOffset = this.yOffset + this.speed
|
||||
}
|
||||
if (this.yOffset > this.bounceDepth) {
|
||||
this.up = true
|
||||
}
|
||||
} else {
|
||||
if (this.yOffset > 0) {
|
||||
this.yOffset = this.yOffset - this.speed
|
||||
}
|
||||
if (this.yOffset < 0) {
|
||||
this.up = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let ball1 = new Ball(100, 400, 20)
|
||||
let ball2 = new Ball(700, 400, 80)
|
||||
let ball3 = new Ball(0, 200, 60)
|
||||
let logo = new Logo()
|
||||
|
||||
|
||||
function draw() {
|
||||
background('#209bd0');
|
||||
|
||||
|
||||
ball1.display(ball2, ball3)
|
||||
ball2.display(ball1, ball3)
|
||||
ball3.display(ball1, ball2)
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
ball2.r = 40;
|
||||
ball3.r = 30;
|
||||
} else {
|
||||
ball2.r = 80;
|
||||
ball3.r = 60;
|
||||
}
|
||||
|
||||
logo.display()
|
||||
|
||||
}
|
227
web/static/js/sketch_export.js
Normal file
|
@ -0,0 +1,227 @@
|
|||
let myFont;
|
||||
function preload() {
|
||||
myFont = loadFont('assets/fonts/nabla.ttf');
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var canvas = createCanvas(1200, 400);
|
||||
canvas.parent('shrinkin-sketch')
|
||||
createLoop({duration:120, gif:true})
|
||||
}
|
||||
|
||||
function windowResized() {
|
||||
if (windowWidth <= 480) {
|
||||
var canvas = resizeCanvas(windowWidth, 200);
|
||||
} else {
|
||||
var canvas = resizeCanvas(windowWidth, 300);
|
||||
}
|
||||
}
|
||||
|
||||
class Ball {
|
||||
constructor(x, y, r) {
|
||||
this.position = new p5.Vector(x, y);
|
||||
this.velocity = p5.Vector.random2D();
|
||||
this.velocity.mult(3);
|
||||
this.r = r;
|
||||
this.m = r * 0.1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
this.position.add(this.velocity);
|
||||
}
|
||||
|
||||
checkBoundaryCollision() {
|
||||
if (this.position.x > width - this.r) {
|
||||
this.position.x = width - this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.x < this.r) {
|
||||
this.position.x = this.r;
|
||||
this.velocity.x *= -1;
|
||||
} else if (this.position.y > height - this.r) {
|
||||
this.position.y = height - this.r;
|
||||
this.velocity.y *= -1;
|
||||
} else if (this.position.y < this.r) {
|
||||
this.position.y = this.r;
|
||||
this.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
checkCollision(other) {
|
||||
// Get distances between the balls components
|
||||
let distanceVect = p5.Vector.sub(other.position, this.position);
|
||||
|
||||
// Calculate magnitude of the vector separating the balls
|
||||
let distanceVectMag = distanceVect.mag();
|
||||
|
||||
// Minimum distance before they are touching
|
||||
let minDistance = this.r + other.r;
|
||||
|
||||
if (distanceVectMag < minDistance) {
|
||||
let distanceCorrection = (minDistance - distanceVectMag) / 2.0;
|
||||
let d = distanceVect.copy();
|
||||
let correctionVector = d.normalize().mult(distanceCorrection);
|
||||
other.position.add(correctionVector);
|
||||
this.position.sub(correctionVector);
|
||||
|
||||
// get angle of distanceVect
|
||||
let theta = distanceVect.heading();
|
||||
// precalculate trig values
|
||||
let sine = sin(theta);
|
||||
let cosine = cos(theta);
|
||||
|
||||
/* bTemp will hold rotated ball this.positions. You
|
||||
just need to worry about bTemp[1] this.position*/
|
||||
let bTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
/* this ball's this.position is relative to the other
|
||||
so you can use the vector between them (bVect) as the
|
||||
reference point in the rotation expressions.
|
||||
bTemp[0].this.position.x and bTemp[0].this.position.y will initialize
|
||||
automatically to 0.0, which is what you want
|
||||
since b[1] will rotate around b[0] */
|
||||
bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y;
|
||||
bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x;
|
||||
|
||||
// rotate Temporary velocities
|
||||
let vTemp = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y;
|
||||
vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x;
|
||||
vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y;
|
||||
vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x;
|
||||
|
||||
/* Now that velocities are rotated, you can use 1D
|
||||
conservation of momentum equations to calculate
|
||||
the final this.velocity along the x-axis. */
|
||||
let vFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[0].x =
|
||||
((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[0].y = vTemp[0].y;
|
||||
|
||||
// final rotated this.velocity for b[0]
|
||||
vFinal[1].x =
|
||||
((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) /
|
||||
(this.m + other.m);
|
||||
vFinal[1].y = vTemp[1].y;
|
||||
|
||||
// hack to avoid clumping
|
||||
bTemp[0].x += vFinal[0].x;
|
||||
bTemp[1].x += vFinal[1].x;
|
||||
|
||||
/* Rotate ball this.positions and velocities back
|
||||
Reverse signs in trig expressions to rotate
|
||||
in the opposite direction */
|
||||
// rotate balls
|
||||
let bFinal = [new p5.Vector(), new p5.Vector()];
|
||||
|
||||
bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
|
||||
bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
|
||||
bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
|
||||
bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;
|
||||
|
||||
// update balls to screen this.position
|
||||
other.position.x = this.position.x + bFinal[1].x;
|
||||
other.position.y = this.position.y + bFinal[1].y;
|
||||
|
||||
this.position.add(bFinal[0]);
|
||||
|
||||
// update velocities
|
||||
this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
|
||||
this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
|
||||
other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
|
||||
other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
|
||||
}
|
||||
}
|
||||
|
||||
display(friend1, friend2) {
|
||||
this.update()
|
||||
noStroke();
|
||||
fill('#ff0000');
|
||||
ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2);
|
||||
this.checkBoundaryCollision()
|
||||
this.checkCollision(friend1)
|
||||
this.checkCollision(friend2)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Logo {
|
||||
constructor() {
|
||||
this.yOffset = 0
|
||||
this.up = false
|
||||
this.textSize = 36
|
||||
this.bounceDepth = 10
|
||||
this.speed = 0.2
|
||||
}
|
||||
|
||||
display() {
|
||||
fill('#20d582');
|
||||
textFont(myFont);
|
||||
|
||||
if (windowWidth/6 > 120) {
|
||||
textSize(120);
|
||||
} else {
|
||||
textSize(windowWidth/6)
|
||||
}
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
text('shrinkin', width/2 - 120, 20 + 60 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 100 + 60 + this.yOffset);
|
||||
} else {
|
||||
text('shrinkin', width/2 - 120, 50 + 90 + this.yOffset);
|
||||
text('-minkin', width/2 - 120, 150 + 90 + this.yOffset);
|
||||
}
|
||||
|
||||
this.bounce()
|
||||
}
|
||||
|
||||
bounce() {
|
||||
if (!this.up) {
|
||||
if (this.yOffset <= this.bounceDepth) {
|
||||
this.yOffset = this.yOffset + this.speed
|
||||
}
|
||||
if (this.yOffset > this.bounceDepth) {
|
||||
this.up = true
|
||||
}
|
||||
} else {
|
||||
if (this.yOffset > 0) {
|
||||
this.yOffset = this.yOffset - this.speed
|
||||
}
|
||||
if (this.yOffset < 0) {
|
||||
this.up = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let ball1 = new Ball(100, 400, 20)
|
||||
let ball2 = new Ball(700, 400, 80)
|
||||
let ball3 = new Ball(0, 200, 60)
|
||||
let logo = new Logo()
|
||||
|
||||
|
||||
function draw() {
|
||||
background('#209bd0');
|
||||
|
||||
|
||||
ball1.display(ball2, ball3)
|
||||
ball2.display(ball1, ball3)
|
||||
ball3.display(ball1, ball2)
|
||||
|
||||
if (windowWidth <= 480) {
|
||||
ball2.r = 40;
|
||||
ball3.r = 30;
|
||||
} else {
|
||||
ball2.r = 80;
|
||||
ball3.r = 60;
|
||||
}
|
||||
|
||||
logo.display()
|
||||
|
||||
}
|
41
web/templates/album.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% block 'content' %}
|
||||
<div class="container">
|
||||
<center>
|
||||
<br>
|
||||
<br>
|
||||
<h5>Listen to our first album Tyrannizing Harmonics Everywhere!!</h5>
|
||||
<br>
|
||||
<div style="margin: 0 auto; max-width: 600px;">
|
||||
<iframe style="border: 0; width: 100%; height: 439px;" src="https://bandcamp.com/EmbeddedPlayer/album=4037494074/size=large/bgcol=ffffff/linkcol=0687f5/artwork=small/transparent=true/" seamless><a href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">Tyrannizing Harmonics by shrinkin-minkin</a></iframe>
|
||||
|
||||
</div>
|
||||
|
||||
<a target="_blank" href="https://open.spotify.com/album/4imchLIIQnfFfrxcy0bQ3l">
|
||||
<button type="button" class="btn btn-light link">Spotify</button><br>
|
||||
</a>
|
||||
<a target="_blank" href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">
|
||||
<button type="button" class="btn btn-light link">Bandcamp</button><br>
|
||||
</a>
|
||||
<a target="_blank" href="https://www.youtube.com/watch?v=hwaWr7GQ09M&list=OLAK5uy_mr2CAlUomJZIEd3Y0_vIiguRz80bXNmwI">
|
||||
<button type="button" class="btn btn-light link">YouTube</button><br>
|
||||
</a>
|
||||
<a target="_blank" href="https://music.apple.com/us/album/tyrannizing-harmonics/1814317803" style="display:none;">
|
||||
<button type="button" class="btn btn-light link">Apple Music</button><br>
|
||||
</a>
|
||||
<a target="_blank" href="https://www.pandora.com/artist/shrinkin-minkin/tyrannizing-harmonics/AL3j4zhrhJbf4cP">
|
||||
<button type="button" class="btn btn-light link">Pandora</button><br>
|
||||
</a>
|
||||
<a target="_blank" href="https://www.instagram.com/shrinkinminkin/">
|
||||
<button type="button" class="btn btn-light link">Follow us on Instagram</button><br>
|
||||
</a>
|
||||
<br>
|
||||
{% include 'mailing_list.html' %}
|
||||
|
||||
|
||||
We hope you enjoy our ad free listening experience! Please visit our socials and like and subscribe to support us!
|
||||
</center>
|
||||
<br><br>
|
||||
</div>
|
||||
{% endblock %}
|
45
web/templates/base.html
Normal file
|
@ -0,0 +1,45 @@
|
|||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Shrinkin-Minkin</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/style.css' %}">
|
||||
</head>
|
||||
<body style="padding: 0px; margin: 0px;">
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-success alert-dismissible fade show"
|
||||
role="alert"
|
||||
style="max-width:400px;
|
||||
position: fixed;
|
||||
bottom:0;
|
||||
right: 0;
|
||||
margin:20px">
|
||||
{{ message }}
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">X</span>
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<center>
|
||||
<a href="{% url 'index' %}">
|
||||
<img src="{% static 'img/album_release_header.png' %}"
|
||||
alt=""
|
||||
class="header-img">
|
||||
<br>
|
||||
</a>
|
||||
</center>
|
||||
{% block 'content' %}{% endblock %}
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
|
||||
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
|
||||
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
|
||||
crossorigin="anonymous"></script>
|
||||
</body>
|
123
web/templates/index.html
Normal file
|
@ -0,0 +1,123 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% block 'content' %}
|
||||
<div>
|
||||
<center>
|
||||
<a href="#listen">
|
||||
<button type="button" class="btn btn-light nav-link">listen</button>
|
||||
</a>
|
||||
|
||||
<a href="#watch">
|
||||
<button type="button" class="btn btn-light nav-link">watch</button>
|
||||
</a>
|
||||
|
||||
<a href="#book">
|
||||
<button type="button" class="btn btn-light nav-link">book us</button>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'socials' %}">
|
||||
<button type="button" class="btn btn-light nav-link">social</button>
|
||||
</a>
|
||||
<br>
|
||||
</center>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container-fluid pt-2 mt-3">
|
||||
|
||||
<div class="row pb-4">
|
||||
<div class="col-lg-6">
|
||||
<center>
|
||||
<img id="band-img-1" class="img-fluid" src="{% static 'img/members.png' %}" alt="" style="margin-bottom: 20px; width:100%; height: auto; max-width: 840px;">
|
||||
|
||||
<div style="margin-top:30px; margin-bottom: 20px;">
|
||||
{% include 'mailing_list.html' %}
|
||||
</div>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6" style="padding:30px; background-color: #54b879;">
|
||||
<h1>About Us:</h1>
|
||||
<p>
|
||||
<b>SHRINKIN-MINKIN</b> thrives on the fringes of genre, violating the confines of classification.
|
||||
Founded in 2022 by singer/guitarists Dominic DiTaranto and Michael Heinfling;
|
||||
SHRINKIN-MINKIN blends Rock, Funk, Jazz, Punk, infused with creative improvisation and FX landscape.
|
||||
The NJ based 5-piece is <i>tight</i>. Technical, Playful, and dripping with thirst-quenching satire.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Their musical multiplicity allows SHRINKIN-MINKIN to fit into any lineup.
|
||||
Their songs range from the Funk, Rock, Hip Hop, Gospel fusion of "GLOP";
|
||||
to Post-Punk anthems like "Industry Rock" and the comical love-lament of "Butter Queen".
|
||||
Songs that are guaranteed to get asses convulsing in rhythmic fervor.
|
||||
More discerning listeners can relax and watch the band trade solos on "Down Polypore Wood".
|
||||
Add in Alternative ballads, Blues tracks, and even a Psychedelic-Waltz and you will begin to scratch
|
||||
the surface of what SHRINKIN-MINKIN has to offer.
|
||||
<br><br>
|
||||
<a href="#book">Book Us</a> now to support or headline!
|
||||
</p>
|
||||
<p>
|
||||
<b>Members:</b>
|
||||
<br>Dominic DiTaranto - Guitar/Vocals/Synth
|
||||
<br>Michael Heinfling - Guitar/Vocals
|
||||
<br>Charlie Misch - Keyboard/Synth
|
||||
<br>B.S. Ashford - Bass
|
||||
<br>Recon Paul - Drums
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<b>Recommended if you like:</b>
|
||||
Frank Zappa,
|
||||
King Crimson,
|
||||
Talking Heads,
|
||||
David Bowie,
|
||||
Mahavishnu Orchestra,
|
||||
Phish,
|
||||
Miles Davis,
|
||||
The Stooges,
|
||||
Funkadelic,
|
||||
John Coltrane,
|
||||
The Stranglers,
|
||||
The Damned,
|
||||
Weather Report,
|
||||
The Cars
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 id="listen">Listen:</h1>
|
||||
<center>
|
||||
<iframe style="border: 0; max-width: 350px; height: 753px;" src="https://bandcamp.com/EmbeddedPlayer/album=4037494074/size=large/bgcol=ffffff/linkcol=de270f/transparent=true/" seamless><a href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">Tyrannizing Harmonics by shrinkin-minkin</a></iframe>
|
||||
</center>
|
||||
<br><br>
|
||||
|
||||
<h1 id="watch">Watch Us Live:</h1>
|
||||
<div class="iframe-container">
|
||||
|
||||
<iframe class="responsive-iframe" src="https://www.youtube.com/embed/7Dbg5MuOgbY?si=qW3dw8QY4a8sHqbX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
</div>
|
||||
<br><br>
|
||||
<div class="iframe-container">
|
||||
<iframe class="responsive-iframe" src="https://www.youtube.com/embed/4Cx1_LMJRzM?si=fS9EuyczsNvsJuSb&start=42" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
</div>
|
||||
<br><br>
|
||||
<div class="iframe-container">
|
||||
<iframe class="responsive-iframe" src="https://www.youtube.com/embed/R3fo-k2_wfM?si=Foz0OaTK6GC5psKo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div class="mt-5 mb-5 p-5">
|
||||
<h1 id="book">Book Us:</h1>
|
||||
<br>
|
||||
Email: shrinkinminkin<span style="font-family: monospace;">@</span>gmail.com <br>
|
||||
Phone: 732-895-5253
|
||||
<br><br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<img class="footer-image" src="{% static 'img/bugman_sticker.png' %}" alt="">
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
8
web/templates/mailing_list.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<div class="card p-2" style="margin-bottom:10px;">
|
||||
<form action="/mailing_list/" method="post">
|
||||
{% csrf_token %}
|
||||
<label for="email">Join Our Mailing List:</label>
|
||||
<input type="email" id="email" name="email" placeholder="your@email.com" style="font-family: monospace;">
|
||||
<input type="submit" class="btn btn-success" value="JOIN">
|
||||
</form>
|
||||
</div>
|
44
web/templates/socials.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% block 'content' %}
|
||||
<div class="container">
|
||||
<center>
|
||||
<br>
|
||||
<br>
|
||||
<iframe style="border: 0;
|
||||
width: 100%;
|
||||
height: 42px"
|
||||
src="https://bandcamp.com/EmbeddedPlayer/album=4037494074/size=small/bgcol=ffffff/linkcol=0687f5/transparent=true/"
|
||||
seamless><a href="https://shrinkin-minkin.bandcamp.com/album/tyrannizing-harmonics">Tyrannizing Harmonics by shrinkin-minkin</a></iframe>
|
||||
<a target="_blank" href="{% url 'album' %}">
|
||||
<button type="button" class="btn btn-success link">Listen To Our Album!</button>
|
||||
<br>
|
||||
</a>
|
||||
<a target="_blank" href="https://www.instagram.com/shrinkinminkin/">
|
||||
<button type="button" class="btn btn-light link">Instagram</button>
|
||||
<br>
|
||||
</a>
|
||||
<a target="_blank" href="https://shrinkin-minkin.bandcamp.com/">
|
||||
style="margin-bottom:10px;" <button type="button" class="btn btn-light link">Bandcamp</button>
|
||||
<br>
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://www.youtube.com/channel/UCCmRKeoqtHC9G1X-yvuUG7A">
|
||||
<button type="button" class="btn btn-light link">YouTube</button>
|
||||
<br>
|
||||
</a>
|
||||
<a target="_blank" href="https://www.shrinkinminkin.com/">
|
||||
<button type="button" class="btn btn-light link">For Promoters And Venues</button>
|
||||
<br>
|
||||
</a>
|
||||
<a target="_blank" href="https://www.bonfire.com/store/shrinkin-minkin/">
|
||||
<button type="button" class="btn btn-danger link">Merch</button>
|
||||
<br>
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
</center>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
{% endblock %}
|
3
web/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
33
web/views.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from django.contrib import messages
|
||||
from django.shortcuts import render, redirect
|
||||
from web.models import MailingList
|
||||
|
||||
|
||||
|
||||
def index(request):
|
||||
return render(request, 'index.html')
|
||||
|
||||
|
||||
def album(request):
|
||||
return render(request, 'album.html')
|
||||
|
||||
|
||||
def socials(request):
|
||||
return render(request, 'socials.html')
|
||||
|
||||
|
||||
def mailing_list(request):
|
||||
if request.method == 'POST':
|
||||
referer = request.META['HTTP_REFERER'][:-1].split('/')[-1].split('.')[0]
|
||||
email = request.POST.get('email')
|
||||
|
||||
if email:
|
||||
exists = MailingList.objects.filter(email=email).first()
|
||||
if not exists:
|
||||
m = MailingList(
|
||||
email=email
|
||||
)
|
||||
m.save()
|
||||
messages.add_message(request, messages.INFO, "Nice! Thanks for joining our mailing list!")
|
||||
|
||||
return redirect(referer)
|