Browse Source

list page completed

graphics
Cailean Finn 4 months ago
parent
commit
189dbaeede
  1. 4
      app.py
  2. 100
      public/css/styles.css
  3. BIN
      public/images/dither.png
  4. 148
      public/js/list.js
  5. 27
      templates/list.html

4
app.py

@ -20,7 +20,8 @@ def index():
@app.route('/events')
def events():
return render_template('list.html', title='Events')
events = get_all_content('event')
return render_template('list.html', title='Events', content=events)
@app.route('/exhibitions')
def exhibitions():
@ -50,6 +51,7 @@ def get_all_content(type):
}
content_list.append(content)
print(content_list)
return content_list
def format_datetime(dt):
date_str = dt.strftime('%d.%m.%y')

100
public/css/styles.css

@ -21,6 +21,7 @@ body {
white 30%,
rgba(255, 255, 255, 0) 100%),
url('/public/images/skybox.png');
background-position: 0px calc(100vh / 2.2);
background-size: cover;
background-repeat: repeat-x;
}
@ -35,14 +36,21 @@ a {
}
hr {
border: 0;
/* border: 0;
clear:both;
display:block;
background-color:#0075FF;
width: 100%;
height: 2px;
z-index: -1000;
margin: 0; */
clear:both;
display:block;
width: 100%;
margin: 0;
padding: 0;
border: 0;
border-top: medium solid #0075FF;
}
#main-wrapper {
@ -110,6 +118,7 @@ hr {
padding: 10px;
padding-left: 25px;
padding-right: 25px;
font-family: 'Syne Mono', monospace;
}
@ -126,6 +135,89 @@ hr {
z-index: -999;
}
#list-container {
display: flex;
flex-wrap: wrap;
align-items: stretch;
row-gap: 100px;
column-gap: 50px;
justify-content: space-evenly;
padding-top: 40px;
}
.list {
display: flex;
flex-direction: column;
width: 600px;
height: 500px;
gap:10px;
}
.list-image {
width: 100%;
height: 500px;
overflow: hidden;
position: relative;
border-radius: 0px;
margin-bottom: 10px;
}
.list-image img {
width: 100%;
height: 100%;
object-fit: cover;
position: absolute;
top: 0;
left: 0;
}
.list-image-overlay {
position: absolute;
width: calc(100% + .2rem);
height: 100%;
box-shadow: 0 0 .25rem .5rem white inset;
}
.list-title {
font-size: 30px;
color: #0075FF;
font-weight: 600;
font-family: 'Syne Mono', monospace;
}
.list-details {
font-size: 20px;
color: #0075FF;
display: flex;
flex-direction: row;
justify-content: flex-start;
row-gap: 5px;
column-gap: 20px;
flex-wrap: wrap;
font-family: 'Syne Mono', monospace;
}
.list-artists {
font-size: 20px;
font-family: 'Syne Mono', monospace;
color: #0075FF;
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
#page-header {
display: flex;
flex-direction: row;
padding-top: 20px;
padding-bottom: 20px;
padding-left: 50px;
font-size: 30px;
font-family: 'Syne Mono', monospace;
color: #0075FF;
}
/* Tablet breakpoint (768px to 1024px) */
@media (max-width: 1024px) and (min-width: 768px) {
#nav-bar {
@ -164,7 +256,6 @@ hr {
flex-direction: column;
text-align: center;
gap: 5px;
height: 75px;
}
.nav-element {
@ -210,4 +301,9 @@ hr {
#container {
}
#list-container {
padding-left: 20px;
padding-right: 20px;
}
}

BIN
public/images/dither.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

148
public/js/list.js

