diff --git a/.gitignore b/.gitignore index e2082e9..c97fc85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ *.un~ *.swp *.sh +thsf.log +thsf_venv +build/ +src/thsf.egg-info/ +thsf.pid diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..6a5acb6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "arrowParens": "always", + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": false +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..dd49821 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +global-exclude *.pyc +global-exclude build +global-exclude __pycache__ + +include src/thsf/templates/*.* +include src/thsf/static/**/*.* diff --git a/Makefile b/Makefile index 9ac38b3..5f27d87 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,45 @@ -.PHONY: install +.PHONY: clean distclean install run stop install: - echo "We Make P0RN" + set -e ;\ + THSF_DIR=$$(pwd); \ + echo [+] Déploiement dans $$THSF_DIR; \ + python3 -m venv thsf_venv; \ + . thsf_venv/bin/activate; \ + pip3 install -r requirements.txt ;\ + pip3 install . ;\ + pip3 install gunicorn; \ + +run: + set -e ;\ + THSF_DIR=$$(pwd); \ + echo [+] Démarrage dans $$THSF_DIR; \ + . thsf_venv/bin/activate; \ + thsf_venv/bin/gunicorn -D -p thsf.pid -w 4 -b 127.0.0.1:8042 'thsf:app' + +debug: + set -e ;\ + THSF_DIR=$$(pwd); \ + echo [+] Démarrage dans $$THSF_DIR; \ + . thsf_venv/bin/activate; \ + thsf_venv/bin/gunicorn -p thsf.pid -w 4 -b 127.0.0.1:8042 'thsf:app' + +stop: + -set -e;\ + THSF_DIR=$$(pwd); \ + echo [+] Arrêt dans $$THSF_DIR; \ + kill -15 $$(cat $$THSF_DIR/thsf.pid); \ + rm thsf.pid + +clean: + -set -e ;\ + THSF_DIR=$$(pwd); \ + echo [+] Nettoyage dans $$THSF_DIR; \ + rm -Rf ./build ./src/thsf.egg-info ./thsf.pid ./thsf.log; \ + . thsf_venv/bin/activate; \ + pip3 uninstall thsf -y + +distclean: clean + rm -Rf thsf_venv/ + +all: stop clean install run diff --git a/NOTE.md b/NOTE.md new file mode 100644 index 0000000..9a6b225 --- /dev/null +++ b/NOTE.md @@ -0,0 +1,84 @@ +# API + +## Récupérer l'évènement + +```bash +curl -s -X GET -H "Authorization: Token " https://23.thsf.net/api/events/ +``` + +Réponse: + +```json +[{"name":{"en":"Toulouse HackerSpace Factory","fr":"Toulouse HackerSpace Factory"},"slug":"thsf-2023","is_public":true,"date_from":"2023-05-26","date_to":"2023-05-28","timezone":"Europe/Paris","urls":{"base":"https://23.thsf.net/thsf-2023/","schedule":"https://23.thsf.net/thsf-2023/schedule/","login":"https://23.thsf.net/thsf-2023/login/","feed":"https://23.thsf.net/thsf-2023/schedule/feed.xml"}}] +``` + +## Récupérer la liste des intervenants + +```bash +curl -s -X GET -H "Authorization: Token " https://23.thsf.net/api/speakes/ +``` + +## Récupérer la liste des salles + + curl -s -X GET -H "Authorization: Token " https://23.thsf.net/api/events/thsf-2023/rooms/ + +## Récupérer les versions des plannings de l'évènement + +```bash +curl -s -X GET -H "Authorization: Token " https://23.thsf.net/api/events//schedules/ +``` + +Réponse: + +```json +{"count":6,"next":null,"previous":null,"results":[{"version":"wip","published":null},{"version":"0.5","published":"2023-04-03T12:14:39.675671+02:00"},{"version":"0.4","published":"2023-04-03T10:07:41.632059+02:00"},{"version":"0.3","published":"2023-03-25T12:34:17.704819+01:00"},{"version":"0.2","published":"2023-03-25T12:21:23.464899+01:00"},{"version":"0.1","published":"2023-03-25T12:14:10.460100+01:00"}]} +``` + +### Récupérer un planning spécifique + +```bash +curl -s -X GET -H "Authorization: Token " https://23.thsf.net/api/events/thsf-2023/schedules// +``` + +Reponse: + +```json +{ + "slots": [ + { + "code": "JHCFVE", + "speakers": [ + { + "code": "BT9CDU", + "name": "Youssr Youssef", + "biography": "", + "avatar": "https://23.thsf.net/media/avatars/YoussrYoussef_408QSEG.jpeg" + } + ], + "title": "René Carmille, un hacker sous l'Occupation", + "submission_type": { + "en": "Screening", + "fr": "Projection" + }, + "track": null, + "state": "confirmed", + "abstract": "Entre collaboration et résistance, confronté aux premiers enjeux modernes de la collecte de données en masse, la trajectoire étonnante de René Carmille n'a encore jamais été racontée... Son héritage est pourtant majeur, les questions qu'il soulève le sont tout autant. \r\nSous l’Occupation, le polytechnicien René Carmille est le précurseur de l'usage massif des données en France : c'est lui qui a mis en place et dirigé le Service national de statistiques (SNS) qui deviendra plus tard l'INSEE, c'est aussi lui qui a inventé notre numéro de sécurité sociale.\r\n\r\nLa projection du documentaire sera suivie d'une rencontre en visioconférence avec la réalisatrice.", + "description": "", + "duration": 80, + "slot_count": 1, + "do_not_record": false, + "is_featured": true, + "content_locale": "fr", + "slot": { + "room": { + "en": "Salle 1 Cinema", + "fr": "Salle 1 Cinema" + }, + "start": "2023-05-27T11:30:00+02:00", + "end": "2023-05-27T12:50:00+02:00" + }, + "image": "https://23.thsf.net/media/thsf-2023/submissions/JHCFVE/Carmille-1-scaled_p0gxA6D.jpeg", + "resources": [] + }, +... +``` diff --git a/README.md b/README.md index c7ff670..704aa32 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Le site du THSF ## Modifier le site -Il n'est **pas possible** de pousser directement des modifcations sur la branche `master`. +Il n'est **pas possible** de pousser directement des modifications sur la branche `master`. Pour modifier le site, il est nécessaire de créer une branche spécifique et d'y pousser vos modifications. @@ -16,9 +16,9 @@ Lorsque la demande de fusion sera acceptée (vous pouvez auto-accepter vos deman ### Personnalisation de la publication -Afin de rendre le processus plus souple, il est possible de personnaliser la livraison en plaçant **à la racine du dépôt** un fichier `Makefile` contenant une cible `install` qui sera systématiquement executée. +Afin de rendre le processus plus souple, il est possible de personnaliser la livraison en plaçant **à la racine du dépôt** un fichier `Makefile` contenant une cible `all` qui sera systématiquement exécutée. -C'est dans cette cible `install` que vous pourrez mettre toutes vos commandes personnalisées, typiquement l'installation de modules `npm`. +C'est dans cette cible `all` que vous pourrez mettre toutes vos commandes personnalisées, typiquement l'installation de modules `python`, etc. Le processus de publication est le suivant: @@ -26,7 +26,7 @@ Le processus de publication est le suivant: 2. La branche `master` du présent dépôt est cloné sur le serveur hébergeant le site du **THSF** -3. Si un fichier `Makefile` se trouve **à la racine du dépôt**, la cible `install` (i.e: `make install`) est automatiquement exécutée. +3. Si un fichier `Makefile` se trouve **à la racine du dépôt**, la cible `all` (i.e: `make all`) est automatiquement exécutée. ## Contrôle de qualité et tests diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..a049ae7 --- /dev/null +++ b/config.yml @@ -0,0 +1,65 @@ +--- +log: + version: 1 + formatters: + default: + format: '[%(asctime)-20s][%(levelname)-8s][%(funcName)-20s]: %(message)s' + handlers: + wsgi: + class: logging.FileHandler + filename: thsf.log + formatter: default + loggers: + thsf: + handlers: [wsgi] + propagate: no + root: + level: DEBUG + handlers: [wsgi] +app: + secret_key: xxx + languages: + - fr + name: THSF + real_url: https://www.thsf.net +pretalx: + url: https://23.thsf.net + apiprefix: api + apikey: bb770a53b15467dfb67c03d178004aca9e4819d6 + event: thsf-2023 + schedule: wip +navbar: + items: + - name: Home + classes: fa-solid fa-house + url: / + - name: Programme + classes: fa-regular fa-calendar + url: /planning + - name: Lieu + classes: fa-solid fa-map-location-dot + url: /place + - name: Restauration + classes: fa-solid fa-burger + url: /food + - name: Goodies + classes: fa-solid fa-shirt + url: /goodies + - name: Concerts & DJ Sets + classes: fa-solid fa-guitar + url: /concerts + - name: Ateliers + classes: fa-solid fa-screwdriver-wrench + url: /workshops + - name: Projections + classes: fa-solid fa-film + url: /screenings + - name: Tables rondes + classes: fa-solid fa-users-line + url: /discussions + - name: Installations artistiques + classes: fa-solid fa-palette + url: /exhibitions + - name: Présentations + classes: fa-solid fa-person-chalkboard + url: /talks diff --git a/images/affiche_v1.png b/images/affiche_v1.png deleted file mode 100644 index bba9baf..0000000 Binary files a/images/affiche_v1.png and /dev/null differ diff --git a/index.html b/index.html deleted file mode 100644 index f703f35..0000000 --- a/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - THSF 2023: Extractivisme - - - - - - - -
    -
  • -
  • -
  • -
  • Extraction in progress...
  • -
  • -
  • -
  • -
  • Extraction in progress...
  • -
  • -
  • -
  • -
  • Extraction in progress...
  • -
  • -
  • -
  • -
  • Extraction in progress...
  • -
  • -
  • -
  • -
- - diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dc40988 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["setuptools>=62", + "build", + "wheel"] +build-backend = "setuptools.build_meta" + +[tool.pytest.ini_options] +pythonpath = [ + "src" +] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..62c69fa --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +build +wheel +flask +Flask-Minify +gunicorn +pyYAML +requests diff --git a/resources/THSF23_WEBSITE_BANNER.svg b/resources/THSF23_WEBSITE_BANNER.svg new file mode 100644 index 0000000..f680b45 --- /dev/null +++ b/resources/THSF23_WEBSITE_BANNER.svg @@ -0,0 +1,611 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..65b6405 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,50 @@ +[metadata] +version = 0.0.1 +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: MIT License + Operating System :: OS Independent +url = https://git.tetalab.org/tetalab/thsf.net +description = "THSF website" +name = thsf +long_description = file: README.md +long_description_content_type = text/markdown +author = Doug Le Tough +author_email = doug@redatomik.org + +[options] +package_dir = + = src +packages = find: +include_package_data = True +python_requires = >=3.7 +install_requires = + flask + Flask-Minify + gunicorn + pyYAML + requests + +[options.packages.find] +where = src + +[options.extras_require] +dev = + twine + build + wheel>=0.37.0 + flake8>=4.0.1 + flake8-breakpoint>=1.1.0 + flake8-builtins>=1.5.3 + flake8-print>=4.0.0 + flake8-return>=1.1.3 + pep8-naming>=0.8.2 + setuptools>=60.9.2 + pylint>=2.12.2 + +[flake8] +ignore = E111 +exclude = .git,__pycache__,build,dist, thot-cli-venv +max-line-length = 160 +use-flake8-tabs = true +tab-width = 2 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b908cbe --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +import setuptools + +setuptools.setup() diff --git a/src/thsf/__init__.py b/src/thsf/__init__.py new file mode 100644 index 0000000..b05909b --- /dev/null +++ b/src/thsf/__init__.py @@ -0,0 +1,202 @@ +import re +import sys +import json +import logging +from logging import config +import yaml +from flask import Flask, render_template, redirect, request, url_for +from flask_minify import minify +from thsf.backend import Backend +from thsf.schedule import Schedule +from thsf.navbar import Navbar + + +# ------------------------------------------------------------------------------ +# -- Configuration +# ------------------------------------------------------------------------------ +class AppConfig: + """ Flask application config """ + CONFIG_FILENAME = "config.yml" + + +# ------------------------------------------------------------------------------ +# -- Application +# ------------------------------------------------------------------------------ +logger = logging.getLogger('wsgi') +app = Flask(__name__) + +# ------------------------------------------------------------------------------ +# -- Local configuration +# ------------------------------------------------------------------------------ +app.config.from_object(__name__ + '.AppConfig') +try: + with open(app.config["CONFIG_FILENAME"], mode="r", encoding="utf-8") as local_config_file: + app.local_config = yaml.load(local_config_file, Loader=yaml.SafeLoader) + app.config["SECRET_KEY"] = app.local_config["app"]["secret_key"] + app.config["LANGUAGES"] = app.local_config["app"]["languages"] + config.dictConfig(app.local_config["log"]) + backend = Backend(url=app.local_config["pretalx"]["url"], + apiprefix=app.local_config["pretalx"]["apiprefix"], + apikey=app.local_config["pretalx"]["apikey"]) + schedule = Schedule() + navbar = Navbar(config=app.local_config["navbar"]) +except Exception as err: + logger.critical("[{}] {}".format(err.__class__, str(err))) + sys.exit(1) + +if app.local_config["log"]["root"]["level"] != "DEBUG": + minify(app=app, html=True, js=True, cssless=True) + +# ------------------------------------------------------------------------------ +# -- Tools +# ------------------------------------------------------------------------------ +@app.errorhandler(404) +def page_not_found(err): + return redirect(url_for('index')) + +def get_slots(): + return backend.get(endpoint=f"events/{app.local_config['pretalx']['event']}/schedules/{app.local_config['pretalx']['schedule']}/").json() + +def get_speaker_biography(name): + try: + speaker_info = backend.get(endpoint=f"events/{app.local_config['pretalx']['event']}/speakers/", params={"q": name}).json() + logging.info(speaker_info) + return speaker_info["results"][0]["biography"].strip() + except Exception as err: + logging.error(f"UnknownSpeakerError: {name}") + return None + +# ------------------------------------------------------------------------------ +# -- Custom filters +# ------------------------------------------------------------------------------ +@app.template_filter('date2dmyhm') +def date2dmyhm(date): + splitted_date = date.split("-") + splitted_time = splitted_date[2].split("T")[1].split(":") + year, month, day = (splitted_date[0], + splitted_date[1], + splitted_date[2].split("T")[0]) + hour, minutes = (splitted_time[0], splitted_time[1].split("+")[0]) + return f"{day}/{month} {hour}:{minutes}" + +@app.template_filter('date2dayclass') +def date2dayclass(date): + classes = {"26/05": "bg1", + "27/05": "bg2", + "28/05": "bg3",} + splitted_date = date.split("-") + month, day = (splitted_date[1], + splitted_date[2].split("T")[0]) + return classes[f"{day}/{month}"] + +@app.template_filter('toicon') +def date2dmyhm(slot_type): + slot_types = {"Projection": "fa-solid fa-film", + "Presentation Courte": "fa-solid fa-person-chalkboard", + "DJ Set": "fa-solid fa-guitar", + "Concert": "fa-solid fa-guitar", + "Présentation": "fa-solid fa-person-chalkboard", + "Table Ronde": "fa-solid fa-users-line", + "Atelier": "fa-solid fa-screwdriver-wrench", + "Exposition": "fa-solid fa-palette"} + return slot_types[slot_type] + +# ------------------------------------------------------------------------------ +# -- Routes +# ------------------------------------------------------------------------------ +@app.route('/favicon.ico', methods=['GET']) +def favicon(): + return redirect(url_for('static', filename='images/favicon.png')) + + +@app.route('/', methods=['GET']) +def index(): + return render_template("index.html", + navbar=navbar.get_from_page(page="/")) + +@app.route('/planning', methods=['GET']) +def planning(): + slots = get_slots() + for slot in slots.get("slots"): + for speaker in slot.get("speakers"): + speaker["biography"] = get_speaker_biography(speaker.get("name")) + return render_template("planning.html", + slots=sorted(slots.get("slots"), + key=lambda slot: slot.get("slot").get("start")), + navbar=navbar.get_from_page(page="/planning")) + +@app.route('/place', methods=['GET']) +def place(): + return render_template("index.html", + navbar=navbar.get_from_page(page="/place")) + +@app.route('/food', methods=['GET']) +def food(): + return render_template("index.html", + navbar=navbar.get_from_page(page="/food")) + +@app.route('/goodies', methods=['GET']) +def goodies(): + return render_template("goodies.html", + navbar=navbar.get_from_page(page="/goodies")) + +@app.route('/concerts', methods=['GET']) +def concerts(): + slots = get_slots() + return render_template("planning.html", + slots=sorted(slots.get("slots"), + key=lambda slot: slot.get("slot").get("start")), + navbar=navbar.get_from_page(page="/concerts"), + filter=["concert", "dj set"]) + +@app.route('/workshops', methods=['GET']) +def workshops(): + slots = get_slots() + return render_template("planning.html", + slots=sorted(slots.get("slots"), + key=lambda slot: slot.get("slot").get("start")), + navbar=navbar.get_from_page(page="/workshops"), + filter=["workshop"]) + +@app.route('/screenings', methods=['GET']) +def screenings(): + slots = get_slots() + return render_template("planning.html", + slots=sorted(slots.get("slots"), + key=lambda slot: slot.get("slot").get("start")), + navbar=navbar.get_from_page(page="/screenings"), + filter=["screening"]) + +@app.route('/discussions', methods=['GET']) +def discussions(): + slots = get_slots() + return render_template("planning.html", + slots=sorted(slots.get("slots"), + key=lambda slot: slot.get("slot").get("start")), + navbar=navbar.get_from_page(page="/discussions"), + filter=["panel discussion"]) + +@app.route('/exhibitions', methods=['GET']) +def exhibitions(): + slots = get_slots() + return render_template("planning.html", + slots=sorted(slots.get("slots"), + key=lambda slot: slot.get("slot").get("start")), + navbar=navbar.get_from_page(page="/exhibitions"), + filter=["exhibition"]) + +@app.route('/talks', methods=['GET']) +def talks(): + slots = get_slots() + return render_template("planning.html", + slots=sorted(slots.get("slots"), + key=lambda slot: slot.get("slot").get("start")), + navbar=navbar.get_from_page(page="/talks"), + filter=["talk", "light talk"]) + + +# ------------------------------------------------------------------------------ +# -- Main +# ------------------------------------------------------------------------------ +if __name__ == '__main__': + app.run(host='127.0.0.1', port=5000, debug=True) diff --git a/src/thsf/backend/__init__.py b/src/thsf/backend/__init__.py new file mode 100644 index 0000000..1eb615d --- /dev/null +++ b/src/thsf/backend/__init__.py @@ -0,0 +1,15 @@ +import requests +import logging + +class Backend: + def __init__(self, url, apiprefix, apikey): + self.url = url + self.apiprefix = apiprefix + self.apikey = apikey + self.session = requests.Session() + + def get(self, endpoint, params=None): + url = f"{self.url}/{self.apiprefix}/{endpoint}" + headers = {"Authorization": f"Token {self.apikey}", + "Accept": "application/json"} + return self.session.get(url, params=params, headers=headers) diff --git a/src/thsf/navbar/__init__.py b/src/thsf/navbar/__init__.py new file mode 100644 index 0000000..605c6ee --- /dev/null +++ b/src/thsf/navbar/__init__.py @@ -0,0 +1,6 @@ +class Navbar: + def __init__(self, config): + self.config = config + + def get_from_page(self, page): + return [item for item in self.config["items"] if item["url"] != page] diff --git a/src/thsf/schedule/__init__.py b/src/thsf/schedule/__init__.py new file mode 100644 index 0000000..adba87e --- /dev/null +++ b/src/thsf/schedule/__init__.py @@ -0,0 +1,6 @@ +class Schedule: + def __init__(self): + self.slots = list() + + def set_slots(self, slots): + self.slots = slots diff --git a/src/thsf/static/css/colors.css b/src/thsf/static/css/colors.css new file mode 100644 index 0000000..47b860c --- /dev/null +++ b/src/thsf/static/css/colors.css @@ -0,0 +1,49 @@ +@font-face { + font-family: pfdintextcomppromedium; + src: url(../fonts/PFDinTextCompPro-Medium.ttf); +} + +@font-face { + font-family: pfdintextcompprothin; + src: url(../fonts/PFDinTextCompPro-Thin.ttf); +} + +:root { + --main-bg-color: #e6007e; + --alt-bg-color: #E59730; + --alt2-bg-color: #9EBF43; + --alt3-bg-color: #3096E5; + --main-color: #ffffff; + --alt-main-color: #1A000D; +} + +.white { + color: var(--main-color); +} + +.black { + color: var(--alt-main-color); +} + +.thin { + font-family: pfdintextcompprothin; +} + +.bold { + font-family: pfdintextcomppromedium; +} + +.bg1 { + background-color: var(--alt-bg-color); + border-color: var(--alt-bg-color); +} + +.bg2 { + background-color: var(--alt2-bg-color); + border-color: var(--alt2-bg-color); +} + +.bg3 { + background-color: var(--alt3-bg-color); + border-color: var(--alt3-bg-color); +} diff --git a/src/thsf/static/css/custom.css b/src/thsf/static/css/custom.css new file mode 100644 index 0000000..c14817f --- /dev/null +++ b/src/thsf/static/css/custom.css @@ -0,0 +1,109 @@ +@media screen and (min-width: 45em) { + .header { + display: flex; + flex-direction: row; + justify-content: center; + gap: 0; + text-align: center; + font-size: 9.75em; + font-weight: bold; + padding: 0; + } + .logo { + width: inherit; + } + .header > span { + margin: 0; + } + .subheader { + margin: -1em 0 0 0; + font-size: 3.47em; + } + .place { + margin: 0; + font-size: 2.145em; + } + .important { + font-family: pfdintextcomppromedium; + } + .left { + float: left; + margin-right: 0.5em; + } + .right { + float: right; + margin-left: 0.5em; + } + .logo_partner { + max-width: 250px; + max-height: 250px; + margin: 1em; + } + .button { + font-size: 2.5em; + transition-property: color; + transition-duration: 1s; + } + .button:hover { + color: var(--main-color); + cursor: pointer; + } +} + +@media screen and (max-width: 44em) { + .header { + display: flex; + flex-direction: row; + justify-content: center; + gap: 0; + text-align: center; + font-size: 6.75em; + font-weight: bold; + padding: 0; + } + .header > span { + margin: 0; + } + .logo { + width: inherit; + } + .subheader { + margin: -1em 0 0 0; + font-size: 2.30em; + } + .place { + margin: 0; + font-size: 1.2em; + } + .important { + font-family: pfdintextcomppromedium; + } + .left { + float: left; + margin-right: 0.25em; + } + .right { + float: right; + margin-left: 0.25em; + } + .logo_partner { + max-width: 125px; + max-height: 125px; + margin: 0.25em; + } + .button { + font-size: 1.2em; + transition-property: color; + transition-duration: 1s; + } + .button:hover { + color: var(--main-color); + cursor: pointer; + } + .goodies { + text-align: justify; + } + .goodies_pic { + max-width: 5em; + } +} diff --git a/src/thsf/static/css/elements.css b/src/thsf/static/css/elements.css new file mode 100644 index 0000000..912a022 --- /dev/null +++ b/src/thsf/static/css/elements.css @@ -0,0 +1,18 @@ +a { + font-family: pfdintextcomppromedium; + font-weight: 250; + color: var(--alt-main-color); + transition-property: color; + transition-duration: 1s; + text-decoration: wavy; +} + +a:hover { + color: var(--main-color); + cursor: pointer; +} + +.content > p, +.content > h2 { + margin-top: 1.5em; +} diff --git a/src/thsf/static/css/slot.css b/src/thsf/static/css/slot.css new file mode 100644 index 0000000..f824b10 --- /dev/null +++ b/src/thsf/static/css/slot.css @@ -0,0 +1,66 @@ +.slot { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + align-content: center; + margin-bottom: 1em; + width: 20em; +} + +.slot_header { + margin: 0; + width: 20em; + font-family: pfdintextcompprothin; + font-weight: bold; +} + +.slot_title { + border-radius: 1em 0 0 0; + color: var(--main-color); + padding: 0.5em; + text-align: center; + display: flex; + flex-direction: row; + justify-content: flex-start; + align-content: flex-start; + align-items: flex-start; + width: 20em; + cursor: pointer; +} + +.slot_title .title{ + margin-left: 0.5em; +} + +.slot_info { + background-color: var(--main-color); + color: var(--alt-main-color); + margin: 0; + padding: 0.5em; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-content: flex-start; + align-items: flex-start; + border-radius: 0 0 0 1em; +} + +.speaker { + cursor: pointer; +} + +.speakers > .speaker > .name > span { + text-decoration: underline; +} + +.speaker_details, +.slot_details { + visibility: hidden; + display: none; +} + +.speaker_img, +.slot_img { + width: 18em; +} diff --git a/src/thsf/static/css/style.css b/src/thsf/static/css/style.css new file mode 100644 index 0000000..40c3a1e --- /dev/null +++ b/src/thsf/static/css/style.css @@ -0,0 +1,15 @@ +* { + box-sizing: border-box; +} + +body { + background-color: var(--main-bg-color); + font-family: pfdintextcomppromedium; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + align-content: center; + text-align: center; + /* background-color: yellow; */ +} diff --git a/src/thsf/static/css/tooltip.css b/src/thsf/static/css/tooltip.css new file mode 100644 index 0000000..de75b9d --- /dev/null +++ b/src/thsf/static/css/tooltip.css @@ -0,0 +1,57 @@ +.tooltip, +.slot_tooltip { + position: relative; + display: inline-block; +} + +.tooltip .tooltiptext { + visibility: hidden; + background-color: var(--alt-main-color); + color: var(--main-color); + text-align: center; + border-radius: 6px; + padding: 5px 0; + position: absolute; + z-index: 1; + bottom: 0; + left: 0; + opacity: 0; + transform: translateX(-25%) translateY(-2em); + transition: opacity 1s; +} + +.slot_tooltip .slot_tooltiptext { + visibility: hidden; + background-color: var(--main-color); + color: var(--alt-main-color); + text-align: center; + border-radius: 6px; + padding: 5px 0; + position: absolute; + z-index: 1; + bottom: 0; + left: 0; + opacity: 0; + transform: translateX(2em); + transition: opacity 1s; +} + +.tooltip .tooltiptext::after, +.slot_tooltip .slot_tooltiptext::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; +} + +.tooltip:hover .tooltiptext, +.slot_tooltip:hover .slot_tooltiptext { + visibility: visible; + opacity: 1; + font-size: 0.7em; + padding: 0.2em; +} + + diff --git a/src/thsf/static/css/wemakeporn.css b/src/thsf/static/css/wemakeporn.css new file mode 100644 index 0000000..7607230 --- /dev/null +++ b/src/thsf/static/css/wemakeporn.css @@ -0,0 +1,72 @@ +@media screen and (min-width: 45em) { + .wemakeporn { + background-color: #FFD036; + color: #000000; + font-family: Arial, Helvetica, sans-serif; + border-radius: 1em; + border-width: 1em; + border-style: solid; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + align-content: center; + padding: 0.5em; + transform: rotate(-20deg) translate(2em, -6em); + visibility: hidden; + position: fixed; + } + .wemakeporn:hover{ + cursor: default; + } + + .wemake { + font-size: 7em; + font-weight: bold; + flex-direction: row; + justify-content: center; + align-items: center; + align-content: center; + } + + .porn { + font-size: 12em; + font-weight: bold; + flex-direction: row; + justify-content: center; + align-items: center; + align-content: center; + } +} +@media screen and (max-width: 44em) { + .wemakeporn { + background-color: #FFD036; + color: #000000; + font-family: Arial, Helvetica, sans-serif; + border-radius: 0.5em; + border-width: 0.5em; + border-style: solid; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + align-content: center; + padding: 0.5em; + transform: rotate(-20deg) translate(-1.5em, 8em); + visibility: hidden; + position: fixed; + } + .wemakeporn:hover{ + cursor: default; + } + + .wemake { + font-size: 3.5em; + font-weight: bold; + } + + .porn { + font-size: 6em; + font-weight: bold; + } +} diff --git a/src/thsf/static/css/wrappers.css b/src/thsf/static/css/wrappers.css new file mode 100644 index 0000000..8ac4d3b --- /dev/null +++ b/src/thsf/static/css/wrappers.css @@ -0,0 +1,125 @@ +@media screen and (min-width: 45em) { + .page_wrapper { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + align-content: center; + text-align: center; + padding-bottom: 5em; + /* background-color: green; */ + } + .center_wrapper, + .header_wrapper { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + } + .logo_wrapper { + margin: 1em 0 1em 0; + width: 40em; + } + .navbar_wrapper { + position: fixed; + bottom: 0; + padding: 1em 0; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + gap: 1.4em; + background-color: var(--main-bg-color); + width: 40em; + transform: translateZ(2); + } + .content { + font-size: 2em; + font-family: pfdintextcompprothin; + color: var(--main-color); + width: 20em; + text-align:justify; + text-justify: inter-word; + } + .partners { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + margin-bottom: 2em; + } + .subpartners { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + text-align: center; + } +} +@media screen and (max-width: 44em) { + .page_wrapper { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + align-content: center; + text-align: center; + padding-bottom: 2em; + width: 21em; + /* background-color: green; */ + } + .center_wrapper , + .header_wrapper { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + width: 21em; + /* background-color: orangered; */ + } + .logo_wrapper { + margin-top: 0.5em; + width: 21em; + /* background-color: red; */ + } + .navbar_wrapper { + position: fixed; + bottom: 0; + padding: 0.5em 0; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + gap: 1em; + background-color: var(--main-bg-color); + width: 21em; + transform: translateZ(2); + /* background-color: white; */ + } + .content { + font-size: 1em; + font-family: pfdintextcompprothin; + color: var(--main-color); + width: 21em; + text-align:justify; + text-justify: inter-word; + } + .partners { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + margin-bottom: 2em; + } + .subpartners { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + text-align: center; + } +} diff --git a/fonts/PFDinTextCompPro-Medium.ttf b/src/thsf/static/fonts/PFDinTextCompPro-Medium.ttf similarity index 100% rename from fonts/PFDinTextCompPro-Medium.ttf rename to src/thsf/static/fonts/PFDinTextCompPro-Medium.ttf diff --git a/fonts/PFDinTextCompPro-Thin.ttf b/src/thsf/static/fonts/PFDinTextCompPro-Thin.ttf similarity index 100% rename from fonts/PFDinTextCompPro-Thin.ttf rename to src/thsf/static/fonts/PFDinTextCompPro-Thin.ttf diff --git a/fonts/Uni Sans Bold.otf b/src/thsf/static/fonts/Uni Sans Bold.otf similarity index 100% rename from fonts/Uni Sans Bold.otf rename to src/thsf/static/fonts/Uni Sans Bold.otf diff --git a/fonts/Uni Sans Book.otf b/src/thsf/static/fonts/Uni Sans Book.otf similarity index 100% rename from fonts/Uni Sans Book.otf rename to src/thsf/static/fonts/Uni Sans Book.otf diff --git a/src/thsf/static/images/antistatik.png b/src/thsf/static/images/antistatik.png new file mode 100644 index 0000000..0f160be Binary files /dev/null and b/src/thsf/static/images/antistatik.png differ diff --git a/src/thsf/static/images/bg.png b/src/thsf/static/images/bg.png new file mode 100644 index 0000000..c6734cb Binary files /dev/null and b/src/thsf/static/images/bg.png differ diff --git a/src/thsf/static/images/clutch.png b/src/thsf/static/images/clutch.png new file mode 100644 index 0000000..4802096 Binary files /dev/null and b/src/thsf/static/images/clutch.png differ diff --git a/images/favicon.png b/src/thsf/static/images/favicon.png similarity index 100% rename from images/favicon.png rename to src/thsf/static/images/favicon.png diff --git a/src/thsf/static/images/logo.svg b/src/thsf/static/images/logo.svg new file mode 100644 index 0000000..c2b921e --- /dev/null +++ b/src/thsf/static/images/logo.svg @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/thsf/static/images/pretalx-header.png b/src/thsf/static/images/pretalx-header.png new file mode 100644 index 0000000..c8e3346 Binary files /dev/null and b/src/thsf/static/images/pretalx-header.png differ diff --git a/src/thsf/static/images/stickers.webp b/src/thsf/static/images/stickers.webp new file mode 100644 index 0000000..2fee5df Binary files /dev/null and b/src/thsf/static/images/stickers.webp differ diff --git a/src/thsf/static/images/sweatshirt.webp b/src/thsf/static/images/sweatshirt.webp new file mode 100644 index 0000000..999a666 Binary files /dev/null and b/src/thsf/static/images/sweatshirt.webp differ diff --git a/src/thsf/static/images/terranova.jpg b/src/thsf/static/images/terranova.jpg new file mode 100644 index 0000000..ae4486a Binary files /dev/null and b/src/thsf/static/images/terranova.jpg differ diff --git a/src/thsf/static/images/tetalab.png b/src/thsf/static/images/tetalab.png new file mode 100644 index 0000000..16cf624 Binary files /dev/null and b/src/thsf/static/images/tetalab.png differ diff --git a/src/thsf/static/images/tetaneutral.png b/src/thsf/static/images/tetaneutral.png new file mode 100644 index 0000000..09b297d Binary files /dev/null and b/src/thsf/static/images/tetaneutral.png differ diff --git a/src/thsf/static/images/totebag.webp b/src/thsf/static/images/totebag.webp new file mode 100644 index 0000000..ae5d9a8 Binary files /dev/null and b/src/thsf/static/images/totebag.webp differ diff --git a/src/thsf/static/images/tshirt.webp b/src/thsf/static/images/tshirt.webp new file mode 100644 index 0000000..1b723ea Binary files /dev/null and b/src/thsf/static/images/tshirt.webp differ diff --git a/src/thsf/static/scripts/thsf23.js b/src/thsf/static/scripts/thsf23.js new file mode 100644 index 0000000..50fad40 --- /dev/null +++ b/src/thsf/static/scripts/thsf23.js @@ -0,0 +1,14 @@ +function switch_visibility(item){ + console.log(item.style.visibility); + console.log(item.style.display); + if (item.style.visibility == "hidden" || item.style.display == "none") { + item.style.visibility = "visible"; + item.style.display = "block"; + } else if (item.style.visibility == "" && item.style.display == "") { + item.style.visibility = "visible"; + item.style.display = "block"; + } else { + item.style.visibility = "hidden"; + item.style.display = "none"; + } +} diff --git a/src/thsf/templates/base.html b/src/thsf/templates/base.html new file mode 100644 index 0000000..e502619 --- /dev/null +++ b/src/thsf/templates/base.html @@ -0,0 +1,95 @@ + + + + THSF 2023: S/Extraire + + + + + + + + + + + + + + {% block headers %} + {% endblock %} + + + +
+
+
+
+ THSF + 2023 +
+
+ Toulouse Hacker Space Factory +
+
+ 26 28 mai 2023 - + CINÉMA UTOPIA BORDEROUGE +
+
+ {% block content %} + {% endblock %} +
+ +
+ + Tetaneutral + +
+ +
+ {% block navbar %} + {% include "navbar.html" %} + {% endblock %} +
+
+ + diff --git a/src/thsf/templates/goodies.html b/src/thsf/templates/goodies.html new file mode 100644 index 0000000..5f58f3e --- /dev/null +++ b/src/thsf/templates/goodies.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} +{% block content %} +
+ +
+
+

