first implementation of new layout
This commit is contained in:
@@ -107,7 +107,7 @@ def profile_view(request, member_id=None):
|
|||||||
logger.info("Wrong member id '{}'".format(member_id))
|
logger.info("Wrong member id '{}'".format(member_id))
|
||||||
raise Http404("no member")
|
raise Http404("no member")
|
||||||
|
|
||||||
jobs = deque(JobMember.members.filter(member__id=member_id))
|
jobs = deque(JobMember.members.filter(member__id=member_id).order_by("job_start"))
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
"pinned_job_groups": pinned_job_groups,
|
"pinned_job_groups": pinned_job_groups,
|
||||||
|
|||||||
2517
fet2020/static/js/alpinejs@3.2.2.js
Normal file
2517
fet2020/static/js/alpinejs@3.2.2.js
Normal file
File diff suppressed because it is too large
Load Diff
484
fet2020/static/js/gumshoe@5.1.1.js
Normal file
484
fet2020/static/js/gumshoe@5.1.1.js
Normal file
@@ -0,0 +1,484 @@
|
|||||||
|
/*!
|
||||||
|
* gumshoejs v5.1.1
|
||||||
|
* A simple, framework-agnostic scrollspy script.
|
||||||
|
* (c) 2019 Chris Ferdinandi
|
||||||
|
* MIT License
|
||||||
|
* http://github.com/cferdinandi/gumshoe
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (root, factory) {
|
||||||
|
if ( typeof define === 'function' && define.amd ) {
|
||||||
|
define([], (function () {
|
||||||
|
return factory(root);
|
||||||
|
}));
|
||||||
|
} else if ( typeof exports === 'object' ) {
|
||||||
|
module.exports = factory(root);
|
||||||
|
} else {
|
||||||
|
root.Gumshoe = factory(root);
|
||||||
|
}
|
||||||
|
})(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, (function (window) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Defaults
|
||||||
|
//
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
|
||||||
|
// Active classes
|
||||||
|
navClass: 'active',
|
||||||
|
contentClass: 'active',
|
||||||
|
|
||||||
|
// Nested navigation
|
||||||
|
nested: false,
|
||||||
|
nestedClass: 'active',
|
||||||
|
|
||||||
|
// Offset & reflow
|
||||||
|
offset: 0,
|
||||||
|
reflow: false,
|
||||||
|
|
||||||
|
// Event support
|
||||||
|
events: true
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge two or more objects together.
|
||||||
|
* @param {Object} objects The objects to merge together
|
||||||
|
* @returns {Object} Merged values of defaults and options
|
||||||
|
*/
|
||||||
|
var extend = function () {
|
||||||
|
var merged = {};
|
||||||
|
Array.prototype.forEach.call(arguments, (function (obj) {
|
||||||
|
for (var key in obj) {
|
||||||
|
if (!obj.hasOwnProperty(key)) return;
|
||||||
|
merged[key] = obj[key];
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return merged;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a custom event
|
||||||
|
* @param {String} type The event type
|
||||||
|
* @param {Node} elem The element to attach the event to
|
||||||
|
* @param {Object} detail Any details to pass along with the event
|
||||||
|
*/
|
||||||
|
var emitEvent = function (type, elem, detail) {
|
||||||
|
|
||||||
|
// Make sure events are enabled
|
||||||
|
if (!detail.settings.events) return;
|
||||||
|
|
||||||
|
// Create a new event
|
||||||
|
var event = new CustomEvent(type, {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
detail: detail
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dispatch the event
|
||||||
|
elem.dispatchEvent(event);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an element's distance from the top of the Document.
|
||||||
|
* @param {Node} elem The element
|
||||||
|
* @return {Number} Distance from the top in pixels
|
||||||
|
*/
|
||||||
|
var getOffsetTop = function (elem) {
|
||||||
|
var location = 0;
|
||||||
|
if (elem.offsetParent) {
|
||||||
|
while (elem) {
|
||||||
|
location += elem.offsetTop;
|
||||||
|
elem = elem.offsetParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return location >= 0 ? location : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort content from first to last in the DOM
|
||||||
|
* @param {Array} contents The content areas
|
||||||
|
*/
|
||||||
|
var sortContents = function (contents) {
|
||||||
|
if(contents) {
|
||||||
|
contents.sort((function (item1, item2) {
|
||||||
|
var offset1 = getOffsetTop(item1.content);
|
||||||
|
var offset2 = getOffsetTop(item2.content);
|
||||||
|
if (offset1 < offset2) return -1;
|
||||||
|
return 1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the offset to use for calculating position
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
* @return {Float} The number of pixels to offset the calculations
|
||||||
|
*/
|
||||||
|
var getOffset = function (settings) {
|
||||||
|
|
||||||
|
// if the offset is a function run it
|
||||||
|
if (typeof settings.offset === 'function') {
|
||||||
|
return parseFloat(settings.offset());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, return it as-is
|
||||||
|
return parseFloat(settings.offset);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the document element's height
|
||||||
|
* @private
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
var getDocumentHeight = function () {
|
||||||
|
return Math.max(
|
||||||
|
document.body.scrollHeight, document.documentElement.scrollHeight,
|
||||||
|
document.body.offsetHeight, document.documentElement.offsetHeight,
|
||||||
|
document.body.clientHeight, document.documentElement.clientHeight
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if an element is in view
|
||||||
|
* @param {Node} elem The element
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
* @param {Boolean} bottom If true, check if element is above bottom of viewport instead
|
||||||
|
* @return {Boolean} Returns true if element is in the viewport
|
||||||
|
*/
|
||||||
|
var isInView = function (elem, settings, bottom) {
|
||||||
|
var bounds = elem.getBoundingClientRect();
|
||||||
|
var offset = getOffset(settings);
|
||||||
|
if (bottom) {
|
||||||
|
return parseInt(bounds.bottom, 10) < (window.innerHeight || document.documentElement.clientHeight);
|
||||||
|
}
|
||||||
|
return parseInt(bounds.top, 10) <= offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if at the bottom of the viewport
|
||||||
|
* @return {Boolean} If true, page is at the bottom of the viewport
|
||||||
|
*/
|
||||||
|
var isAtBottom = function () {
|
||||||
|
if (window.innerHeight + window.pageYOffset >= getDocumentHeight()) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the last item should be used (even if not at the top of the page)
|
||||||
|
* @param {Object} item The last item
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
* @return {Boolean} If true, use the last item
|
||||||
|
*/
|
||||||
|
var useLastItem = function (item, settings) {
|
||||||
|
if (isAtBottom() && isInView(item.content, settings, true)) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the active content
|
||||||
|
* @param {Array} contents The content areas
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
* @return {Object} The content area and matching navigation link
|
||||||
|
*/
|
||||||
|
var getActive = function (contents, settings) {
|
||||||
|
var last = contents[contents.length-1];
|
||||||
|
if (useLastItem(last, settings)) return last;
|
||||||
|
for (var i = contents.length - 1; i >= 0; i--) {
|
||||||
|
if (isInView(contents[i].content, settings)) return contents[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate parent navs in a nested navigation
|
||||||
|
* @param {Node} nav The starting navigation element
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
*/
|
||||||
|
var deactivateNested = function (nav, settings) {
|
||||||
|
|
||||||
|
// If nesting isn't activated, bail
|
||||||
|
if (!settings.nested) return;
|
||||||
|
|
||||||
|
// Get the parent navigation
|
||||||
|
var li = nav.parentNode.closest('li');
|
||||||
|
if (!li) return;
|
||||||
|
|
||||||
|
// Remove the active class
|
||||||
|
li.classList.remove(settings.nestedClass);
|
||||||
|
|
||||||
|
// Apply recursively to any parent navigation elements
|
||||||
|
deactivateNested(li, settings);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deactivate a nav and content area
|
||||||
|
* @param {Object} items The nav item and content to deactivate
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
*/
|
||||||
|
var deactivate = function (items, settings) {
|
||||||
|
|
||||||
|
// Make sure their are items to deactivate
|
||||||
|
if (!items) return;
|
||||||
|
|
||||||
|
// Get the parent list item
|
||||||
|
var li = items.nav.closest('li');
|
||||||
|
if (!li) return;
|
||||||
|
|
||||||
|
// Remove the active class from the nav and content
|
||||||
|
li.classList.remove(settings.navClass);
|
||||||
|
items.content.classList.remove(settings.contentClass);
|
||||||
|
|
||||||
|
// Deactivate any parent navs in a nested navigation
|
||||||
|
deactivateNested(li, settings);
|
||||||
|
|
||||||
|
// Emit a custom event
|
||||||
|
emitEvent('gumshoeDeactivate', li, {
|
||||||
|
link: items.nav,
|
||||||
|
content: items.content,
|
||||||
|
settings: settings
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate parent navs in a nested navigation
|
||||||
|
* @param {Node} nav The starting navigation element
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
*/
|
||||||
|
var activateNested = function (nav, settings) {
|
||||||
|
|
||||||
|
// If nesting isn't activated, bail
|
||||||
|
if (!settings.nested) return;
|
||||||
|
|
||||||
|
// Get the parent navigation
|
||||||
|
var li = nav.parentNode.closest('li');
|
||||||
|
if (!li) return;
|
||||||
|
|
||||||
|
// Add the active class
|
||||||
|
li.classList.add(settings.nestedClass);
|
||||||
|
|
||||||
|
// Apply recursively to any parent navigation elements
|
||||||
|
activateNested(li, settings);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate a nav and content area
|
||||||
|
* @param {Object} items The nav item and content to activate
|
||||||
|
* @param {Object} settings The settings for this instantiation
|
||||||
|
*/
|
||||||
|
var activate = function (items, settings) {
|
||||||
|
|
||||||
|
// Make sure their are items to activate
|
||||||
|
if (!items) return;
|
||||||
|
|
||||||
|
// Get the parent list item
|
||||||
|
var li = items.nav.closest('li');
|
||||||
|
if (!li) return;
|
||||||
|
|
||||||
|
// Add the active class to the nav and content
|
||||||
|
li.classList.add(settings.navClass);
|
||||||
|
items.content.classList.add(settings.contentClass);
|
||||||
|
|
||||||
|
// Activate any parent navs in a nested navigation
|
||||||
|
activateNested(li, settings);
|
||||||
|
|
||||||
|
// Emit a custom event
|
||||||
|
emitEvent('gumshoeActivate', li, {
|
||||||
|
link: items.nav,
|
||||||
|
content: items.content,
|
||||||
|
settings: settings
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the Constructor object
|
||||||
|
* @param {String} selector The selector to use for navigation items
|
||||||
|
* @param {Object} options User options and settings
|
||||||
|
*/
|
||||||
|
var Constructor = function (selector, options) {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Variables
|
||||||
|
//
|
||||||
|
|
||||||
|
var publicAPIs = {};
|
||||||
|
var navItems, contents, current, timeout, settings;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set variables from DOM elements
|
||||||
|
*/
|
||||||
|
publicAPIs.setup = function () {
|
||||||
|
|
||||||
|
// Get all nav items
|
||||||
|
navItems = document.querySelectorAll(selector);
|
||||||
|
|
||||||
|
// Create contents array
|
||||||
|
contents = [];
|
||||||
|
|
||||||
|
// Loop through each item, get it's matching content, and push to the array
|
||||||
|
Array.prototype.forEach.call(navItems, (function (item) {
|
||||||
|
|
||||||
|
// Get the content for the nav item
|
||||||
|
var content = document.getElementById(decodeURIComponent(item.hash.substr(1)));
|
||||||
|
if (!content) return;
|
||||||
|
|
||||||
|
// Push to the contents array
|
||||||
|
contents.push({
|
||||||
|
nav: item,
|
||||||
|
content: content
|
||||||
|
});
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Sort contents by the order they appear in the DOM
|
||||||
|
sortContents(contents);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect which content is currently active
|
||||||
|
*/
|
||||||
|
publicAPIs.detect = function () {
|
||||||
|
|
||||||
|
// Get the active content
|
||||||
|
var active = getActive(contents, settings);
|
||||||
|
|
||||||
|
// if there's no active content, deactivate and bail
|
||||||
|
if (!active) {
|
||||||
|
if (current) {
|
||||||
|
deactivate(current, settings);
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the active content is the one currently active, do nothing
|
||||||
|
if (current && active.content === current.content) return;
|
||||||
|
|
||||||
|
// Deactivate the current content and activate the new content
|
||||||
|
deactivate(current, settings);
|
||||||
|
activate(active, settings);
|
||||||
|
|
||||||
|
// Update the currently active content
|
||||||
|
current = active;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect the active content on scroll
|
||||||
|
* Debounced for performance
|
||||||
|
*/
|
||||||
|
var scrollHandler = function (event) {
|
||||||
|
|
||||||
|
// If there's a timer, cancel it
|
||||||
|
if (timeout) {
|
||||||
|
window.cancelAnimationFrame(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup debounce callback
|
||||||
|
timeout = window.requestAnimationFrame(publicAPIs.detect);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update content sorting on resize
|
||||||
|
* Debounced for performance
|
||||||
|
*/
|
||||||
|
var resizeHandler = function (event) {
|
||||||
|
|
||||||
|
// If there's a timer, cancel it
|
||||||
|
if (timeout) {
|
||||||
|
window.cancelAnimationFrame(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup debounce callback
|
||||||
|
timeout = window.requestAnimationFrame((function () {
|
||||||
|
sortContents(contents);
|
||||||
|
publicAPIs.detect();
|
||||||
|
}));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the current instantiation
|
||||||
|
*/
|
||||||
|
publicAPIs.destroy = function () {
|
||||||
|
|
||||||
|
// Undo DOM changes
|
||||||
|
if (current) {
|
||||||
|
deactivate(current, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove event listeners
|
||||||
|
window.removeEventListener('scroll', scrollHandler, false);
|
||||||
|
if (settings.reflow) {
|
||||||
|
window.removeEventListener('resize', resizeHandler, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset variables
|
||||||
|
contents = null;
|
||||||
|
navItems = null;
|
||||||
|
current = null;
|
||||||
|
timeout = null;
|
||||||
|
settings = null;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the current instantiation
|
||||||
|
*/
|
||||||
|
var init = function () {
|
||||||
|
|
||||||
|
// Merge user options into defaults
|
||||||
|
settings = extend(defaults, options || {});
|
||||||
|
|
||||||
|
// Setup variables based on the current DOM
|
||||||
|
publicAPIs.setup();
|
||||||
|
|
||||||
|
// Find the currently active content
|
||||||
|
publicAPIs.detect();
|
||||||
|
|
||||||
|
// Setup event listeners
|
||||||
|
window.addEventListener('scroll', scrollHandler, false);
|
||||||
|
if (settings.reflow) {
|
||||||
|
window.addEventListener('resize', resizeHandler, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize and return the public APIs
|
||||||
|
//
|
||||||
|
|
||||||
|
init();
|
||||||
|
return publicAPIs;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the Constructor
|
||||||
|
//
|
||||||
|
|
||||||
|
return Constructor;
|
||||||
|
|
||||||
|
}));
|
||||||
36
fet2020/static/js/scripts.js
Normal file
36
fet2020/static/js/scripts.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Open article on click without an anchor-tag.
|
||||||
|
function openArticle(link){
|
||||||
|
window.location.href=link;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cookieSet("InfoBoxHidden")){
|
||||||
|
let element = document.getElementById("infoBox");
|
||||||
|
element.classList.toggle("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideInfoBox(){
|
||||||
|
let element = document.getElementById("infoBox");
|
||||||
|
element.classList.toggle("hidden");
|
||||||
|
|
||||||
|
let exMinutes = 2; // Gültigkeit des Cookies in Tagen
|
||||||
|
const d = new Date();
|
||||||
|
d.setTime(d.getTime() + (exMinutes*60*1000));
|
||||||
|
let expires = "expires="+ d.toUTCString();
|
||||||
|
document.cookie = "InfoBoxHidden=true; expires=" + expires + ";path=/;SameSite=Strict";
|
||||||
|
}
|
||||||
|
|
||||||
|
function cookieSet(cname) {
|
||||||
|
let name = cname + "=";
|
||||||
|
let decodedCookie = decodeURIComponent(document.cookie);
|
||||||
|
let ca = decodedCookie.split(';');
|
||||||
|
for(let i = 0; i < ca.length; i++) {
|
||||||
|
let c = ca[i];
|
||||||
|
while (c.charAt(0) == ' ') {
|
||||||
|
c = c.substring(1);
|
||||||
|
}
|
||||||
|
if (c.indexOf(name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
650
fet2020/static/js/smooth-scroll@16.1.2.js
Normal file
650
fet2020/static/js/smooth-scroll@16.1.2.js
Normal file
@@ -0,0 +1,650 @@
|
|||||||
|
/*!
|
||||||
|
* smooth-scroll v16.1.2
|
||||||
|
* Animate scrolling to anchor links
|
||||||
|
* (c) 2020 Chris Ferdinandi
|
||||||
|
* MIT License
|
||||||
|
* http://github.com/cferdinandi/smooth-scroll
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (root, factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
define([], (function () {
|
||||||
|
return factory(root);
|
||||||
|
}));
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
module.exports = factory(root);
|
||||||
|
} else {
|
||||||
|
root.SmoothScroll = factory(root);
|
||||||
|
}
|
||||||
|
})(typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this, (function (window) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Default settings
|
||||||
|
//
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
|
||||||
|
// Selectors
|
||||||
|
ignore: '[data-scroll-ignore]',
|
||||||
|
header: null,
|
||||||
|
topOnEmptyHash: true,
|
||||||
|
|
||||||
|
// Speed & Duration
|
||||||
|
speed: 500,
|
||||||
|
speedAsDuration: false,
|
||||||
|
durationMax: null,
|
||||||
|
durationMin: null,
|
||||||
|
clip: true,
|
||||||
|
offset: 0,
|
||||||
|
|
||||||
|
// Easing
|
||||||
|
easing: 'easeInOutCubic',
|
||||||
|
customEasing: null,
|
||||||
|
|
||||||
|
// History
|
||||||
|
updateURL: true,
|
||||||
|
popstate: true,
|
||||||
|
|
||||||
|
// Custom Events
|
||||||
|
emitEvents: true
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Utility Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if browser supports required methods
|
||||||
|
* @return {Boolean} Returns true if all required methods are supported
|
||||||
|
*/
|
||||||
|
var supports = function () {
|
||||||
|
return (
|
||||||
|
'querySelector' in document &&
|
||||||
|
'addEventListener' in window &&
|
||||||
|
'requestAnimationFrame' in window &&
|
||||||
|
'closest' in window.Element.prototype
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge two or more objects together.
|
||||||
|
* @param {Object} objects The objects to merge together
|
||||||
|
* @returns {Object} Merged values of defaults and options
|
||||||
|
*/
|
||||||
|
var extend = function () {
|
||||||
|
var merged = {};
|
||||||
|
Array.prototype.forEach.call(arguments, (function (obj) {
|
||||||
|
for (var key in obj) {
|
||||||
|
if (!obj.hasOwnProperty(key)) return;
|
||||||
|
merged[key] = obj[key];
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return merged;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if user prefers reduced motion
|
||||||
|
* @param {Object} settings Script settings
|
||||||
|
*/
|
||||||
|
var reduceMotion = function () {
|
||||||
|
if ('matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the height of an element.
|
||||||
|
* @param {Node} elem The element to get the height of
|
||||||
|
* @return {Number} The element's height in pixels
|
||||||
|
*/
|
||||||
|
var getHeight = function (elem) {
|
||||||
|
return parseInt(window.getComputedStyle(elem).height, 10);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape special characters for use with querySelector
|
||||||
|
* @author Mathias Bynens
|
||||||
|
* @link https://github.com/mathiasbynens/CSS.escape
|
||||||
|
* @param {String} id The anchor ID to escape
|
||||||
|
*/
|
||||||
|
var escapeCharacters = function (id) {
|
||||||
|
|
||||||
|
// Remove leading hash
|
||||||
|
if (id.charAt(0) === '#') {
|
||||||
|
id = id.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var string = String(id);
|
||||||
|
var length = string.length;
|
||||||
|
var index = -1;
|
||||||
|
var codeUnit;
|
||||||
|
var result = '';
|
||||||
|
var firstCodeUnit = string.charCodeAt(0);
|
||||||
|
while (++index < length) {
|
||||||
|
codeUnit = string.charCodeAt(index);
|
||||||
|
// Note: there’s no need to special-case astral symbols, surrogate
|
||||||
|
// pairs, or lone surrogates.
|
||||||
|
|
||||||
|
// If the character is NULL (U+0000), then throw an
|
||||||
|
// `InvalidCharacterError` exception and terminate these steps.
|
||||||
|
if (codeUnit === 0x0000) {
|
||||||
|
throw new InvalidCharacterError(
|
||||||
|
'Invalid character: the input contains U+0000.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
|
||||||
|
// U+007F, […]
|
||||||
|
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
|
||||||
|
// If the character is the first character and is in the range [0-9]
|
||||||
|
// (U+0030 to U+0039), […]
|
||||||
|
(index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
|
||||||
|
// If the character is the second character and is in the range [0-9]
|
||||||
|
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
|
||||||
|
(
|
||||||
|
index === 1 &&
|
||||||
|
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
|
||||||
|
firstCodeUnit === 0x002D
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// http://dev.w3.org/csswg/cssom/#escape-a-character-as-code-point
|
||||||
|
result += '\\' + codeUnit.toString(16) + ' ';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the character is not handled by one of the above rules and is
|
||||||
|
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
|
||||||
|
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
|
||||||
|
// U+005A), or [a-z] (U+0061 to U+007A), […]
|
||||||
|
if (
|
||||||
|
codeUnit >= 0x0080 ||
|
||||||
|
codeUnit === 0x002D ||
|
||||||
|
codeUnit === 0x005F ||
|
||||||
|
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
|
||||||
|
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
|
||||||
|
codeUnit >= 0x0061 && codeUnit <= 0x007A
|
||||||
|
) {
|
||||||
|
// the character itself
|
||||||
|
result += string.charAt(index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the escaped character.
|
||||||
|
// http://dev.w3.org/csswg/cssom/#escape-a-character
|
||||||
|
result += '\\' + string.charAt(index);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return sanitized hash
|
||||||
|
return '#' + result;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the easing pattern
|
||||||
|
* @link https://gist.github.com/gre/1650294
|
||||||
|
* @param {String} type Easing pattern
|
||||||
|
* @param {Number} time Time animation should take to complete
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
var easingPattern = function (settings, time) {
|
||||||
|
var pattern;
|
||||||
|
|
||||||
|
// Default Easing Patterns
|
||||||
|
if (settings.easing === 'easeInQuad') pattern = time * time; // accelerating from zero velocity
|
||||||
|
if (settings.easing === 'easeOutQuad') pattern = time * (2 - time); // decelerating to zero velocity
|
||||||
|
if (settings.easing === 'easeInOutQuad') pattern = time < 0.5 ? 2 * time * time : -1 + (4 - 2 * time) * time; // acceleration until halfway, then deceleration
|
||||||
|
if (settings.easing === 'easeInCubic') pattern = time * time * time; // accelerating from zero velocity
|
||||||
|
if (settings.easing === 'easeOutCubic') pattern = (--time) * time * time + 1; // decelerating to zero velocity
|
||||||
|
if (settings.easing === 'easeInOutCubic') pattern = time < 0.5 ? 4 * time * time * time : (time - 1) * (2 * time - 2) * (2 * time - 2) + 1; // acceleration until halfway, then deceleration
|
||||||
|
if (settings.easing === 'easeInQuart') pattern = time * time * time * time; // accelerating from zero velocity
|
||||||
|
if (settings.easing === 'easeOutQuart') pattern = 1 - (--time) * time * time * time; // decelerating to zero velocity
|
||||||
|
if (settings.easing === 'easeInOutQuart') pattern = time < 0.5 ? 8 * time * time * time * time : 1 - 8 * (--time) * time * time * time; // acceleration until halfway, then deceleration
|
||||||
|
if (settings.easing === 'easeInQuint') pattern = time * time * time * time * time; // accelerating from zero velocity
|
||||||
|
if (settings.easing === 'easeOutQuint') pattern = 1 + (--time) * time * time * time * time; // decelerating to zero velocity
|
||||||
|
if (settings.easing === 'easeInOutQuint') pattern = time < 0.5 ? 16 * time * time * time * time * time : 1 + 16 * (--time) * time * time * time * time; // acceleration until halfway, then deceleration
|
||||||
|
|
||||||
|
// Custom Easing Patterns
|
||||||
|
if (!!settings.customEasing) pattern = settings.customEasing(time);
|
||||||
|
|
||||||
|
return pattern || time; // no easing, no acceleration
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the document's height
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
var getDocumentHeight = function () {
|
||||||
|
return Math.max(
|
||||||
|
document.body.scrollHeight, document.documentElement.scrollHeight,
|
||||||
|
document.body.offsetHeight, document.documentElement.offsetHeight,
|
||||||
|
document.body.clientHeight, document.documentElement.clientHeight
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate how far to scroll
|
||||||
|
* Clip support added by robjtede - https://github.com/cferdinandi/smooth-scroll/issues/405
|
||||||
|
* @param {Element} anchor The anchor element to scroll to
|
||||||
|
* @param {Number} headerHeight Height of a fixed header, if any
|
||||||
|
* @param {Number} offset Number of pixels by which to offset scroll
|
||||||
|
* @param {Boolean} clip If true, adjust scroll distance to prevent abrupt stops near the bottom of the page
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
var getEndLocation = function (anchor, headerHeight, offset, clip) {
|
||||||
|
var location = 0;
|
||||||
|
if (anchor.offsetParent) {
|
||||||
|
do {
|
||||||
|
location += anchor.offsetTop;
|
||||||
|
anchor = anchor.offsetParent;
|
||||||
|
} while (anchor);
|
||||||
|
}
|
||||||
|
location = Math.max(location - headerHeight - offset, 0);
|
||||||
|
if (clip) {
|
||||||
|
location = Math.min(location, getDocumentHeight() - window.innerHeight);
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the height of the fixed header
|
||||||
|
* @param {Node} header The header
|
||||||
|
* @return {Number} The height of the header
|
||||||
|
*/
|
||||||
|
var getHeaderHeight = function (header) {
|
||||||
|
return !header ? 0 : (getHeight(header) + header.offsetTop);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the speed to use for the animation
|
||||||
|
* @param {Number} distance The distance to travel
|
||||||
|
* @param {Object} settings The plugin settings
|
||||||
|
* @return {Number} How fast to animate
|
||||||
|
*/
|
||||||
|
var getSpeed = function (distance, settings) {
|
||||||
|
var speed = settings.speedAsDuration ? settings.speed : Math.abs(distance / 1000 * settings.speed);
|
||||||
|
if (settings.durationMax && speed > settings.durationMax) return settings.durationMax;
|
||||||
|
if (settings.durationMin && speed < settings.durationMin) return settings.durationMin;
|
||||||
|
return parseInt(speed, 10);
|
||||||
|
};
|
||||||
|
|
||||||
|
var setHistory = function (options) {
|
||||||
|
|
||||||
|
// Make sure this should run
|
||||||
|
if (!history.replaceState || !options.updateURL || history.state) return;
|
||||||
|
|
||||||
|
// Get the hash to use
|
||||||
|
var hash = window.location.hash;
|
||||||
|
hash = hash ? hash : '';
|
||||||
|
|
||||||
|
// Set a default history
|
||||||
|
history.replaceState(
|
||||||
|
{
|
||||||
|
smoothScroll: JSON.stringify(options),
|
||||||
|
anchor: hash ? hash : window.pageYOffset
|
||||||
|
},
|
||||||
|
document.title,
|
||||||
|
hash ? hash : window.location.href
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the URL
|
||||||
|
* @param {Node} anchor The anchor that was scrolled to
|
||||||
|
* @param {Boolean} isNum If true, anchor is a number
|
||||||
|
* @param {Object} options Settings for Smooth Scroll
|
||||||
|
*/
|
||||||
|
var updateURL = function (anchor, isNum, options) {
|
||||||
|
|
||||||
|
// Bail if the anchor is a number
|
||||||
|
if (isNum) return;
|
||||||
|
|
||||||
|
// Verify that pushState is supported and the updateURL option is enabled
|
||||||
|
if (!history.pushState || !options.updateURL) return;
|
||||||
|
|
||||||
|
// Update URL
|
||||||
|
history.pushState(
|
||||||
|
{
|
||||||
|
smoothScroll: JSON.stringify(options),
|
||||||
|
anchor: anchor.id
|
||||||
|
},
|
||||||
|
document.title,
|
||||||
|
anchor === document.documentElement ? '#top' : '#' + anchor.id
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bring the anchored element into focus
|
||||||
|
* @param {Node} anchor The anchor element
|
||||||
|
* @param {Number} endLocation The end location to scroll to
|
||||||
|
* @param {Boolean} isNum If true, scroll is to a position rather than an element
|
||||||
|
*/
|
||||||
|
var adjustFocus = function (anchor, endLocation, isNum) {
|
||||||
|
|
||||||
|
// Is scrolling to top of page, blur
|
||||||
|
if (anchor === 0) {
|
||||||
|
document.body.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't run if scrolling to a number on the page
|
||||||
|
if (isNum) return;
|
||||||
|
|
||||||
|
// Otherwise, bring anchor element into focus
|
||||||
|
anchor.focus();
|
||||||
|
if (document.activeElement !== anchor) {
|
||||||
|
anchor.setAttribute('tabindex', '-1');
|
||||||
|
anchor.focus();
|
||||||
|
anchor.style.outline = 'none';
|
||||||
|
}
|
||||||
|
window.scrollTo(0 , endLocation);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit a custom event
|
||||||
|
* @param {String} type The event type
|
||||||
|
* @param {Object} options The settings object
|
||||||
|
* @param {Node} anchor The anchor element
|
||||||
|
* @param {Node} toggle The toggle element
|
||||||
|
*/
|
||||||
|
var emitEvent = function (type, options, anchor, toggle) {
|
||||||
|
if (!options.emitEvents || typeof window.CustomEvent !== 'function') return;
|
||||||
|
var event = new CustomEvent(type, {
|
||||||
|
bubbles: true,
|
||||||
|
detail: {
|
||||||
|
anchor: anchor,
|
||||||
|
toggle: toggle
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// SmoothScroll Constructor
|
||||||
|
//
|
||||||
|
|
||||||
|
var SmoothScroll = function (selector, options) {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Variables
|
||||||
|
//
|
||||||
|
|
||||||
|
var smoothScroll = {}; // Object for public APIs
|
||||||
|
var settings, anchor, toggle, fixedHeader, eventTimeout, animationInterval;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel a scroll-in-progress
|
||||||
|
*/
|
||||||
|
smoothScroll.cancelScroll = function (noEvent) {
|
||||||
|
cancelAnimationFrame(animationInterval);
|
||||||
|
animationInterval = null;
|
||||||
|
if (noEvent) return;
|
||||||
|
emitEvent('scrollCancel', settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start/stop the scrolling animation
|
||||||
|
* @param {Node|Number} anchor The element or position to scroll to
|
||||||
|
* @param {Element} toggle The element that toggled the scroll event
|
||||||
|
* @param {Object} options
|
||||||
|
*/
|
||||||
|
smoothScroll.animateScroll = function (anchor, toggle, options) {
|
||||||
|
|
||||||
|
// Cancel any in progress scrolls
|
||||||
|
smoothScroll.cancelScroll();
|
||||||
|
|
||||||
|
// Local settings
|
||||||
|
var _settings = extend(settings || defaults, options || {}); // Merge user options with defaults
|
||||||
|
|
||||||
|
// Selectors and variables
|
||||||
|
var isNum = Object.prototype.toString.call(anchor) === '[object Number]' ? true : false;
|
||||||
|
var anchorElem = isNum || !anchor.tagName ? null : anchor;
|
||||||
|
if (!isNum && !anchorElem) return;
|
||||||
|
var startLocation = window.pageYOffset; // Current location on the page
|
||||||
|
if (_settings.header && !fixedHeader) {
|
||||||
|
// Get the fixed header if not already set
|
||||||
|
fixedHeader = document.querySelector(_settings.header);
|
||||||
|
}
|
||||||
|
var headerHeight = getHeaderHeight(fixedHeader);
|
||||||
|
var endLocation = isNum ? anchor : getEndLocation(anchorElem, headerHeight, parseInt((typeof _settings.offset === 'function' ? _settings.offset(anchor, toggle) : _settings.offset), 10), _settings.clip); // Location to scroll to
|
||||||
|
var distance = endLocation - startLocation; // distance to travel
|
||||||
|
var documentHeight = getDocumentHeight();
|
||||||
|
var timeLapsed = 0;
|
||||||
|
var speed = getSpeed(distance, _settings);
|
||||||
|
var start, percentage, position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the scroll animation when it reaches its target (or the bottom/top of page)
|
||||||
|
* @param {Number} position Current position on the page
|
||||||
|
* @param {Number} endLocation Scroll to location
|
||||||
|
* @param {Number} animationInterval How much to scroll on this loop
|
||||||
|
*/
|
||||||
|
var stopAnimateScroll = function (position, endLocation) {
|
||||||
|
|
||||||
|
// Get the current location
|
||||||
|
var currentLocation = window.pageYOffset;
|
||||||
|
|
||||||
|
// Check if the end location has been reached yet (or we've hit the end of the document)
|
||||||
|
if (position == endLocation || currentLocation == endLocation || ((startLocation < endLocation && window.innerHeight + currentLocation) >= documentHeight)) {
|
||||||
|
|
||||||
|
// Clear the animation timer
|
||||||
|
smoothScroll.cancelScroll(true);
|
||||||
|
|
||||||
|
// Bring the anchored element into focus
|
||||||
|
adjustFocus(anchor, endLocation, isNum);
|
||||||
|
|
||||||
|
// Emit a custom event
|
||||||
|
emitEvent('scrollStop', _settings, anchor, toggle);
|
||||||
|
|
||||||
|
// Reset start
|
||||||
|
start = null;
|
||||||
|
animationInterval = null;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop scrolling animation
|
||||||
|
*/
|
||||||
|
var loopAnimateScroll = function (timestamp) {
|
||||||
|
if (!start) { start = timestamp; }
|
||||||
|
timeLapsed += timestamp - start;
|
||||||
|
percentage = speed === 0 ? 0 : (timeLapsed / speed);
|
||||||
|
percentage = (percentage > 1) ? 1 : percentage;
|
||||||
|
position = startLocation + (distance * easingPattern(_settings, percentage));
|
||||||
|
window.scrollTo(0, Math.floor(position));
|
||||||
|
if (!stopAnimateScroll(position, endLocation)) {
|
||||||
|
animationInterval = window.requestAnimationFrame(loopAnimateScroll);
|
||||||
|
start = timestamp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset position to fix weird iOS bug
|
||||||
|
* @link https://github.com/cferdinandi/smooth-scroll/issues/45
|
||||||
|
*/
|
||||||
|
if (window.pageYOffset === 0) {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the URL
|
||||||
|
updateURL(anchor, isNum, _settings);
|
||||||
|
|
||||||
|
// If the user prefers reduced motion, jump to location
|
||||||
|
if (reduceMotion()) {
|
||||||
|
window.scrollTo(0, Math.floor(endLocation));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit a custom event
|
||||||
|
emitEvent('scrollStart', _settings, anchor, toggle);
|
||||||
|
|
||||||
|
// Start scrolling animation
|
||||||
|
smoothScroll.cancelScroll(true);
|
||||||
|
window.requestAnimationFrame(loopAnimateScroll);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If smooth scroll element clicked, animate scroll
|
||||||
|
*/
|
||||||
|
var clickHandler = function (event) {
|
||||||
|
|
||||||
|
// Don't run if event was canceled but still bubbled up
|
||||||
|
// By @mgreter - https://github.com/cferdinandi/smooth-scroll/pull/462/
|
||||||
|
if (event.defaultPrevented) return;
|
||||||
|
|
||||||
|
// Don't run if right-click or command/control + click or shift + click
|
||||||
|
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey) return;
|
||||||
|
|
||||||
|
// Check if event.target has closest() method
|
||||||
|
// By @totegi - https://github.com/cferdinandi/smooth-scroll/pull/401/
|
||||||
|
if (!('closest' in event.target)) return;
|
||||||
|
|
||||||
|
// Check if a smooth scroll link was clicked
|
||||||
|
toggle = event.target.closest(selector);
|
||||||
|
if (!toggle || toggle.tagName.toLowerCase() !== 'a' || event.target.closest(settings.ignore)) return;
|
||||||
|
|
||||||
|
// Only run if link is an anchor and points to the current page
|
||||||
|
if (toggle.hostname !== window.location.hostname || toggle.pathname !== window.location.pathname || !/#/.test(toggle.href)) return;
|
||||||
|
|
||||||
|
// Get an escaped version of the hash
|
||||||
|
var hash;
|
||||||
|
try {
|
||||||
|
hash = escapeCharacters(decodeURIComponent(toggle.hash));
|
||||||
|
} catch(e) {
|
||||||
|
hash = escapeCharacters(toggle.hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the anchored element
|
||||||
|
var anchor;
|
||||||
|
if (hash === '#') {
|
||||||
|
if (!settings.topOnEmptyHash) return;
|
||||||
|
anchor = document.documentElement;
|
||||||
|
} else {
|
||||||
|
anchor = document.querySelector(hash);
|
||||||
|
}
|
||||||
|
anchor = !anchor && hash === '#top' ? document.documentElement : anchor;
|
||||||
|
|
||||||
|
// If anchored element exists, scroll to it
|
||||||
|
if (!anchor) return;
|
||||||
|
event.preventDefault();
|
||||||
|
setHistory(settings);
|
||||||
|
smoothScroll.animateScroll(anchor, toggle);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate scroll on popstate events
|
||||||
|
*/
|
||||||
|
var popstateHandler = function (event) {
|
||||||
|
|
||||||
|
// Stop if history.state doesn't exist (ex. if clicking on a broken anchor link).
|
||||||
|
// fixes `Cannot read property 'smoothScroll' of null` error getting thrown.
|
||||||
|
if (history.state === null) return;
|
||||||
|
|
||||||
|
// Only run if state is a popstate record for this instantiation
|
||||||
|
if (!history.state.smoothScroll || history.state.smoothScroll !== JSON.stringify(settings)) return;
|
||||||
|
|
||||||
|
// Only run if state includes an anchor
|
||||||
|
|
||||||
|
// if (!history.state.anchor && history.state.anchor !== 0) return;
|
||||||
|
|
||||||
|
// Get the anchor
|
||||||
|
var anchor = history.state.anchor;
|
||||||
|
if (typeof anchor === 'string' && anchor) {
|
||||||
|
anchor = document.querySelector(escapeCharacters(history.state.anchor));
|
||||||
|
if (!anchor) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animate scroll to anchor link
|
||||||
|
smoothScroll.animateScroll(anchor, null, {updateURL: false});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the current initialization.
|
||||||
|
*/
|
||||||
|
smoothScroll.destroy = function () {
|
||||||
|
|
||||||
|
// If plugin isn't already initialized, stop
|
||||||
|
if (!settings) return;
|
||||||
|
|
||||||
|
// Remove event listeners
|
||||||
|
document.removeEventListener('click', clickHandler, false);
|
||||||
|
window.removeEventListener('popstate', popstateHandler, false);
|
||||||
|
|
||||||
|
// Cancel any scrolls-in-progress
|
||||||
|
smoothScroll.cancelScroll();
|
||||||
|
|
||||||
|
// Reset variables
|
||||||
|
settings = null;
|
||||||
|
anchor = null;
|
||||||
|
toggle = null;
|
||||||
|
fixedHeader = null;
|
||||||
|
eventTimeout = null;
|
||||||
|
animationInterval = null;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Smooth Scroll
|
||||||
|
* @param {Object} options User settings
|
||||||
|
*/
|
||||||
|
var init = function () {
|
||||||
|
|
||||||
|
// feature test
|
||||||
|
if (!supports()) throw 'Smooth Scroll: This browser does not support the required JavaScript methods and browser APIs.';
|
||||||
|
|
||||||
|
// Destroy any existing initializations
|
||||||
|
smoothScroll.destroy();
|
||||||
|
|
||||||
|
// Selectors and variables
|
||||||
|
settings = extend(defaults, options || {}); // Merge user options with defaults
|
||||||
|
fixedHeader = settings.header ? document.querySelector(settings.header) : null; // Get the fixed header
|
||||||
|
|
||||||
|
// When a toggle is clicked, run the click handler
|
||||||
|
document.addEventListener('click', clickHandler, false);
|
||||||
|
|
||||||
|
// If updateURL and popState are enabled, listen for pop events
|
||||||
|
if (settings.updateURL && settings.popstate) {
|
||||||
|
window.addEventListener('popstate', popstateHandler, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize plugin
|
||||||
|
//
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Public APIs
|
||||||
|
//
|
||||||
|
|
||||||
|
return smoothScroll;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return SmoothScroll;
|
||||||
|
|
||||||
|
}));
|
||||||
34
fet2020/static/js/toolkit-screen@1.0.0.js
Normal file
34
fet2020/static/js/toolkit-screen@1.0.0.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
(() => {
|
||||||
|
// packages/$screen/src/index.js
|
||||||
|
function src_default(Alpine) {
|
||||||
|
let data = Alpine.reactive({screensize: window.innerWidth});
|
||||||
|
const defaultBreakpoints = {
|
||||||
|
xs: 0,
|
||||||
|
sm: 640,
|
||||||
|
md: 768,
|
||||||
|
lg: 1024,
|
||||||
|
xl: 1280,
|
||||||
|
"2xl": 1536
|
||||||
|
};
|
||||||
|
const breakpoints = window.AlpineMagicHelpersConfig && window.AlpineMagicHelpersConfig.breakpoints ? window.AlpineMagicHelpersConfig.breakpoints : defaultBreakpoints;
|
||||||
|
let update;
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
clearTimeout(update);
|
||||||
|
update = setTimeout(() => data.screensize = window.innerWidth, 150);
|
||||||
|
});
|
||||||
|
Alpine.magic("screen", (el) => (breakpoint) => {
|
||||||
|
let width = data.screensize;
|
||||||
|
if (Number.isInteger(breakpoint))
|
||||||
|
return breakpoint <= width;
|
||||||
|
if (breakpoints[breakpoint] === void 0) {
|
||||||
|
throw Error("Undefined $screen property: " + breakpoint + ". Supported properties: " + Object.keys(breakpoints).join(", "));
|
||||||
|
}
|
||||||
|
return breakpoints[breakpoint] <= width;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// packages/$screen/builds/cdn.js
|
||||||
|
document.addEventListener("alpine:init", () => {
|
||||||
|
window.Alpine.plugin(src_default);
|
||||||
|
});
|
||||||
|
})();
|
||||||
200639
fet2020/static/styles.css
Normal file
200639
fet2020/static/styles.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,31 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto w-full px-4 my-8 flex-grow flex flex-col">
|
||||||
|
<h1 class="page-title">Login für FET-Mitarbeiter</h1>
|
||||||
|
<div class="w-full h-full flex-1 flex justify-center items-center">
|
||||||
|
<form action="" method="POST" class="sm:p-4 sm:w-3/5 md:w-1/2 lg:w-2/5 xl:w-1/3 2xl:w-1/4 grid grid-cols-1 gap-3 sm:gap-6">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
<div class="grid-container padding-top-1">
|
{% for message in messages %}
|
||||||
<div class="grid-x">
|
<div class="alert alert-danger">
|
||||||
|
<i class="alert-icon fas fa-check-circle"></i>
|
||||||
<form action="" method="post">
|
<h2 class="alert-title">Fehler:</h2>
|
||||||
<h3>Anmeldung für FET-Mitarbeiter</h3>
|
<div class="alert-body">{{ message }}</div>
|
||||||
{% csrf_token %}
|
</div>
|
||||||
{{ form }}
|
{% endfor %}
|
||||||
<input type="submit" class="button" name="btn_input" value="Anmelden">
|
|
||||||
|
|
||||||
{% for message in messages %}
|
|
||||||
<p id="messages">{{message}}</p>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<span class="text-gray-700">Username</span>
|
||||||
|
<input type="text" name="username" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50 placeholder-gray-400" required="required">
|
||||||
|
</label>
|
||||||
|
<label class="block">
|
||||||
|
<span class="text-gray-700">Passwort</span>
|
||||||
|
<input type="password" name="password" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50 placeholder-gray-400" required="required">
|
||||||
|
</label>
|
||||||
|
<input type="submit" class="block btn btn-primary" value="Anmelden">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
152
fet2020/templates/base.html
Normal file
152
fet2020/templates/base.html
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
{% load static %}
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>FET: Startseite</title>
|
||||||
|
|
||||||
|
<meta name="author" content="Fachschaft Elektrotechnik (FET)">
|
||||||
|
<meta name="description" content="Die Fachschaft Elektrotechnik besteht aus ET Studierenden, die sich um die Anliegen der Studenten und Studentinnen kümmern.">
|
||||||
|
<meta property="og:image" content="#"> <!--og:... = Facebook metadata-->
|
||||||
|
<meta property="og:description" content="Die Fachschaft Elektrotechnik besteht aus ET Studierenden, die sich um die Anliegen der Studenten und Studentinnen kümmern.">
|
||||||
|
<meta property="og:title" content="Fachschaft Elektrotechnik (FET)">
|
||||||
|
<meta name="twitter:title" content="Fachschaft Elektrotechnik (FET)">
|
||||||
|
<meta name="theme-color" content="#006599">
|
||||||
|
<!-- third-generation iPad with high-resolution Retina display: -->
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="#">
|
||||||
|
<!-- iPhone with high-resolution Retina display: -->
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="#">
|
||||||
|
<!-- first- and second-generation iPad: -->
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="#">
|
||||||
|
<!-- non-Retina iPhone, iPod Touch, and Android 2.1+ devices: -->
|
||||||
|
<link rel="apple-touch-icon-precomposed" href="#">
|
||||||
|
<!-- basic favicon -->
|
||||||
|
<link rel="icon" href="#">
|
||||||
|
<link rel="shortcut icon" type="image/png" href="{% static 'img/fet_logo_white.png' %}">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
||||||
|
<!--<link rel="stylesheet" href="../css/tailwind.css">-->
|
||||||
|
<!--<script src="https://kit.fontawesome.com/fb26f70535.js" crossorigin="anonymous"></script>-->
|
||||||
|
<link rel="stylesheet" href="{% static 'fontawesomefree/css/all.min.css' %}" type="text/css">
|
||||||
|
|
||||||
|
<!--Google Fonts-->
|
||||||
|
<!--
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||||
|
-->
|
||||||
|
{% block extraheader %}
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- NAVBAR -->
|
||||||
|
<nav class="navbar" x-data="{ showNavBar: false }">
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'home' %}">
|
||||||
|
<img src="{% static 'img/logo2014_64.png' %}" alt="FET-Logo" class="navbar-logo">
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggle"
|
||||||
|
@click="showNavBar = ! showNavBar"
|
||||||
|
>
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<ul id="navBarContent" class="navbar-content sm:block"
|
||||||
|
x-show="showNavBar || $screen('sm')"
|
||||||
|
x-transition:enter="transition ease-out duration-300"
|
||||||
|
x-transition:enter-start="transform opacity-0"
|
||||||
|
x-transition:enter-end="transform opacity-100"
|
||||||
|
x-transition:leave="transition ease-in duration-150"
|
||||||
|
x-transition:leave-start="transform opacity-100"
|
||||||
|
x-transition:leave-end="transform opacity-0"
|
||||||
|
>
|
||||||
|
<li><a href="{% url 'posts:posts.index' %}">News</a></li>
|
||||||
|
<li><a href="{% url 'members_view' 'A' %}">Fachschaft</a></li>
|
||||||
|
<li><a href="/fotos/">Fotos</a></li>
|
||||||
|
<li><a href="{% url 'blackboard' %}">Blackboard</a></li>
|
||||||
|
<li><a href="{% url 'contact' %}">Kontakt</a></li>
|
||||||
|
|
||||||
|
{% if not request.user.is_authenticated %}
|
||||||
|
<li><a href="{% url 'login' %}?next={{ request.path }}">Login</a></li>
|
||||||
|
{% else %}
|
||||||
|
<hr class="border-proprietary">
|
||||||
|
<div href="#" class="inline-block w-full sm:w-auto rounded relative"
|
||||||
|
x-data="{ showPopupNav: false }"
|
||||||
|
@click.outside="showPopupNav = false"
|
||||||
|
>
|
||||||
|
<div class="sm:inline-flex items-center divide-x divide-blue-200 bg-proprietary text-blue-50 rounded">
|
||||||
|
<a class="hidden sm:block flex-1 px-2 py-1 hover:bg-proprietary-dark active:bg-proprietary-darker rounded-l" href="#"
|
||||||
|
@click="showPopupNav = !showPopupNav"
|
||||||
|
>
|
||||||
|
{% if request.user.first_name %}
|
||||||
|
Hallo {{ request.user.first_name }}
|
||||||
|
{% else %}
|
||||||
|
Hallo {{ request.user.username }}
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
<a class="hidden sm:block flex-0 px-2 py-1 hover:bg-proprietary-dark focus:bg-proprietary-darker rounded-r" href="{% url 'logout' %}?next={{ request.path }}"><i class="fa-solid fa-power-off"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="sm:block sm:absolute z-20 top-9 right-0 bg-white sm:shadow-md sm:rounded w-full"
|
||||||
|
x-show="showPopupNav || !$screen('sm')"
|
||||||
|
x-transition:enter="transition ease-out duration-300"
|
||||||
|
x-transition:enter-start="transform origin-top opacity-0 scale-95"
|
||||||
|
x-transition:enter-end="transform origin-top opacity-100 scale-100"
|
||||||
|
x-transition:leave="transition ease-in duration-150"
|
||||||
|
x-transition:leave-start="transform origin-top opacity-100 scale-100"
|
||||||
|
x-transition:leave-end="transform origin-top opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<li class="navInternal"><a href="{% url 'admin:index' %}"><i class="fa-fw fa-solid fa-user-secret mr-2"></i>Admin</a></li>
|
||||||
|
<li class="navInternal"><a href="{% url 'tasks' %}"><i class="fa-fw fa-solid fa-list-check mr-2"></i>Tasks</a></li>
|
||||||
|
<li class="navInternal"><a href="https://legacy.fet.at/home/intern"><i class="fa-fw fa-solid fa-database mr-2"></i>Intern</a></li>
|
||||||
|
<li class="navInternal"
|
||||||
|
x-show="!$screen('sm')"
|
||||||
|
><a href="{% url 'logout' %}?next={{ request.path }}"><i class="fa-fw fa-solid fa-power-off mr-2"></i>Logout</a></li>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<footer class="bg-proprietary p-4 text-blue-100 flex-none">
|
||||||
|
<ul class="flex justify-center mb-4 text-2xl">
|
||||||
|
<li class="mx-4">
|
||||||
|
<a href="https://facebook.fet.at/"><i class="fab fa-facebook"></i></a>
|
||||||
|
</li>
|
||||||
|
<li class="mx-4">
|
||||||
|
<a href="https://instagram.fet.at/"><i class="fab fa-instagram"></i></a>
|
||||||
|
</li>
|
||||||
|
<li class="mx-4">
|
||||||
|
<a href="https://discord.fet.at/"><i class="fab fa-discord"></i></a>
|
||||||
|
</li>
|
||||||
|
<li class="mx-4">
|
||||||
|
<a href="https://telegram.fet.at/"><i class="fab fa-telegram"></i></a>
|
||||||
|
</li>
|
||||||
|
<li class="mx-4">
|
||||||
|
<a href="mailto:service@fet.at"><i class="fas fa-envelope"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="flex justify-center my-4">
|
||||||
|
<a href="{% url 'impressum' %}" class="text-center text-sm sm:text-base">Impressum</a>
|
||||||
|
</div>
|
||||||
|
<hr class="border-blue-300 -mx-4">
|
||||||
|
<p class="mt-4 uppercase text-center text-sm sm:text-base">© {% now 'Y' %} FET - Alle Rechte vorbehalten.</p>
|
||||||
|
</footer>
|
||||||
|
<div class="text-center p-2 bg-gray-800 text-gray-400 font-light" x-data="{ counter: 0 }">
|
||||||
|
<span :class="counter>=4 && 'text-purple-300'">Handcrafted </span><span :class="counter>=5 && 'text-green-400'">with </span><i class="fa-solid fa-heart" aria-label="love" @click="counter++" :class="counter>=2 ? 'text-proprietary hover:text-proprietary-dark' : 'text-red-600 hover:text-red-700'"></i><span :class="counter>=6 && 'text-pink-400'"> by</span><span class="font-normal" :class="counter>=3 && 'text-yellow-500'"> Matteo Duchscher</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script async src="{% static 'js/alpinejs@3.2.2.js' %}" defer></script>
|
||||||
|
<script src="{% static 'js/toolkit-screen@1.0.0.js' %}" defer></script>
|
||||||
|
|
||||||
|
<script async="async" src="{% static 'js/scripts.js' %}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,46 +1,70 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto w-full px-4 mt-8 flex-1">
|
||||||
|
<h1 class="page-title">Blackboard</h1>
|
||||||
|
|
||||||
<div class="grid-container padding-top-1">
|
<div class="lg:w-2/3 xl:w-7/12 mx-auto">
|
||||||
{% if request.user.is_authenticated %}
|
<section class="my-8 flex flex-col gap-2">
|
||||||
<div class="grid-x">
|
<div class="db-page-content">
|
||||||
<div class="cell large-3 medium-4 small-12">
|
<!-- Content from DB here: -->
|
||||||
<a class="button" href="{% url 'admin:blackboard_jobposting_add' %}">neue Stellenausschreibung hinzufügen</a>
|
{% if bb_info %}
|
||||||
</div>
|
{{ bb_info.content|safe }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if bb_info %}
|
{% if request.user.is_authenticated and bb_info %}
|
||||||
<div class="cell large-3 medium-4 small-12">
|
<a href="{% url 'admin:core_customflatpage_change' bb_info.id %}" class="self-center sm:self-end btn-small btn-primary w-full sm:w-auto max-w-sm">
|
||||||
<a class="button" href="{% url 'admin:core_customflatpage_change' bb_info.id %}">Info-Text bearbeiten</a>
|
<i class="fa-regular fa-pen-to-square mr-1"></i>Info-Text bearbeiten
|
||||||
</div>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
|
||||||
{% if bb_empty %}
|
{% if job_postings %}
|
||||||
<div class="cell large-3 medium-4 small-12">
|
<section class="my-8 flex flex-col gap-2">
|
||||||
<a class="button" href="{% url 'admin:core_customflatpage_change' bb_empty.id %}">"leeres Blackboard"-Text bearbeiten</a>
|
<div class="jobsList">
|
||||||
</div>
|
{% for job in job_postings %}
|
||||||
{% endif %}
|
{% if not forloop.first %}
|
||||||
<hr>
|
<hr class="border-gray-300">
|
||||||
</div>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h1>Blackboard</h1>
|
{% include 'blackboard/partials/_show_job_posting.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if bb_info %}
|
{% if request.user.is_authenticated %}
|
||||||
{{ bb_info.content|safe }}
|
<div class="inline-flex flex-col sm:flex-row sm:justify-end gap-2 w-full sm:w-auto">
|
||||||
<hr>
|
<a href="{% url 'admin:blackboard_jobposting_add' %}" class="self-center block btn-small btn-primary w-full sm:w-auto max-w-sm">
|
||||||
{% endif %}
|
<i class="fa-regular fa-square-plus mr-1"></i>Neuer Eintrag
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="grid-x grid-margin-x">
|
{% else %}
|
||||||
{% for job in job_postings %}
|
<section class="my-8 p-8 flex flex-col gap-2 items-center border-2 border-dashed rounded border-gray-300">
|
||||||
{% include 'blackboard/partials/_show_job_posting.html' %}
|
{% if bb_empty %}
|
||||||
{% empty %}
|
<div class="text-center text-gray-600">
|
||||||
{% if bb_empty %}
|
<i class="fa-solid fa-sparkles text-gray-400 text-2xl mb-4"></i>
|
||||||
<div class="cell large-3 medium-4 small-12">
|
{{ bb_empty.content|safe }}
|
||||||
{{ bb_empty.content|safe }}
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
|
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<div class="inline-flex flex-col sm:flex-row gap-2 w-full sm:w-auto">
|
||||||
|
<a href="{% url 'admin:blackboard_jobposting_add' %}" class="self-center block btn-small btn-primary w-full sm:w-auto max-w-sm">
|
||||||
|
<i class="fa-regular fa-square-plus mr-1"></i>Neuer Eintrag
|
||||||
|
</a>
|
||||||
|
{% if bb_empty %}
|
||||||
|
<a href="{% url 'admin:core_customflatpage_change' bb_empty.id %}" class="self-center block btn-small btn-primary w-full sm:w-auto max-w-sm">
|
||||||
|
<i class="fa-solid fa-asterisk mr-1"></i>Fülltext bearbeiten
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
</main>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
<div class="cell large-3 medium-4 small-12">
|
<a href="{{ job.pdf_location.url }}" class="jobsList-item">
|
||||||
<h2>{{job.company_name}}</h2>
|
<div class="jobsList-desc">
|
||||||
<p>{{job.job_name}}<br>
|
<h2>{{ job.company_name }}</h2>
|
||||||
|
<h3>{{ job.job_name }}</h3>
|
||||||
{% if job.number_of_hours == 1 %}
|
</div>
|
||||||
Mindestgehalt: {{job.salary}}€ Stundenlohn<br></p>
|
<div class="jobsList-price">
|
||||||
{% else %}
|
<p class="jobsList-value">{{ job.salary }}€</p>
|
||||||
monatliches Mindestgehalt:<br>
|
<p class="jobsList-amount ">/ {{ job.number_of_hours }} <span class="sm:hidden">h</span><span class="hidden sm:inline">Stunden</span></p>
|
||||||
{{job.salary}}€ für {{job.number_of_hours}}h</p>
|
</div>
|
||||||
{% endif %}
|
<div class="jobsList-expand">
|
||||||
|
<i class="fas fa-angle-right"></i>
|
||||||
{# only thumb and name of member #}
|
</div>
|
||||||
<a class="thumbnail member-thumb" href="{{job.pdf_location.url}}" style="width:200px;height:280px" target="_blank">
|
</a>
|
||||||
<img style="width:200px;height:280px" src="{{job.pdf_thumb_location}}" alt="" />
|
|
||||||
<div class="thumb-layer">
|
|
||||||
<div>
|
|
||||||
<h1>{{job.company_name}}</h1>
|
|
||||||
<p>{{job.job_name}}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -1,103 +1,93 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% load post_helpers %}
|
{% load post_helpers %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<!--Hero section-->
|
||||||
|
<section class="hero-image relative z-0 w-full h-56 sm:h-80 lg:h-96 bg-cover-image bg-cover bg-center bg-no-repeat flex-none">
|
||||||
|
<div class="absolute z-10 w-full h-full bg-blue-50 opacity-60"></div>
|
||||||
|
<div class="relative container px-4 mx-auto z-20 w-full h-full flex flex-wrap items-center gap-x-2">
|
||||||
|
<h1 class="w-3/5 flex-1 uppercase font-semibold text-xl sm:text-2xl lg:text-3xl text-center text-gray-900">
|
||||||
|
<span class="hidden">Willkommen bei der </span><span>Fachschaft</span><br>
|
||||||
|
<span class="text-proprietary-darker">Elektrotechnik</span>
|
||||||
|
</h1>
|
||||||
|
<div class="hidden sm:block flex-none w-2/5 lg:w-1/3 bg-white p-2 lg:p-4 rounded shadow-xl">
|
||||||
|
<h2 class="section-title sm:text-left"><i class="fas fa-comments text-gray-300 mr-2"></i>Events</h2>
|
||||||
|
<div class="-mb-2 text-gray-700 text-sm md:text-base">
|
||||||
|
|
||||||
|
{% if featured_event %}
|
||||||
|
{% with post=featured_event %}
|
||||||
|
{% include 'posts/partials/_meeting_row.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% for post in featured_meeting %}
|
||||||
|
{% include 'posts/partials/_meeting_row.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<div class="grid-x small-padding-left-1">
|
</div>
|
||||||
<div class="medium-8 small cell" style="background: grey">
|
</div>
|
||||||
{% with post=featured_post %}
|
<!--<div class="w-full self-end flex justify-center mb-4">
|
||||||
<a href="{{ post.url }}">
|
<i class="fas fa-chevron-down animate-bounce text-proprietary text-2xl"></i>
|
||||||
<div class="news-hero-large"style="background-image: url('{{ post.imageurl }}');)">
|
</div>-->
|
||||||
<div class="news-hero-text">
|
</div>
|
||||||
<hr>
|
</section>
|
||||||
<div class="article-date">
|
|
||||||
<p>{{ post.date|date:"d. F Y" }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="article-title">
|
|
||||||
<h1>{{ post.title|safe }}</h1>
|
|
||||||
<p>{{ post.subtitle|default_if_none:" "|safe }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{% endwith %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cell medium-4 responsive-side-box">
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto w-full px-4 my-8 flex-1">
|
||||||
|
<section class="sm:hidden my-8">
|
||||||
|
<h2 class="section-title section-title-margins">Events</h2>
|
||||||
|
|
||||||
<div class="article-row-section">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="article-row-section-inner">
|
{% if featured_event %}
|
||||||
|
{% with post=featured_event %}
|
||||||
<h1 class="article-row-section-header">Events</h1>
|
|
||||||
|
|
||||||
{% with post=featured_event %}
|
|
||||||
{% include 'posts/partials/_article_row.html' %}
|
{% include 'posts/partials/_article_row.html' %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
{% for post in featured_meeting %}
|
{% for post in featured_meeting %}
|
||||||
{% include 'posts/partials/_meeting_row.html' %}
|
{% include 'posts/partials/_article_row.html' %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid-container">
|
<div class="sm:flex sm:flex-row-reverse justify-center my-8">
|
||||||
<div class="grid-x grid-padding-x padding-top-1 padding-left-1 padding-right-1">
|
<aside class="calendar-preview sm:w-2/5 xl:w-1/4 sm:pl-4 my-8 sm:my-0">
|
||||||
{{ tags_list|tags_to_url }}
|
<div>
|
||||||
</div>
|
<h2 class="section-title section-title-margins">Kalender</h2>
|
||||||
|
<div class="calendar-entries">
|
||||||
|
{% for post in events %}
|
||||||
|
{% include 'posts/partials/_date_box.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<div class="grid-x grid-x-padding">
|
<a href="https://fet.at/posts/fet_calendar.ics" class="btn btn-secondary block w-full"><i class="fas fa-calendar-alt mr-2"></i>Kalender abonnieren</a>
|
||||||
<div class="large-8 medium-7 small-12 small-order-2 medium-order-1">
|
</div>
|
||||||
{% for post in posts %}
|
</div>
|
||||||
{% include 'posts/partials/_posts_hero.html' %}
|
</aside>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="large-4 medium-5 small-12 small-order-1 medium-order-1 padding-top-1 large-padding-left-1 medium-padding-left-1">
|
<section class="my-8 sm:my-0 sm:w-3/5 xl:w-2/5 flex flex-col gap-4">
|
||||||
|
<h2 class="section-title section-title-margins">Zuletzt veröffentlicht</h2>
|
||||||
|
|
||||||
<a href="mailto:service@fet.at">
|
{% for post in posts %}
|
||||||
<div class="social-media-box">
|
{% include 'posts/partials/_posts_hero.html' %}
|
||||||
<span class="social-media-badge badge">
|
{% endfor %}
|
||||||
<span class="social-media-badge-symbol">
|
|
||||||
<i class="fa-solid fa-envelope"></i>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="social-media-text">Schreib uns ein Mail :)</span>
|
<a href="{% url 'posts:posts.index' %}" class="btn btn-primary block w-full"><i class="fas fa-plus-square mr-2"></i>Mehr anzeigen</a>
|
||||||
</div>
|
</section>
|
||||||
</a>
|
</div>
|
||||||
<a href="{% url 'discord' %}">
|
|
||||||
<div class="social-media-box">
|
|
||||||
<span class="social-media-badge badge">
|
|
||||||
<span class="social-media-badge-symbol">
|
|
||||||
<i class="fa-brands fa-discord"></i>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span class="social-media-text">Komm auf unseren Discord-Server!</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% for post in events %}
|
|
||||||
{% include 'posts/partials/_date_box.html' %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<a href="{% url 'posts:posts.calendar' %}">
|
|
||||||
<div class="social-media-box">
|
|
||||||
<span class="social-media-badge badge">
|
|
||||||
<span class="social-media-badge-symbol">
|
|
||||||
<i class="fa-regular fa-calendar"></i>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span class="social-media-text">FET-Kalender abonnieren</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a class="button" href="{% url 'posts:posts.index' %}" style="background: gray">Mehr anzeigen</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div id="infoBox" class="sticky bottom-4 p-4 rounded-lg shadow-lg bg-gray-600 text-gray-200 flex gap-x-4 items-center leading-none">
|
||||||
|
<div class="flex-none relative">
|
||||||
|
<span class="absolute flex h-3 w-3 right-0 top-0">
|
||||||
|
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-500 opacity-80"></span>
|
||||||
|
<span class="relative inline-flex rounded-full h-3 w-3 bg-blue-500"></span>
|
||||||
|
</span>
|
||||||
|
<i class="fab fa-discord text-4xl"></i>
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'discord' %}" class="flex-1">
|
||||||
|
FET Discord-Server<br>
|
||||||
|
<span class="hidden lg:inline text-sm text-gray-300">Du hast Fragen zum Studium oder möchtest dich einfach mich anderen Studierenden austauschen? </span><span class="text-sm text-gray-300">Klicke hier zum Beitreten <span class="hidden sm:inline"><i class="fa-solid fa-angle-right"></i></span></span>
|
||||||
|
</a>
|
||||||
|
<button id="infoBox-closeButton" class="flex-none self-stretch px-2 -mr-2" onclick="hideInfoBox()"><i class="fas fa-times text-gray-400"></i></button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -4,18 +4,18 @@
|
|||||||
<html class="no-js" lang="en">
|
<html class="no-js" lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>FET - Fachschaft Elektrotechnik</title>
|
<title>FET - Fachschaft Elektrotechnik</title>
|
||||||
<link rel="shortcut icon" type="image/png" href="{% static 'img/fet_logo_white.png' %}"/>
|
<link rel="shortcut icon" type="image/png" href="{% static 'img/fet_logo_white.png' %}"/>
|
||||||
<link rel="stylesheet" href="{% static 'app.css' %}">
|
<link rel="stylesheet" href="{% static 'app.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'fet.css' %}">
|
<link rel="stylesheet" href="{% static 'fet.css' %}">
|
||||||
<link href="{% static 'fontawesomefree/css/all.min.css' %}" rel="stylesheet" type="text/css">
|
<link href="{% static 'fontawesomefree/css/all.min.css' %}" rel="stylesheet" type="text/css">
|
||||||
{% block galleryheader %}
|
{% block galleryheader %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block extraheader %}
|
{% block extraheader %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,104 +1,154 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% load softhyphen_tags %}
|
{% load softhyphen_tags %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid-container">
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto w-full px-4 mt-8 flex-1">
|
||||||
|
<h1 class="page-title">Über uns</h1>
|
||||||
|
<div class="sm:flex sm:flex-row justify-center my-8">
|
||||||
|
<aside class="flex-none max-w-min sm:mr-8">
|
||||||
|
<div class="fixed sm:sticky top-0 sm:top-4 left-0 w-full h-full sm:h-auto bg-black sm:bg-transparent bg-opacity-70 flex sm:block items-center justify-center"
|
||||||
|
x-show="showModal || $screen('sm')"
|
||||||
|
x-transition:enter="transition duration-300 ease-out"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="transition duration-150 ease-in"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
>
|
||||||
|
<div class="max-w-sm sm:w-full mx-4 sm:mx-0 p-4 sm:p-0 bg-white sm:bg-transparent rounded sm:rounded-none"
|
||||||
|
@click.outside="showModal = false"
|
||||||
|
x-show="showModal || $screen('sm')"
|
||||||
|
x-transition:enter="transition transform ease-out duration-300"
|
||||||
|
x-transition:enter-start="scale-110 opacity-0"
|
||||||
|
x-transition:enter-end="scale-100 opacity-100"
|
||||||
|
x-transition:leave="transition transform ease-in duration-150"
|
||||||
|
x-transition:leave-start="scale-100 opacity-100"
|
||||||
|
x-transition:leave-end="scale-110 opacity-0"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between items-center mb-2 sm:hidden">
|
||||||
|
<h2 class="text-gray-800 sm:section-title sm_section-title-margins sm:w-full">
|
||||||
|
<span class="mr-1 text-gray-400 sm:hidden">
|
||||||
|
<i class="fa-solid fa-bars"></i>
|
||||||
|
</span>
|
||||||
|
Kategorien
|
||||||
|
</h2>
|
||||||
|
<div class="ml-4 -mr-2 px-2 rounded text-xl text-gray-600 sm:hidden cursor-pointer" @click="showModal = false">
|
||||||
|
<i class="far fa-times"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ul class="sideBarNav">
|
||||||
|
{% for job in pinned_job_groups %}
|
||||||
|
<li class="{% if job.slug in request.path %} active {% endif %}">
|
||||||
|
<a href="{% url 'jobs' job.slug %}">{{ job.name|softhyphen|safe }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<div class="grid-x grid-padding-x padding-top-1">
|
{% for job in unpinned_job_groups %}
|
||||||
|
<li class="{% if job.slug in request.path %} active {% endif %}">
|
||||||
|
<a href="{% url 'jobs' job.slug %}">{{ job.name|softhyphen|safe }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% for job in pinned_job_groups %}
|
<hr class="">
|
||||||
<div class="cell large-2 medium-4 small-6">
|
|
||||||
<a class="button job-btn {% if job.slug in request.path %} active {% endif %}" href="{% url 'jobs' job.slug %}">
|
|
||||||
{{ job.name|softhyphen|safe }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% for job in unpinned_job_groups %}
|
<li class="{% if 'pension' in request.path %} active {% endif %}">
|
||||||
<div class="cell large-2 medium-4 small-6">
|
<a href="{% url 'members_view' 'pension' %}">Pension</a>
|
||||||
<a class="button job-btn {% if job.slug in request.path %} active {% endif %} job-btn" href="{% url 'jobs' job.slug %}">
|
</li>
|
||||||
{{ job.name|softhyphen|safe }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<div class="cell large-2 medium-4 small-6">
|
<li class="{% if '/members/' == request.path %} active {% endif %}">
|
||||||
<a class="button memb-btn {% if 'pension' in request.path %} active {% endif %}" href="{% url 'members_view' 'pension' %}">
|
<a href="{% url 'members' %}">Alle Mitglieder</a>
|
||||||
Pension
|
</li>
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cell large-2 medium-4 small-6">
|
<li class="active"><a href="#">Studienkommission</a></li>
|
||||||
<a class="button memb-btn {% if '/members/' == request.path %} active {% endif %}" href="{% url 'members' %}">
|
<ul id="scrollspy-subNav">
|
||||||
Alle Mitglieder
|
<li class="active"><a href="#stuko-computational-science">Studienkommission Computational Science</a></li>
|
||||||
</a>
|
<li><a href="#stuko-et">Studienkommission ET</a></li>
|
||||||
</div>
|
<li><a href="#stuko-ulg">Studienkommission Universitätslehrgänge</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
</div>
|
<li class="internalLI"><a href="#"><i class="fa-regular fa-pen-to-square mr-1"></i>Bearbeiten</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="modal-trigger-1" class="trigger fixed bottom-4 right-4 bg-proprietary-darker text-blue-50 shadow-lg text-2xl rounded sm:hidden"
|
||||||
|
@click="showModal = true"
|
||||||
|
x-show="!showModal && !$screen('sm')"
|
||||||
|
x-transition:enter="transition duration-100 ease-in"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="transition duration-100 ease-out"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-bars px-2 py-1"></i>
|
||||||
|
</button>
|
||||||
|
</aside>
|
||||||
|
|
||||||
{% if description %}
|
<section class="flex-grow max-w-prose my-8 sm:my-0">
|
||||||
<div class="grid-x">
|
{% if description %}
|
||||||
<div class="cell padding-top-1 padding-left-1 padding-right-1" style="background-color: white; text-align: justify;">
|
<div class="db-page-content text-gray-800">
|
||||||
{{ description|safe }}
|
{{ description|safe }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- show details of a member -->
|
|
||||||
{% if member %}
|
|
||||||
{% block members_content %}
|
|
||||||
{% endblock %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- show all, active or pension members -->
|
|
||||||
{% if members %}
|
|
||||||
<div class="grid-x">
|
|
||||||
<div class="cell padding-top-1 padding-left-1 padding-right-1" style="background-color: white; text-align: justify;">
|
|
||||||
{% if fs_info %}
|
|
||||||
{{ fs_info.content|safe }}
|
|
||||||
|
|
||||||
{% if request.user.is_authenticated %}
|
|
||||||
<hr>
|
|
||||||
<a href="{% url 'admin:core_customflatpage_change' fs_info.id %}">Fachschaft-Text bearbeiten</a>
|
|
||||||
<hr>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="padding-top-1 padding-left-1 padding-right-1" style="background-color: white;">
|
{% if member %}
|
||||||
{% include 'members/members_list.html' %}
|
<!-- show details of a member -->
|
||||||
</div>
|
{% block members_content %}
|
||||||
{% endif %}
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- show job lists in a job group -->
|
{% if members %}
|
||||||
{% include 'members/jobs_list.html' %}
|
<!-- show all, active or pension members -->
|
||||||
|
{% if fs_info %}
|
||||||
|
<div class="db-page-content text-gray-800">
|
||||||
|
{{ fs_info.content|safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
{% if request.user.is_authenticated %}
|
||||||
|
<hr>
|
||||||
|
<a href="{% url 'admin:core_customflatpage_change' fs_info.id %}">Fachschaft-Text bearbeiten</a>
|
||||||
|
<hr>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<article class="members-article">
|
||||||
|
<div class="members-listing">
|
||||||
|
{% for member in members %}
|
||||||
|
{% include 'members/partials/_member.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- show job lists in a job group -->
|
||||||
|
{% include 'members/jobs_list.html' %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="{% static 'js/gumshoe@5.1.1.js' %}"></script>
|
||||||
|
<script src="{% static 'js/smooth-scroll@16.1.2.js' %}"></script>
|
||||||
|
<script src="{% static 'js/toolkit-screen@1.0.0.js' %}" defer></script>
|
||||||
|
<script defer src="{% static 'js/alpinejs@3.2.2.js' %}"></script>
|
||||||
|
<script defer src="{% static 'js/scripts.js' %}"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var spy = new Gumshoe('#scrollspy-subNav a', {
|
||||||
|
/***** Scrollspy *****/ // Active classes
|
||||||
|
navClass: 'font-semibold', // applied to the nav list item
|
||||||
|
});
|
||||||
|
|
||||||
|
/***** SmoothScroll *****/ // All animations will take exactly 500ms
|
||||||
|
var scroll = new SmoothScroll('a[href*="#"]', {
|
||||||
|
speed: 750,
|
||||||
|
speedAsDuration: true,
|
||||||
|
easing: 'easeInOutQuad'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<script>
|
|
||||||
// Get the container element
|
|
||||||
var btnContainer = document.getElementById("grid-container");
|
|
||||||
|
|
||||||
// Get all buttons with class="btn" inside the container
|
|
||||||
var grid = btnContainer.getElementsByClassName("grid-x");
|
|
||||||
var cell = grid.getElementsByClassName("cell");
|
|
||||||
var btns = cell.getElementsByClassName("button");
|
|
||||||
|
|
||||||
// Loop through the buttons and add the active class to the current/clicked button
|
|
||||||
for (var i = 0; i < btns.length; i++) {
|
|
||||||
btns[i].addEventListener("click", function() {
|
|
||||||
var current = document.getElementsByClassName("active");
|
|
||||||
|
|
||||||
// If there's no active class
|
|
||||||
if (current.length > 0) {
|
|
||||||
current[0].className = current[0].className.replace(" active", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the active class to the current/clicked button
|
|
||||||
this.className += " active";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
{% regroup job_members by job.name as all_jobmem_list %}
|
{% regroup job_members by job.name as all_jobmem_list %}
|
||||||
|
|
||||||
{% for jobmem in all_jobmem_list %}
|
{% for jobmem in all_jobmem_list %}
|
||||||
|
<article id="{{jobmem.list.0.job.slug}}" class="members-article">
|
||||||
<div class="padding-top-1 padding-left-1 padding-right-1" style="background-color: white;">
|
<a href="#{{jobmem.list.0.job.slug}}" class="title">
|
||||||
|
<i class="far fa-link"></i>
|
||||||
<h2>{{jobmem.grouper}}<a class="headerlink" id="{{jobmem.list.0.job.slug}}" href="#{{jobmem.list.0.job.slug}}" title="Permalink to {{jobmem.grouper}}"> #</a></h2>
|
<h2>{{jobmem.grouper}}</h2>
|
||||||
|
</a>
|
||||||
<div class="grid-x align-bottom">
|
<div class="members-listing">
|
||||||
|
|
||||||
{% for jm in jobmem.list %}
|
{% for jm in jobmem.list %}
|
||||||
{% with member=jm.member %}
|
{% with member=jm.member %}
|
||||||
{% include 'members/partials/_job_membership_grid.html' %}
|
{% include 'members/partials/_member.html' %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
{% extends 'members/index.html' %}
|
{% extends 'members/index.html' %}
|
||||||
|
|
||||||
{% block extraheader %}
|
{% block extraheader %}
|
||||||
<meta content="{{member.image.url}}" property="og:image">
|
<meta content="{{member.image.url}}" property="og:image">
|
||||||
<meta content="{{ member.firstname }}" property="og:profile:first_name">
|
<meta content="{{ member.firstname }}" property="og:profile:first_name">
|
||||||
<meta content="{{ member.surname }}" property="og:profile:last_name">
|
<meta content="{{ member.surname }}" property="og:profile:last_name">
|
||||||
<meta content="profile" property="og:type">
|
<meta content="profile" property="og:type">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block members_content %}
|
{% block members_content %}
|
||||||
<div class="padding-top-1 padding-left-1 padding-bottom-1 padding-right-1" style="background-color: white;">
|
{% include 'members/partials/_member_details.html' %}
|
||||||
{% include 'members/partials/_member_details.html' %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
<div class="grid-x align-bottom">
|
<div class="grid-x align-bottom">
|
||||||
{% for member in members %}
|
{% for member in members %}
|
||||||
<div class="cell large-2 medium-3 small-6 padding-right-1" style="text-align: center">
|
<div class="cell large-2 medium-3 small-6 padding-right-1" style="text-align: center">
|
||||||
@@ -7,4 +6,3 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
{# only thumb and name of member #}
|
<figure>
|
||||||
<a class="thumbnail member-thumb" href="{{ member.get_absolute_url }}" style="width:150px; height:150px">
|
<a href="{{ member.get_absolute_url }}">
|
||||||
<img src="{{ member.image.thumb.url }}" alt="" />
|
<img loading="lazy" src="{{ member.image.thumb.url }}" alt="Portraitfoto von {{ member.firstname }}" class="w-36 h-36 bg-white">
|
||||||
<div class="thumb-layer">
|
<figcaption>
|
||||||
<div>
|
<h3>{{ member.firstname }} {{ member.surname }}</h3>
|
||||||
<h1>{{member.nickname}}</h1>
|
</figcaption>
|
||||||
</div>
|
</a>
|
||||||
</div>
|
</figure>
|
||||||
</a>
|
|
||||||
|
|||||||
@@ -1,26 +1,71 @@
|
|||||||
{# This template shows one member and all the details (that are ment for public) including a list of current jobs #}
|
{# This template shows one member and all the details (that are ment for public) including a list of current jobs #}
|
||||||
{% load softhyphen_tags %}
|
{% load softhyphen_tags %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
<div class="media-object stack-for-small">
|
<section class="flex-grow max-w-prose my-8 sm:my-0 text-justify text-gray-800">
|
||||||
<div class="media-object-section padding-bottom-2">
|
<!-- Alternativtext auf jede Person anpassen: Name im alt="" dynamisch erzeugen -->
|
||||||
<img src= "{{member.image.portrait.url}}" style="width:150px;">
|
<img loading="lazy" src="{{ member.image.portrait.url }}" alt="Portraitfoto von {{ member.firstname }} {{ member.surname }}" class="md:float-left w-36 mr-2 mb-2">
|
||||||
</div>
|
<div x-data="{ expandList: false }">
|
||||||
<div class="media-object-section main-section padding-bottom-1"">
|
<h2 class="mb-2 text-lg text-gray-900 text-left">{{ member.firstname }} {{ member.surname }}</h2>
|
||||||
{% if request.user.is_authenticated %}
|
<div class="mb-2">
|
||||||
<a href="{% url 'admin:members_member_change' member.id %}">Profil bearbeiten</a>
|
Spitzname: {{ member.nickname }} <br>
|
||||||
<hr>
|
Mailaccount: {{ member.mailaccount }} <br>
|
||||||
{% endif %}
|
</div>
|
||||||
<h1>{{ member.firstname }} {{ member.surname }}</h1>
|
<div class="mb-2">
|
||||||
<p>Spitzname: {{ member.nickname }} </br>
|
{{ member.description|softhyphen|safe }}
|
||||||
Mailaccount: {{ member.mailaccount }} </br>
|
</div>
|
||||||
</p>
|
|
||||||
{{ member.description|softhyphen|safe }}
|
|
||||||
</p>
|
|
||||||
{% if jobs %}
|
{% if jobs %}
|
||||||
Ehrenamtliche Tätigkeiten: </br>
|
<h3 class="group mt-4 mb-2 text-lg text-gray-900">Ehrenamtliche Tätigkeiten:
|
||||||
{% for jobm in jobs %}
|
<button class="inline float-right text-sm px-2 py-1 text-gray-600 md:text-gray-500 group-hover:text-gray-600 border rounded border-gray-500 md:border-gray-400 group-hover:border-gray-500"
|
||||||
{{ jobm.job.name }}: {{ jobm.job_start|date }} - {{ jobm.job_end|date }} </br>
|
@click="expandList = ! expandList"
|
||||||
{% endfor %}
|
>
|
||||||
|
<span x-show="!expandList">Mehr</span><span x-show="expandList">Weniger</span><span class="hidden md:inline"> anzeigen</span>
|
||||||
|
<i class="fa-fw fa-solid fa-angle-left transition transform -ml-1"
|
||||||
|
:class="expandList ? '-rotate-90' : ''"
|
||||||
|
></i>
|
||||||
|
</button>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<ul class="flex flex-col gap-1">
|
||||||
|
{% for jobm in jobs %}
|
||||||
|
<li class="flex flex-row flex-wrap">
|
||||||
|
<span>{{ jobm.job.name }}:</span>
|
||||||
|
<span class="ml-2 text-gray-600">{{ jobm.job_start|date }} -</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<ul class="flex flex-col gap-1 mt-1"
|
||||||
|
x-show="expandList"
|
||||||
|
x-transition:enter="transition duration-100 ease-in"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="transition duration-100 ease-out"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
>
|
||||||
|
{% for jobm in jobs %}
|
||||||
|
<li class="flex flex-row flex-wrap">
|
||||||
|
<span>{{ jobm.job.name }}:</span>
|
||||||
|
<span class="ml-2 text-gray-600">{{ jobm.job_start|date }} -</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
|
<script src="{% static 'gumshoe.js' %}"></script>
|
||||||
|
<script src="{% static 'smooth-scroll.js' %}"></script>
|
||||||
|
<script>
|
||||||
|
var spy = new Gumshoe('#scrollspy-subNav a', {
|
||||||
|
/***** Scrollspy *****/ // Active classes
|
||||||
|
navClass: 'font-semibold', // applied to the nav list item
|
||||||
|
});
|
||||||
|
|
||||||
|
/***** SmoothScroll *****/ // All animations will take exactly 500ms
|
||||||
|
var scroll = new SmoothScroll('a[href*="#"]', {
|
||||||
|
speed: 750,
|
||||||
|
speedAsDuration: true,
|
||||||
|
easing: 'easeInOutQuad'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,7 +1,132 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% load post_helpers %}
|
{% load post_helpers %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<!-- Main Content -->
|
||||||
|
<main class="container mx-auto w-full px-4 my-8 flex-1">
|
||||||
|
<h1 class="page-title">News</h1>
|
||||||
|
<div class="sm:flex sm:flex-row-reverse justify-center">
|
||||||
|
<aside class="sm:w-2/5 sm:max-w-xs sm:pl-4 lg:pl-8 my-8 sm:my-0">
|
||||||
|
<div class="z-10 fixed sm:sticky top-0 sm:top-4 lg:top-8 left-0 w-full h-full sm:h-auto bg-black sm:bg-transparent bg-opacity-70 flex sm:block items-center justify-center"
|
||||||
|
x-show="showModal || $screen('sm')"
|
||||||
|
x-transition:enter="transition duration-300 ease-out"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="transition duration-150 ease-in"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
>
|
||||||
|
<div class="max-w-sm sm:w-full mx-4 sm:mx-0 p-4 rounded bg-white sm:shadow-lg"
|
||||||
|
@click.outside="showModal = ! showModal"
|
||||||
|
x-show="showModal || $screen('sm')"
|
||||||
|
x-transition:enter="transition transform ease-out duration-300"
|
||||||
|
x-transition:enter-start="scale-110 opacity-0"
|
||||||
|
x-transition:enter-end="scale-100 opacity-100"
|
||||||
|
x-transition:leave="transition transform ease-in duration-150"
|
||||||
|
x-transition:leave-start="scale-100 opacity-100"
|
||||||
|
x-transition:leave-end="scale-110 opacity-0"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between items-center mb-2">
|
||||||
|
<h2 class="text-gray-800 sm:section-title sm_section-title-margins sm:w-full">
|
||||||
|
<span class="mr-1 text-gray-400 sm:hidden">
|
||||||
|
<i class="fas fa-filter"></i>
|
||||||
|
</span>
|
||||||
|
Auswahl einschränken
|
||||||
|
</h2>
|
||||||
|
<div class="ml-4 -mr-2 px-2 rounded text-xl text-gray-600 sm:hidden cursor-pointer" @click="showModal = false">
|
||||||
|
<i class="far fa-times"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form action="" method="POST" class="grid grid-cols-1 gap-2 sm:gap-4" x-data="{ selectedYear: '' }">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="alert-icon fas fa-exclamation-circle"></i>
|
||||||
|
<h2 class="alert-title">Fehler:</h2>
|
||||||
|
<div class="alert-body">{{message}}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<span class="text-gray-700">Jahr</span>
|
||||||
|
<select class="block w-full mt-1 rounded-md border-gray-300 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
||||||
|
x-model="selectedYear"
|
||||||
|
id="id_year"
|
||||||
|
name="year"
|
||||||
|
>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
x-show="selectedYear != ''"
|
||||||
|
x-transition:enter="transition ease-out duration-300"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="transition ease-in duration-150"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
>
|
||||||
|
<span class="text-gray-700">Monat</span>
|
||||||
|
<select class="block w-full mt-1 rounded-md border-gray-300 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
|
||||||
|
<option value="" selected></option>
|
||||||
|
<option value="1">Jänner</option>
|
||||||
|
<option value="2">Februar</option>
|
||||||
|
<option value="3">März</option>
|
||||||
|
<option value="4">April</option>
|
||||||
|
<option value="5">Mai</option>
|
||||||
|
<option value="6">Juni</option>
|
||||||
|
<option value="7">Juli</option>
|
||||||
|
<option value="8">August</option>
|
||||||
|
<option value="9">September</option>
|
||||||
|
<option value="10">Oktober</option>
|
||||||
|
<option value="11">November</option>
|
||||||
|
<option value="12">Dezember</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="inline-flex items-center">
|
||||||
|
<input type="checkbox" class="rounded border-gray-300 text-proprietary shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50">
|
||||||
|
<span class="ml-2 text-gray-700">Kompakte Ansicht</span>
|
||||||
|
</label>
|
||||||
|
<label class="inline-flex items-center">
|
||||||
|
<input type="checkbox" class="rounded border-gray-300 text-proprietary shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50">
|
||||||
|
<span class="ml-2 text-gray-700">nur FET-Sitzungen</span>
|
||||||
|
</label>
|
||||||
|
<input type="submit" class="block btn btn-primary" value="Anzeigen">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="modal-trigger-1" class="z-10 trigger fixed bottom-4 right-4 bg-proprietary-darker text-blue-50 shadow-lg text-2xl rounded sm:hidden"
|
||||||
|
@click="showModal = true"
|
||||||
|
x-show="! showModal"
|
||||||
|
x-transition:enter="transition duration-100 ease-in"
|
||||||
|
x-transition:enter-start="opacity-0"
|
||||||
|
x-transition:enter-end="opacity-100"
|
||||||
|
x-transition:leave="transition duration-100 ease-out"
|
||||||
|
x-transition:leave-start="opacity-100"
|
||||||
|
x-transition:leave-end="opacity-0"
|
||||||
|
>
|
||||||
|
<i class="fas fa-filter p-2"></i>
|
||||||
|
</button>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<section class="my-8 sm:my-0 sm:w-3/5 xl:w-2/5 flex flex-col gap-4">
|
||||||
|
{% if compact_view %}
|
||||||
|
{% for post in posts %}
|
||||||
|
{% include 'posts/partials/_posts_hero_compact.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{% for post in posts %}
|
||||||
|
{% include 'posts/partials/_posts_hero.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
<div class="grid-container">
|
<div class="grid-container">
|
||||||
<div class="grid-x grid-margin-x">
|
<div class="grid-x grid-margin-x">
|
||||||
<div class="cell medium-8">
|
<div class="cell medium-8">
|
||||||
@@ -37,21 +162,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="grid-x">
|
|
||||||
<div class="cell medium-8">
|
|
||||||
|
|
||||||
{% if compact_view %}
|
|
||||||
{% for post in posts %}
|
|
||||||
{% include 'posts/partials/_posts_hero_compact.html' %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
{% for post in posts %}
|
|
||||||
{% include 'posts/partials/_posts_hero.html' %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
<a href="{{ post.url }}">
|
<a href="{{ post.url }}" class="block">
|
||||||
<article class="article-row">
|
<h3 class="text-gray-700">{{ post.title }}</h3>
|
||||||
<div class="article-row-content">
|
<p class="my-1 text-sm text-gray-600">
|
||||||
<h1 class="article-row-content-header">{{post.title}}</h1>
|
<i class="fas fa-calendar-alt text-gray-500"></i>
|
||||||
{% if post.subtitle is not None %}
|
<span>{{ post.event_start|date }} · {{ post.event_start|time }} Uhr</span>
|
||||||
<p class="article-row-content-description">{{post.subtitle}}</p>
|
</p>
|
||||||
{% endif %}
|
|
||||||
<!--<p class="article-row-content-author">{{post.author}}</p>-->
|
|
||||||
<time class="article-row-content-time">{{post.event_start|date}}</time>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
<a href="{{ post.url }}">
|
<a href="{{ post.url }}" class="calendar-entry">
|
||||||
<div class="date-box">
|
<div class="calendar-dateBubble">
|
||||||
<span>
|
<span class="dateBubble-day">{{ post.event_start|date:"d" }}</span>
|
||||||
<span class="date-badge badge primary" style="">
|
<span class="dateBubble-month">{{ post.event_start|date:"M" }}</span>
|
||||||
<span class="date-badge-day">{{post.event_start|date:"d"}}</span>
|
|
||||||
<span class="date-badge-month">{{post.event_start|date:"M"}}</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<span class="date-text"><strong>{{post.title}}</strong></span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<h3>{{ post.title }}</h3>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<a href="{{ post.url }}">
|
<div class="my-2">
|
||||||
<article class="article-row">
|
<a href="{{ post.url }}">
|
||||||
<div class="article-row-content">
|
<h3 class="">{{ post.title }}</h3>
|
||||||
<h1 class="article-row-content-header">{{post.title}}</h1>
|
<p class="py-1 text-sm lg:text-base text-gray-600">
|
||||||
{% if post.subtitle is not None %}
|
<i class="fas fa-calendar-alt text-gray-500"></i>
|
||||||
<p class="article-row-content-description">{{post.subtitle}}</p>
|
<span>{{ post.event_start|date }} · {{ post.event_start|time }} Uhr</span>
|
||||||
{% endif %}
|
</p>
|
||||||
<time class="article-row-content-time" datetime="2008-02-14 20:00">{{post.event_start}}</time>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
|
||||||
</a>
|
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
<a href="{{ post.url }}">
|
<article class="article-cover-image" style="background-image: url('{{ post.imageurl }}');" onclick="openArticle('{{ post.url }}')">
|
||||||
<div class="news-hero padding-bottom-1" style="background-image:url('{{ post.imageurl }}')">
|
<div class="article-cover-desc">
|
||||||
<div class="news-hero-text">
|
<div class="article-cover-desc-items">
|
||||||
<h1>{{ post.title | safe }}</h1>
|
<ul class="article-cover-tags">
|
||||||
<h2>{{ post.subtitle|default_if_none:" " }}</h2>
|
<li><a href="#">#fet</a></li>
|
||||||
<p>{{ post.date|date:"d. F Y" }}</p>
|
<li><a href="#">#ug</a></li>
|
||||||
|
<li><a href="#">#öh</a></li>
|
||||||
|
</ul>
|
||||||
|
<div>
|
||||||
|
<a href="{{ post.url }}"><h3 class="text-gray-50">{{ post.title | safe }}</h3></a>
|
||||||
|
<div class="text-gray-200">
|
||||||
|
<i class="fas fa-clock"></i>
|
||||||
|
{{ post.date|date:"d. F Y" }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</article>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<a href="{{ post.url }}">
|
<article class="bg-white rounded shadow transition-all duration-300 hover:shadow-md transform hover:scale-105">
|
||||||
<div class="news-hero-compact">
|
<a href="{{ post.url }}" class="block p-4">
|
||||||
<div class="news-hero-compact-text">
|
<div class="float-right px-2 py-0.5 rounded-full text-sm font-medium text-proprietary bg-blue-100">
|
||||||
<p style="margin-bottom: 0rem;">{{ post.title | safe | truncatechars:60 }}</p>
|
<i class="fa-solid fa-calendar-days mr-1"></i>
|
||||||
|
<p>{{ post.date|date:"d. F Y" }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<h3 class="text-gray-800 leading-relaxed">{{ post.title | safe | truncatechars:60 }}</h3>
|
||||||
<div class="news-hero-compact-right">
|
</a>
|
||||||
<p style="margin-bottom: 0rem;">{{ post.date|date:"d. F Y" }}</p>
|
</article>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
|
|||||||
@@ -1,155 +1,245 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% load post_helpers %}
|
{% load post_helpers %}
|
||||||
{% load admin_urls %}
|
{% load admin_urls %}
|
||||||
|
|
||||||
{% block extraheader %}
|
{% block extraheader %}
|
||||||
<meta content="{{ post.imageurl }}" property="og:image">
|
<meta content="{{ post.imageurl }}" property="og:image">
|
||||||
<meta content="{{ post.title }}" property="og:title">
|
<meta content="{{ post.title }}" property="og:title">
|
||||||
<meta content="article" property="og:type">
|
<meta content="article" property="og:type">
|
||||||
<meta content="" property="og:url">
|
<meta content="" property="og:url">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="large-article-header" style="background-image:url('{{ post.imageurl }}')">
|
<!-- Main Content -->
|
||||||
<div class="large-article-header-content">
|
<main class="container mx-auto w-full flex-1 my-8 sm:flex flex-col sm:px-4">
|
||||||
<div class="center-container">
|
<a href="#" class="hidden z-20 fixed left-0 top-1/2 -mt-8 p-2 xl:flex items-center text-gray-400 rounded-md"
|
||||||
<div class="article-date">
|
x-data="{ showPrevArticleButton : false }"
|
||||||
<p>{{ post.date|date:"d. F Y" }}</p>
|
@mouseleave="showPrevArticleButton = false"
|
||||||
</div>
|
@mouseover="showPrevArticleButton = true"
|
||||||
|
>
|
||||||
|
<i class="fa-light fa-chevron-left text-5xl -m-2 p-2 bg-gray-100 rounded-md"></i>
|
||||||
|
<span class="text-gray-600 font-medium bg-gray-100 -m-2 p-2 rounded-r-md"
|
||||||
|
x-show="showPrevArticleButton"
|
||||||
|
x-transition:enter="transition ease-out duration-300"
|
||||||
|
x-transition:enter-start="opacity-0 bg-opacity-0 transform scale-90"
|
||||||
|
x-transition:enter-end="opacity-100 transform scale-100"
|
||||||
|
x-transition:leave="transition ease-in duration-150"
|
||||||
|
x-transition:leave-start="opacity-100 transform scale-100"
|
||||||
|
x-transition:leave-end="opacity-0 bg-opacity-0 transform scale-100"
|
||||||
|
>Vorheriger<br>Artikel</span>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'posts:posts.show' next %}" class="hidden z-20 fixed right-0 top-1/2 -mt-8 p-2 xl:flex items-center text-gray-400 rounded-md"
|
||||||
|
x-data="{ showNextArticleButton : false }"
|
||||||
|
@mouseleave="showNextArticleButton = false"
|
||||||
|
@mouseover="showNextArticleButton = true"
|
||||||
|
>
|
||||||
|
<span class="z-30 text-gray-600 font-medium bg-gray-100 -m-2 p-2 rounded-l-md text-right"
|
||||||
|
x-show="showNextArticleButton"
|
||||||
|
x-transition:enter="transition ease-out duration-300"
|
||||||
|
x-transition:enter-start="opacity-0 bg-opacity-0 transform scale-90"
|
||||||
|
x-transition:enter-end="opacity-100 transform scale-100"
|
||||||
|
x-transition:leave="transition ease-in duration-150"
|
||||||
|
x-transition:leave-start="opacity-100 transform scale-100"
|
||||||
|
x-transition:leave-end="opacity-0 bg-opacity-0 transform scale-100"
|
||||||
|
>Nächster<br>Artikel</span>
|
||||||
|
<i class="fa-light fa-chevron-right text-5xl -m-2 p-2 bg-gray-100 rounded-md"></i>
|
||||||
|
</a>
|
||||||
|
<section>
|
||||||
|
<div class="mb-4 flex flex-col sm:flex-col gap-2 mx-auto">
|
||||||
|
<ul class="px-4 sm:px-0 mb-2 flex flex-row justify-center gap-2 sm:gap-4 flex-wrap text-blue-700 text-sm uppercase tracking-wide sm:font-medium">
|
||||||
|
<li class="inline-block py-1 px-2 bg-blue-100 rounded-full"><a href="#">#fachschaft</a></li>
|
||||||
|
<li class="inline-block py-1 px-2 bg-blue-100 rounded-full"><a href="#">#WelcomeDay</a></li>
|
||||||
|
<li class="inline-block py-1 px-2 bg-blue-100 rounded-full"><a href="#">#Inskriptionsberatung</a></li>
|
||||||
|
</ul>
|
||||||
|
<h1 class="px-4 sm:px-0 text-lg sm:text-xl lg:text-3xl text-center sm:text-left font-medium text-gray-900 font-serif tracking-wider leading-normal" style="line-height: 1.5;">{{ post.title|tags_to_url }}</h1>
|
||||||
|
<div class="mx-auto max-w-max sm:mx-0 sm:max-w-none sm:flex justify-between items-center">
|
||||||
|
|
||||||
<div class="article-title">
|
<div class="max-w-max flex flex-row justify-center sm:justify-start gap-2 self-center md:self-start">
|
||||||
<h1>{{ post.title|tags_to_url }}</h1>
|
|
||||||
</div>
|
{% if author_image and author %}
|
||||||
|
|
||||||
|
<img class="hidden sm:block w-12 rounded-full" src="{{ author_image }}" alt="Portraitfoto von {{ author.firstname }}">
|
||||||
|
<div class="sm:flex flex-col justify-evenly text-gray-600 text-sm sm:text-base">
|
||||||
|
<a href="{% url 'member' author.id %}" class="underline">{{ author.firstname }}</a>
|
||||||
|
<span class="sm:hidden"> am </span>
|
||||||
|
<span>{{ post.date|date:"d. F Y" }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% elif post.author %}
|
||||||
|
|
||||||
|
<div class="sm:flex flex-col justify-evenly text-gray-600 text-sm sm:text-base">
|
||||||
|
<a class="underline">{{ post.author }}</a>
|
||||||
|
<span class="sm:hidden"> am </span>
|
||||||
|
<span>{{ post.date|date:"d. F Y" }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
<div class="sm:flex flex-col justify-evenly text-gray-600 text-sm sm:text-base">
|
||||||
|
<a class="underline">fet.at Redaktion</a>
|
||||||
|
<span class="sm:hidden"> am </span>
|
||||||
|
<span>{{ post.date|date:"d. F Y" }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="article-details">
|
|
||||||
<a>
|
|
||||||
{{ post.subtitle|default_if_none:" "|tags_to_url }}
|
|
||||||
</a>
|
|
||||||
{% if author_image and author %}
|
|
||||||
<div class="article-author">
|
|
||||||
<a href="{% url 'member' author.id %}">
|
|
||||||
<img src="{{ author_image }}" alt="" /> {{ author.firstname }}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{% elif post.author %}
|
|
||||||
<div class="article-author">
|
{% if request.user.is_authenticated %}
|
||||||
<a href="">
|
{% if post.post_type == 'N' %}
|
||||||
<img src="" alt="" />{{ post.author }}
|
<a href="{% url 'admin:posts_news_change' post.id %}" class="hidden sm:block btn-small btn-primary">
|
||||||
</a>
|
<i class="fa-regular fa-pen-to-square mr-1"></i>Artikel bearbeiten
|
||||||
</div>
|
</a>
|
||||||
{% else %}
|
{% elif post.post_type == 'E' %}
|
||||||
<div class="article-author">
|
<a href="{% url 'admin:posts_event_change' post.id %}" class="hidden sm:block btn-small btn-primary">
|
||||||
<a href="">
|
<i class="fa-regular fa-pen-to-square mr-1"></i>Event bearbeiten
|
||||||
<img src="" alt="" />fet.at Redaktion
|
</a>
|
||||||
</a>
|
{% elif post.post_type == 'F' %}
|
||||||
|
<a href="{% url 'admin:posts_fetmeeting_change' post.id %}" class="hidden sm:block btn-small btn-primary">
|
||||||
|
<i class="fa-regular fa-pen-to-square mr-1"></i>FET Sitzung bearbeiten
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <img src="img/article-cover-3.jpg" alt="" class="h-44 sm:h-56 lg:h-64 xl:h-80 w-full object-cover sm:rounded-md max-w-5xl mx-auto"> -->
|
||||||
|
<div class="relative w-full h-44 sm:h-56 lg:h-64 xl:h-80 bg-center bg-no-repeat bg-cover sm:rounded-md mx-auto" style="background-image: url('{{ post.imageurl }}');">
|
||||||
|
|
||||||
|
{% if post.post_type != 'N' %}
|
||||||
|
<div class="hidden absolute top-0 right-0 bg-white rounded-bl p-2 bg-opacity-80 lg:flex items-center gap-2">
|
||||||
|
<i class="flex-0 fa-solid fa-calendar-clock text-gray-800"></i>
|
||||||
|
<span class="flex-1 text-sm text-gray-800">
|
||||||
|
Event-Start: {{ post.event_start|date }} um {{ post.event_start|time }} Uhr<br>
|
||||||
|
Event-Ende: {{ post.event_end|date }} um {{ post.event_end|time }} Uhr
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid-container">
|
</div>
|
||||||
<div class="grid-x grid-padding-x padding-top-1">
|
</section>
|
||||||
<div class="cell medium-8">
|
<section class="mx-4 z-10">
|
||||||
{% for tag in post.get_tagnames %}
|
<article class="p-4 mt-4 sm:-mt-16 w-full max-w-prose mx-auto bg-white rounded">
|
||||||
{{ tag|tags_to_url }}
|
<!-- <div class="w-full flex justify-end">
|
||||||
{% endfor %}
|
<div class="hidden lg:block max-w-max text-sm text-gray-600">
|
||||||
<hr>
|
Event-Start: 23. August 2021 um 18:00 Uhr<br>
|
||||||
|
Event-Ende: 23. August 2021 um 20:00 Uhr
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="db-page-content-left">
|
||||||
|
<!-- Content from DB here: -->
|
||||||
|
|
||||||
{% if post.has_agenda %}
|
{% if request.user.is_authenticated %}
|
||||||
<h2>Agenda<a class="headerlink" id="agenda" href="#agenda" title="Permalink to Agenda"> #</a></h2>
|
<hr>
|
||||||
{{ post.agenda_html|safe }}
|
|
||||||
<hr>
|
|
||||||
{% elif post.body %}
|
|
||||||
{{ post.body|safe|add_internal_links|tags_to_url }}
|
|
||||||
<hr>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if request.user.is_authenticated and post.has_protocol %}
|
{% if post.has_agenda %}
|
||||||
<h2>Protokoll<a class="headerlink" id="protocol" href="#protocol" title="Permalink to Protokoll"> #</a></h2>
|
<a href="{{ ep_agenda_link }}">Agenda</a>
|
||||||
{{ post.protocol_html|safe }}
|
{% if filename_agenda %}
|
||||||
<hr>
|
<a href="{% url 'posts:show_pdf_agenda' post.slug %}">
|
||||||
{% endif %}
|
<i class="far fa-file-pdf"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<br>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
{% if post.has_protocol %}
|
||||||
<div class="cell medium-4">
|
<a href="{{ ep_protocol_link }}">Protokoll</a>
|
||||||
<a href="{% url 'posts:posts.show' next %}">Nächster Artikel <span class="nav fa fa-chevron-right fa-1x"></span></a><br>
|
{% if filename_protocol %}
|
||||||
|
<a href="{% url 'posts:show_pdf_protocol' post.slug %}">
|
||||||
|
<i class="far fa-file-pdf"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<br>
|
||||||
|
<hr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if post.has_agenda %}
|
||||||
|
<h2>Agenda</h2>
|
||||||
|
{{ post.agenda_html|safe }}
|
||||||
|
<hr>
|
||||||
|
{% elif post.body %}
|
||||||
|
{{ post.body|safe|add_internal_links|tags_to_url }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if request.user.is_authenticated and post.has_protocol %}
|
||||||
|
<h2>Protokoll</h2>
|
||||||
|
{{ post.protocol_html|safe }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if files %}
|
||||||
|
<hr>
|
||||||
|
Dokumente:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for file in files %}
|
||||||
|
<li><a href="{{file.file_field.url}}" target="_blank">{{file.title}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<hr class="lg:hidden -mx-4 border-gray-200 border-1 my-4">
|
||||||
|
<div class="lg:hidden">
|
||||||
|
<h2 class="text-gray-800 font-medium"><i class="fa-solid fa-calendar-days mr-2 text-gray-400"></i>Termindetails:</h2>
|
||||||
|
<ul class="text-base text-gray-700 my-1">
|
||||||
|
<li>Start:	{{ post.event_start|date }} um {{ post.event_start|time }} Uhr</li>
|
||||||
|
<li>Ende:	{{ post.event_end|date }} um {{ post.event_end|time }} Uhr</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<hr class="-mx-4 border-gray-200 border-1 my-4">
|
||||||
|
<div class="-m-4 flex divide-x divide-gray-200 text-sm sm:text-base">
|
||||||
|
<a href="#" class="w-1/2 p-4 flex items-center gap-2">
|
||||||
|
<i class="fa-solid fa-chevron-left text-gray-600"></i>
|
||||||
|
<span class="text-gray-700 font-medium">Vorheriger Artikel</span>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'posts:posts.show' next %}" class="w-1/2 p-4 flex flex-row-reverse items-center gap-2">
|
||||||
|
<i class="fa-solid fa-chevron-right text-gray-600"></i>
|
||||||
|
<span class="text-gray-700 font-medium">Nächster Artikel</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<hr>
|
|
||||||
|
|
||||||
{% if post.has_agenda %}
|
|
||||||
<a href="{{ ep_agenda_link }}">Agenda</a>
|
|
||||||
{% if filename_agenda %}
|
|
||||||
<a href="{% url 'posts:show_pdf_agenda' post.slug %}">
|
|
||||||
<i class="far fa-file-pdf"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<br>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if post.has_protocol %}
|
|
||||||
<a href="{{ ep_protocol_link }}">Protokoll</a>
|
|
||||||
{% if filename_protocol %}
|
|
||||||
<a href="{% url 'posts:show_pdf_protocol' post.slug %}">
|
|
||||||
<i class="far fa-file-pdf"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<br>
|
|
||||||
<hr>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if post.post_type == 'N' %}
|
{% if post.post_type == 'N' %}
|
||||||
<a href="{% url 'admin:posts_news_change' post.id %}">News bearbeiten</a>
|
<a href="{% url 'admin:posts_news_change' post.id %}" class="sm:hidden block w-full btn btn-primary mt-4">
|
||||||
|
<i class="fa-regular fa-pen-to-square mr-1"></i>Artikel bearbeiten
|
||||||
|
</a>
|
||||||
{% elif post.post_type == 'E' %}
|
{% elif post.post_type == 'E' %}
|
||||||
<a href="{% url 'admin:posts_event_change' post.id %}">Event bearbeiten</a>
|
<a href="{% url 'admin:posts_event_change' post.id %}" class="sm:hidden block w-full btn btn-primary mt-4">
|
||||||
|
<i class="fa-regular fa-pen-to-square mr-1"></i>Event bearbeiten
|
||||||
|
</a>
|
||||||
{% elif post.post_type == 'F' %}
|
{% elif post.post_type == 'F' %}
|
||||||
<a href="{% url 'admin:posts_fetmeeting_change' post.id %}">FET Sitzung bearbeiten</a>
|
<a href="{% url 'admin:posts_fetmeeting_change' post.id %}" class="sm:hidden block w-full btn btn-primary mt-4">
|
||||||
|
<i class="fa-regular fa-pen-to-square mr-1"></i>FET Sitzung bearbeiten
|
||||||
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
|
||||||
{% if post.event_start %}
|
{% if related_posts %}
|
||||||
<hr>
|
<section class="mx-auto w-full px-4">
|
||||||
Start: {{ post.event_start|date:"d. F Y" }} {{ post.event_start|time:"H:i" }}<br>
|
<h2 class="my-4 sm:my-8 text-proprietary text-xl text-center uppercase tracking-wider">Weiterlesen</h2>
|
||||||
{% endif %}
|
|
||||||
{% if post.event_end %}
|
|
||||||
Ende: {{ post.event_end|date:"d. F Y" }} {{ post.event_end|time:"H:i" }}<br>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if post.event_place %}
|
{% for post in related_posts %}
|
||||||
Ort: {{ post.event_place }}
|
<a href="{{ post.url }}" class="sm:flex-1 block rounded bg-white shadow-md bg-no-repeat bg-center h-56 transition-all ease-in-out duration-500 bg-scale-100 hover:bg-scale-120" style="background-image: url('{{ post.imageurl }}');">
|
||||||
{% endif %}
|
<div class="w-full h-full bg-gradient-to-t from-black rounded-md flex flex-col justify-end p-2">
|
||||||
|
<h2 class="text-gray-50 line-clamp-2"><span aria-label="Link zum Artikel: "></span>{{ post.title | safe }}</h2>
|
||||||
{% if post.event_start %}
|
<span class="text-gray-300 text-sm">
|
||||||
{% include 'posts/partials/_date_box.html' %}
|
<i class="fas fa-clock mr-1"></i>
|
||||||
{% endif %}
|
<span aria-label=" vom "></span>
|
||||||
|
{% if post.post_type != 'N' %}
|
||||||
{% if files %}
|
{{ post.event_start|date:"d. F Y" }}
|
||||||
<hr>
|
{% else %}
|
||||||
Dokumente:
|
{{ post.public_date|date:"d. F Y" }}
|
||||||
|
{% endif %}
|
||||||
<ul>
|
</span>
|
||||||
{% for file in files %}
|
</div>
|
||||||
<li><a href="{{file.file_field.url}}" target="_blank">{{file.title}}</a></li>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</section>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
</main>
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid-x grid-margin-x">
|
|
||||||
{% for post in related_posts %}
|
|
||||||
<div class="medium-6 large-4 small-12 cell">
|
|
||||||
{% include 'posts/partials/_posts_hero.html' %}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user