@ -0,0 +1,148 @@
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPixelatedPass } from 'three/addons/postprocessing/RenderPixelatedPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import { randFloat } from 'three/src/math/MathUtils.js';
let scene, camera, renderer
let aspect, frustumSize
let time = 0
let lastTime = 0
let controls
let mesh
let composer
let cubeGroup = []
let instancedMesh, dummy, count
const texture = new THREE.TextureLoader().load("public/images/dither.png")
texture.minFilter = THREE.NearestFilter
texture.colorSpace = THREE.SRGBColorSpace;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
function init(){
SetupRenderer()
scene = new THREE.Scene()
SetupCamera()
SetupControls()
composer = new EffectComposer( renderer );
const renderPixelatedPass = new RenderPixelatedPass( 8, scene, camera );
renderPixelatedPass.normalEdgeStrength = 0;
renderPixelatedPass.depthEdgeStrength = 1;
renderPixelatedPass.pixelAlignedPanning = false;
composer.addPass( renderPixelatedPass );
const outputPass = new OutputPass();
composer.addPass( outputPass );
SetupCubes()
AddLights()
animate()
}
function SetupCubes() {
const cubeGeometry = new THREE.BoxGeometry();
const cubeMaterial = new THREE.MeshPhongMaterial({ map: texture });
// Create an InstancedMesh
count = 100;
instancedMesh = new THREE.InstancedMesh(cubeGeometry, cubeMaterial, count);
scene.add(instancedMesh)
dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
let size = randFloat(5, 8);
dummy.scale.set(size, size, size);
dummy.position.set(randFloat(-10, 10), randFloat(-6, 3), 0);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
}
function SetupRenderer(){
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
renderer.setClearColor(0xffffff, 0);
renderer.setSize(window.innerWidth, window.innerHeight)
document.getElementById('container').appendChild(renderer.domElement)
}
function SetupCamera(){
aspect = (window.innerWidth) / (window.innerHeight)
frustumSize = 10
camera = new THREE.OrthographicCamera(
frustumSize * aspect / -2,
frustumSize * aspect / 2,
frustumSize / 2,
frustumSize / -2,
0.01,
5000
)
camera.position.x = 5
}
function SetupControls(){
controls = new OrbitControls(camera, renderer.domElement)
controls.enableRotate = false;
controls.enablePan = false
controls.zoomToCursor = false;
controls.mouseButtons = {
RIGHT: THREE.MOUSE.ROTATE,
MIDDLE: THREE.MOUSE.DOLLY,
LEFT: THREE.MOUSE.PAN
}
camera.position.set(0, 0, 20)
controls.update()
}
function AddLights() {
// Add Ambient Light
const ambientLight = new THREE.AmbientLight(0xffffff, 10); // Soft white light
scene.add(ambientLight);
// Add Directional Light
const directionalLight = new THREE.DirectionalLight(0xffffff, 0); // Soft white light
directionalLight.position.set(-5, 0, 5).normalize();
scene.add(directionalLight);
}
const matrix = new THREE.Matrix4()
function animate(){
requestAnimationFrame(animate)
// Rotate instanced meshes
const time = performance.now() * 0.001;
const rotationSpeedX = 0.02;
const rotationSpeedY = 0.01;
lastTime = time
for (let i = 0; i < count; i++) {
instancedMesh.getMatrixAt(i, matrix)
matrix.decompose(dummy.position, dummy.rotation, dummy.scale)
dummy.rotation.set(i/1000 * time, i/1000 * time, i/1000 * time);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true
composer.render()
//renderer.render(scene, camera)
}
window.addEventListener('resize', () => {
aspect = (window.innerWidth) / (window.innerHeight)
camera.left = -frustumSize * aspect / 2
camera.right = frustumSize * aspect / 2
camera.top = frustumSize / 2
camera.bottom = -frustumSize / 2
camera.updateProjectionMatrix()
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
})
init()

27
templates/list.html

@ -5,10 +5,35 @@
{% block content %}
<div id="main-wrapper">
{% include '_nav.html' %}
<div id="page-header">
<div>/{{ title }}</div>
</div>
<hr>
<div id="main-container">
<div id="list-container">
{% for event in content %}
<a href='/'>
<div class="list">
<div class="list-image">
<img src="{{ event.image }}" alt="{{ event.title }}">
<div class="list-image-overlay"></div>
</div>
<div class="list-title">→ {{ event.title }}</div>
<div class="list-artists">
<p>[{{ event.artists | join(', ') }}]</p>
</div>
<div class="list-details">
<div class="list-date">● {{ event.date }}</div>
<div class="list-date">● {{ event.time }}→{{ event.end_time }}</div>
<div class="list-date">● {{ event.location[0] }}</div>
</div>
</div>
</a>
{% endfor %}
</div>
</div>
</div>
<div id="container"></div>
<script type="module" src="{{ url_for('static', filename='js/list.js') }}"></script>
<script type="module" src="{{ url_for('static', filename='js/skybox.js') }}"></script>
{% endblock content %}
Loading…
Cancel
Save