Nous avons besoin de votre soutien

+

+ Stickers + Pour faire du Toulouse Hacker Space Factory un événement toujours différent des autres festivals votre soutien financier est nécessaire. +

+

+ T-Shirt + Pour faciliter la collecte des dons et vous remercier de votre participation, nous avons mis en place une cagnote Leetchi qui nous permettra de recenser les dons et vous permettra de suivre l'évolution du financement de notre festival. +

+

+ Sweat shirt + Nous sommes également conscients que la situation actuelle est particulièrement difficile. C'est pourquoi nous nous engageons à ce que toutes les sommes qui dépasseront notre objectif de financement de 2 000 € seront reversées aux caisses des grévistes de la réforme des retraites. Ainsi, votre contribution permettra également de soutenir une cause importante et de faire une différence dans la vie de ceux qui se battent pour nos droits. +

+
+{% endblock %} diff --git a/src/thsf/templates/index.html b/src/thsf/templates/index.html new file mode 100644 index 0000000..9fb73cb --- /dev/null +++ b/src/thsf/templates/index.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} +{% block content %} +
+ +
+
WE MAKE
+
PORN
+
+
+
+

Le THSF est enfin de retour !

+

Nous vous invitons à passer un week-end de 3 jours à Utopia Borderouge Toulouse pour partager avec vous nos projets, nos réflexions, nos performances, nos poésies et nos doutes sur la technologie.

+ +

Après avoir été soutenu et accueilli pendant 10 ans par Mix'Art Myrys, le Toulouse HackerSpace Factory se tient désormais dans un autre lieu où l'utopie nécessaire est inscrite programme.

+ +

Cette année nous mettons en avant des réflexions sur l'extractivisme des ressources planétaires, des données, de la valeur travail.

+ +

Comme toujours, notre objectif est de créer un festival qui poétise les bifurcations de nos idées communes et qui réinvente le sens de certains schémas imposés par notre époque. Rejoignez-nous pour une expérience enrichissante et pleine de surprises !

+ +

Consulter le programme du THSF.

+
+{% endblock %} diff --git a/src/thsf/templates/navbar.html b/src/thsf/templates/navbar.html new file mode 100644 index 0000000..d0fb762 --- /dev/null +++ b/src/thsf/templates/navbar.html @@ -0,0 +1,8 @@ + diff --git a/src/thsf/templates/planning.html b/src/thsf/templates/planning.html new file mode 100644 index 0000000..aca6a52 --- /dev/null +++ b/src/thsf/templates/planning.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} +{% block content %} +
+ {% for slot in slots %} + {% set loop_index = loop.index %} + {% if filter %} + {% if slot.submission_type.en | lower in filter %} + {% include "slot.html" %} + {% endif %} + {% else %} + {% include "slot.html" %} + {% endif %} + {% endfor %} +
+{% endblock %} diff --git a/src/thsf/templates/slot.html b/src/thsf/templates/slot.html new file mode 100644 index 0000000..e3b0e52 --- /dev/null +++ b/src/thsf/templates/slot.html @@ -0,0 +1,64 @@ +
+
+
+ + {{slot.title}} +
+
+
+ + {{slot.slot.start | date2dmyhm}} - {{slot.duration}} minutes ({{slot.content_locale | capitalize}}) +
+
+ + {{slot.slot.room.fr}} +
+
+ {% for speaker in slot.speakers %} +
+
+ + {{speaker.name | title}} +
+ {% if speaker.avatar or speaker.biography %} +
+ {% if speaker.avatar %} +
+ {{speaker.name | title}} +
+ {% endif %} + {% if speaker.biography %} +
+
+ {{ speaker.biography }} +
+
+ {% endif %} +
+ {% endif %} +
+ {% endfor %} +
+
+
+ {% if slot.image %} + {{slot.name}} + {% endif %} + {% if slot.abstract %} +

{{slot.abstract}}

+ {% endif %} + {% if slot.description %} +

{{slot.description}}

+ {% endif %} +
+
+
+
+
diff --git a/src/thsf_wsgi.py b/src/thsf_wsgi.py new file mode 100644 index 0000000..f204296 --- /dev/null +++ b/src/thsf_wsgi.py @@ -0,0 +1,5 @@ +from thsf import app + +if __name__ == "__main__": + application = app + application.run(host="127.0.0.1", port=8043) diff --git a/styles/main.css b/styles/main.css deleted file mode 100644 index 3f502e1..0000000 --- a/styles/main.css +++ /dev/null @@ -1,139 +0,0 @@ -@font-face { - font-family: pfdintextcomppro; - src: url(../fonts/PFDinTextCompPro-Medium.ttf); -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; - font-family: pfdintextcomppro; -} - -body { - background-color: #e6007e; - background-image: url('../images/affiche_v1.png'); - background-repeat: no-repeat; - background-size: auto; - background-position-x: center; - overflow: hidden; -} - -ul { - overflow: hidden; - perspective: 900px; - list-style: none; - height: 100vh; - max-height: 800px; - min-height: 400px; - text-align: center; -} - -@keyframes width-sway { - 0%, 100% { - width: 500px; - } - 50% { - width: 100%; - } -} -li { - position: absolute; - top: 0; - margin: auto; - width: 100%; - transform: translateY(100vh); - font-size: 6rem; - font-family: pfdintextcomppro; - font-weight: bold; - color: #ffffdd; - animation: 5.3333333333s spiral-staircase linear infinite; - white-space: nowrap; -} - -li:nth-child(1) { - animation-delay: 0.3333333333s; -} - -li:nth-child(2) { - animation-delay: 0.6666666667s; -} - -li:nth-child(3) { - animation-delay: 1s; -} - -li:nth-child(4) { - animation-delay: 1.3333333333s; -} - -li:nth-child(5) { - animation-delay: 1.6666666667s; -} - -li:nth-child(6) { - animation-delay: 2s; -} - -li:nth-child(7) { - animation-delay: 2.3333333333s; -} - -li:nth-child(8) { - animation-delay: 2.6666666667s; -} - -li:nth-child(9) { - animation-delay: 3s; -} - -li:nth-child(10) { - animation-delay: 3.3333333333s; -} - -li:nth-child(11) { - animation-delay: 3.6666666667s; -} - -li:nth-child(12) { - animation-delay: 4s; -} - -li:nth-child(13) { - animation-delay: 4.3333333333s; -} - -li:nth-child(14) { - animation-delay: 4.6666666667s; -} - -li:nth-child(15) { - animation-delay: 5s; -} - -li:nth-child(16) { - animation-delay: 5.3333333333s; -} - -@keyframes spiral-staircase { - 0% { - transform: rotateY(90deg) translateY(105vh) rotate(0deg) scale(0); - opacity: 0; - } - 40% { - transform: rotateY(90deg) translateY(61vh) rotate(0deg) scale(0); - opacity: 0; - } - 50% { - transform: rotateY(0deg) translateY(55vh) rotate(0deg) scale(0.50); - opacity: 1; - } - 75% { - transform: rotateY(-60deg) translateY(27.5vh) rotate(0deg) scale(1); - opacity: 1; - } - 100% { - transform: rotateY(-90deg) translateY(-5vh) rotate(0deg) scale(1.2); - opacity: 0; - } -}