mirror of https://github.com/Facinorous-420/dick
- infinite scroll pagination added - custom port fixed - some code clean up - fix admin page route (band-aid) - add on hover tooltip for truncated item names - add convertToPaginatedArray util function - fix console errors due to having js files on pages i wasnt needed on | nicepull/15/head
parent
e95fd10f0e
commit
5049465a78
@ -1,205 +1,196 @@
|
||||
// DOM Ready Function
|
||||
function ready(fn) {
|
||||
if (document.readyState != 'loading') {
|
||||
fn();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fn);
|
||||
if (document.readyState != 'loading') {
|
||||
fn()
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DOM Ready Called
|
||||
ready(function () {
|
||||
|
||||
const openFile = document.getElementById('openFile');
|
||||
const showFile = document.getElementById('showFile');
|
||||
|
||||
const traMove = document.getElementsByClassName('traMove');
|
||||
const tabsProfile = document.getElementsByClassName('tabsProfile');
|
||||
const tabsProfileContent = document.getElementsByClassName('tabsProfileContent');
|
||||
const dropdownNavBtn = document.getElementById('dropdownNavBtn');
|
||||
const dropdownNav = document.getElementById('dropdownNav');
|
||||
|
||||
const dropdownProfileBtn = document.getElementsByClassName('dropdownProfileBtn');
|
||||
const dropdownProfile = document.getElementsByClassName('dropdownProfile');
|
||||
|
||||
const dropdownSearchBtn = document.getElementsByClassName('dropdownSearchBtn');
|
||||
const dropdownSearch = document.getElementsByClassName('dropdownSearch');
|
||||
const dropdownFileBtn = document.getElementsByClassName('dropdownFileBtn');
|
||||
|
||||
// Open File Manager Event
|
||||
/*
|
||||
function fireFileManager(){
|
||||
openFile.addEventListener('click', () => {
|
||||
showFile.click();
|
||||
});
|
||||
}
|
||||
fireFileManager();
|
||||
*/
|
||||
|
||||
// Dropdown Navbar Event
|
||||
function fireDropdownNav(){
|
||||
dropdownNavBtn.addEventListener('click', () => {
|
||||
if (dropdownNav.classList.contains('-translate-y-full')) {
|
||||
dropdownNav.classList.remove('-translate-y-full');
|
||||
dropdownNav.classList.add('translate-y-0', 'ease-linear');
|
||||
|
||||
// When the event get fired, every 'traMove' id attibute will move down
|
||||
Array.prototype.forEach.call(traMove, (e) => {
|
||||
e.classList.remove('-translate-y-32');
|
||||
e.classList.add('translate-y-0', 'ease-linear');
|
||||
});
|
||||
} else {
|
||||
dropdownNav.classList.add('-translate-y-full',);
|
||||
dropdownNav.classList.remove('translate-y-0', 'ease-linear');
|
||||
|
||||
// Then if you hide the event, every 'traMove' id attribute will back to normal
|
||||
Array.prototype.forEach.call(traMove, (e) => {
|
||||
e.classList.add('-translate-y-32');
|
||||
e.classList.remove('translate-y-0', 'ease-linear');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
fireDropdownNav();
|
||||
|
||||
// Dropdown Profile Event
|
||||
function fireDropdownProfile() {
|
||||
Array.prototype.forEach.call(dropdownProfileBtn, function (e, index) {
|
||||
e.addEventListener('click', () => {
|
||||
var timer;
|
||||
if (dropdownProfile[index].classList.contains('opacity-0')) {
|
||||
window.clearTimeout(timer);
|
||||
dropdownProfile[index].classList.remove('opacity-0', 'translate-y-6', 'invisible');
|
||||
dropdownProfile[index].classList.add('translate-y-0', 'opacity-100');
|
||||
} else {
|
||||
dropdownProfile[index].classList.add('opacity-0', 'translate-y-6');
|
||||
dropdownProfile[index].classList.remove('translate-y-0', 'opacity-100');
|
||||
|
||||
//Set timer to hide the dropdown
|
||||
//the value of timer '250' must be same as the tailwind class 'duration-250' in the class dropdownProfile attribute
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownProfile[index].classList.add('invisible');
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
|
||||
// Click outside event
|
||||
window.addEventListener('click', (eve) => {
|
||||
if (!dropdownProfileBtn[index].contains(eve.target) && !dropdownProfile[index].contains(eve.target)) {
|
||||
dropdownProfile[index].classList.add('opacity-0', 'translate-y-6');
|
||||
dropdownProfile[index].classList.remove('translate-y-0', 'opacity-100');
|
||||
|
||||
// Same as above
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownProfile[index].classList.add('invisible');
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
fireDropdownProfile();
|
||||
|
||||
|
||||
// Dropdown Search Event
|
||||
function fireDropdownSearch() {
|
||||
Array.prototype.forEach.call(dropdownSearchBtn, (e, index) => {
|
||||
e.addEventListener('click', () => {
|
||||
var timer;
|
||||
if (dropdownSearch[index].classList.contains('opacity-0')) {
|
||||
window.clearTimeout(timer);
|
||||
dropdownSearch[index].classList.remove('opacity-0', 'translate-y-6', 'invisible');
|
||||
dropdownSearch[index].classList.add('translate-y-0', 'opacity-100');
|
||||
} else {
|
||||
dropdownSearch[index].classList.add('opacity-0', 'translate-y-6');
|
||||
dropdownSearch[index].classList.remove('translate-y-0', 'opacity-100');
|
||||
|
||||
//Set timer to hide the dropdown
|
||||
//the value of timer '250' must be same as the tailwind class 'duration-250' in the class dropdownSearch attribute
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownSearch[index].classList.add('invisible');
|
||||
}, 250);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Click outside event
|
||||
window.addEventListener('click', (eve) => {
|
||||
if (!dropdownSearchBtn[index].contains(eve.target) && !dropdownSearch[index].contains(eve.target)) {
|
||||
dropdownSearch[index].classList.add('opacity-0', 'translate-y-6');
|
||||
dropdownSearch[index].classList.remove('translate-y-0', 'opacity-100');
|
||||
|
||||
// Same as above
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownSearch[index].classList.add('invisible');
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
fireDropdownSearch();
|
||||
|
||||
// Dropdown File Event
|
||||
function fireDropdownFile() {
|
||||
Array.prototype.forEach.call(dropdownFileBtn, (e, index) => {
|
||||
const findSibling = e.parentElement.children[1];
|
||||
e.addEventListener('click', () => {
|
||||
var timer;
|
||||
if (findSibling.classList.contains('opacity-0')) {
|
||||
window.clearTimeout(timer);
|
||||
findSibling.classList.remove('opacity-0', 'translate-y-6', 'invisible');
|
||||
findSibling.classList.add('translate-y-0', 'opacity-100');
|
||||
} else {
|
||||
findSibling.classList.add('opacity-0', 'translate-y-6');
|
||||
findSibling.classList.remove('translate-y-0', 'opacity-100');
|
||||
|
||||
//Set timer to hide the dropdown
|
||||
//the value of timer '250' must be same as the tailwind class 'duration-250' in the class dropdownFile attribute
|
||||
timer = window.setTimeout( () => {
|
||||
findSibling.classList.add('invisible');
|
||||
}, 250);
|
||||
}
|
||||
});
|
||||
|
||||
// Click outside event
|
||||
window.addEventListener('click', (eve) => {
|
||||
if (!dropdownFileBtn[index].contains(eve.target) && !findSibling.contains(eve.target)) {
|
||||
findSibling.classList.add('opacity-0', 'translate-y-6');
|
||||
findSibling.classList.remove('translate-y-0', 'opacity-100');
|
||||
|
||||
// Same as above
|
||||
timer = window.setTimeout( () => {
|
||||
findSibling.classList.add('invisible');
|
||||
}, 250);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
fireDropdownFile();
|
||||
|
||||
// Tabs Profile Event
|
||||
function fireTabsProfile(){
|
||||
//File Manager Tab = 0
|
||||
tabsProfile[0].addEventListener('click', () => {
|
||||
if (tabsProfile[1].classList.contains('border-b-2', 'border-purple-400', 'font-semibold')) {
|
||||
tabsProfile[1].classList.remove('border-b-2', 'border-purple-400', 'font-semibold');
|
||||
tabsProfile[0].classList.add('border-b-2', 'border-purple-400', 'font-semibold');
|
||||
tabsProfileContent[1].classList.add('hidden');
|
||||
tabsProfileContent[0].classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
//Config Gen Tab = 1
|
||||
tabsProfile[1].addEventListener('click', () => {
|
||||
if (tabsProfile[0].classList.contains('border-b-2', 'border-purple-400', 'font-semibold')) {
|
||||
tabsProfile[0].classList.remove('border-b-2', 'border-purple-400', 'font-semibold');
|
||||
tabsProfile[1].classList.add('border-b-2', 'border-purple-400', 'font-semibold');
|
||||
tabsProfileContent[0].classList.add('hidden');
|
||||
tabsProfileContent[1].classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
fireTabsProfile();
|
||||
|
||||
});
|
||||
|
||||
// DOM Ready Called
|
||||
ready(function () {
|
||||
|
||||
const openFile = document.getElementById('openFile')
|
||||
const showFile = document.getElementById('showFile')
|
||||
|
||||
const traMove = document.getElementsByClassName('traMove')
|
||||
const tabsProfile = document.getElementsByClassName('tabsProfile')
|
||||
const tabsProfileContent = document.getElementsByClassName('tabsProfileContent')
|
||||
const dropdownNavBtn = document.getElementById('dropdownNavBtn')
|
||||
const dropdownNav = document.getElementById('dropdownNav')
|
||||
|
||||
const dropdownProfileBtn = document.getElementsByClassName('dropdownProfileBtn')
|
||||
const dropdownProfile = document.getElementsByClassName('dropdownProfile')
|
||||
|
||||
const dropdownSearchBtn = document.getElementsByClassName('dropdownSearchBtn')
|
||||
const dropdownSearch = document.getElementsByClassName('dropdownSearch')
|
||||
const dropdownFileBtn = document.getElementsByClassName('dropdownFileBtn')
|
||||
|
||||
// Open File Manager Event
|
||||
/*
|
||||
function fireFileManager(){
|
||||
openFile.addEventListener('click', () => {
|
||||
showFile.click();
|
||||
});
|
||||
}
|
||||
fireFileManager();
|
||||
*/
|
||||
|
||||
// Dropdown Navbar Event
|
||||
function fireDropdownNav(){
|
||||
dropdownNavBtn.addEventListener('click', () => {
|
||||
if (dropdownNav.classList.contains('-translate-y-full')) {
|
||||
dropdownNav.classList.remove('-translate-y-full')
|
||||
dropdownNav.classList.add('translate-y-0', 'ease-linear')
|
||||
// When the event get fired, every 'traMove' id attibute will move down
|
||||
Array.prototype.forEach.call(traMove, (e) => {
|
||||
e.classList.remove('-translate-y-32')
|
||||
e.classList.add('translate-y-0', 'ease-linear')
|
||||
})
|
||||
} else {
|
||||
dropdownNav.classList.add('-translate-y-full',)
|
||||
dropdownNav.classList.remove('translate-y-0', 'ease-linear')
|
||||
// Then if you hide the event, every 'traMove' id attribute will back to normal
|
||||
Array.prototype.forEach.call(traMove, (e) => {
|
||||
e.classList.add('-translate-y-32')
|
||||
e.classList.remove('translate-y-0', 'ease-linear')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
fireDropdownNav()
|
||||
|
||||
// Dropdown Profile Event
|
||||
function fireDropdownProfile() {
|
||||
Array.prototype.forEach.call(dropdownProfileBtn, function (e, index) {
|
||||
e.addEventListener('click', () => {
|
||||
var timer
|
||||
if (dropdownProfile[index].classList.contains('opacity-0')) {
|
||||
window.clearTimeout(timer)
|
||||
dropdownProfile[index].classList.remove('opacity-0', 'translate-y-6', 'invisible')
|
||||
dropdownProfile[index].classList.add('translate-y-0', 'opacity-100')
|
||||
} else {
|
||||
dropdownProfile[index].classList.add('opacity-0', 'translate-y-6')
|
||||
dropdownProfile[index].classList.remove('translate-y-0', 'opacity-100')
|
||||
//Set timer to hide the dropdown
|
||||
//the value of timer '250' must be same as the tailwind class 'duration-250' in the class dropdownProfile attribute
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownProfile[index].classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
})
|
||||
// Click outside event
|
||||
window.addEventListener('click', (eve) => {
|
||||
if (!dropdownProfileBtn[index].contains(eve.target) && !dropdownProfile[index].contains(eve.target)) {
|
||||
dropdownProfile[index].classList.add('opacity-0', 'translate-y-6')
|
||||
dropdownProfile[index].classList.remove('translate-y-0', 'opacity-100')
|
||||
// Same as above
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownProfile[index].classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
fireDropdownProfile()
|
||||
|
||||
|
||||
// Dropdown Search Event
|
||||
function fireDropdownSearch() {
|
||||
Array.prototype.forEach.call(dropdownSearchBtn, (e, index) => {
|
||||
e.addEventListener('click', () => {
|
||||
var timer
|
||||
if (dropdownSearch[index].classList.contains('opacity-0')) {
|
||||
window.clearTimeout(timer)
|
||||
dropdownSearch[index].classList.remove('opacity-0', 'translate-y-6', 'invisible')
|
||||
dropdownSearch[index].classList.add('translate-y-0', 'opacity-100')
|
||||
} else {
|
||||
dropdownSearch[index].classList.add('opacity-0', 'translate-y-6')
|
||||
dropdownSearch[index].classList.remove('translate-y-0', 'opacity-100')
|
||||
|
||||
//Set timer to hide the dropdown
|
||||
//the value of timer '250' must be same as the tailwind class 'duration-250' in the class dropdownSearch attribute
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownSearch[index].classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
})
|
||||
|
||||
// Click outside event
|
||||
window.addEventListener('click', (eve) => {
|
||||
if (!dropdownSearchBtn[index].contains(eve.target) && !dropdownSearch[index].contains(eve.target)) {
|
||||
dropdownSearch[index].classList.add('opacity-0', 'translate-y-6')
|
||||
dropdownSearch[index].classList.remove('translate-y-0', 'opacity-100')
|
||||
|
||||
// Same as above
|
||||
timer = window.setTimeout( () => {
|
||||
dropdownSearch[index].classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
fireDropdownSearch()
|
||||
|
||||
// Dropdown File Event
|
||||
function fireDropdownFile() {
|
||||
Array.prototype.forEach.call(dropdownFileBtn, (e, index) => {
|
||||
const findSibling = e.parentElement.children[1]
|
||||
e.addEventListener('click', () => {
|
||||
var timer
|
||||
if (findSibling.classList.contains('opacity-0')) {
|
||||
window.clearTimeout(timer)
|
||||
findSibling.classList.remove('opacity-0', 'translate-y-6', 'invisible')
|
||||
findSibling.classList.add('translate-y-0', 'opacity-100')
|
||||
} else {
|
||||
findSibling.classList.add('opacity-0', 'translate-y-6')
|
||||
findSibling.classList.remove('translate-y-0', 'opacity-100')
|
||||
|
||||
//Set timer to hide the dropdown
|
||||
//the value of timer '250' must be same as the tailwind class 'duration-250' in the class dropdownFile attribute
|
||||
timer = window.setTimeout( () => {
|
||||
findSibling.classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
})
|
||||
|
||||
// Click outside event
|
||||
window.addEventListener('click', (eve) => {
|
||||
if (!dropdownFileBtn[index].contains(eve.target) && !findSibling.contains(eve.target)) {
|
||||
findSibling.classList.add('opacity-0', 'translate-y-6')
|
||||
findSibling.classList.remove('translate-y-0', 'opacity-100')
|
||||
|
||||
// Same as above
|
||||
timer = window.setTimeout( () => {
|
||||
findSibling.classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
fireDropdownFile()
|
||||
|
||||
// Tabs Profile Event
|
||||
function fireTabsProfile(){
|
||||
//File Manager Tab = 0
|
||||
tabsProfile[0].addEventListener('click', () => {
|
||||
if (tabsProfile[1].classList.contains('border-b-2', 'border-purple-400', 'font-semibold')) {
|
||||
tabsProfile[1].classList.remove('border-b-2', 'border-purple-400', 'font-semibold')
|
||||
tabsProfile[0].classList.add('border-b-2', 'border-purple-400', 'font-semibold')
|
||||
tabsProfileContent[1].classList.add('hidden')
|
||||
tabsProfileContent[0].classList.remove('hidden')
|
||||
}
|
||||
});
|
||||
//Config Gen Tab = 1
|
||||
tabsProfile[1].addEventListener('click', () => {
|
||||
if (tabsProfile[0].classList.contains('border-b-2', 'border-purple-400', 'font-semibold')) {
|
||||
tabsProfile[0].classList.remove('border-b-2', 'border-purple-400', 'font-semibold')
|
||||
tabsProfile[1].classList.add('border-b-2', 'border-purple-400', 'font-semibold')
|
||||
tabsProfileContent[0].classList.add('hidden')
|
||||
tabsProfileContent[1].classList.remove('hidden')
|
||||
}
|
||||
})
|
||||
}
|
||||
fireTabsProfile()
|
||||
})
|
@ -0,0 +1,74 @@
|
||||
<div class="bg-tertiary h-auto w-36 cursor-pointer rounded-md p-3 transition duration-300 ease-in-out hover:scale-105 hover:shadow-xl sm:w-44 md:w-[139px] lg:w-40">
|
||||
<!-- File Header -->
|
||||
<div class="flex flex-row flex-nowrap items-center justify-between">
|
||||
<!--We will add this and style it when we add multi-delete, for now eggplant
|
||||
<input class="accent-blue-700 rounded-md h-3 w-4 md:h-4 md:w-5 lg:h-4 lg:w-4" type="checkbox" />
|
||||
-->
|
||||
<span>🍆</span>
|
||||
|
||||
<div class="relative">
|
||||
<!-- File Dropdown Button -->
|
||||
<button class="dropdownFileBtn relative text-gray-400">
|
||||
<svg class="relative h-3 w-3 md:h-4 md:w-4 lg:h-4 lg:w-4" xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle class="relative" cx="12" cy="12" r="1"></circle>
|
||||
<circle class="relative" cx="12" cy="5" r="1"></circle>
|
||||
<circle class="relative" cx="12" cy="19" r="1"></circle>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- End File Dropdown Button -->
|
||||
|
||||
<!-- File Dropdown -->
|
||||
<div class="dropdownFile duration-250 bg-tertiary invisible absolute top-6 right-0 z-10 h-auto w-36 translate-y-6 rounded-lg opacity-0 shadow-lg transition ease-linear">
|
||||
<!-- File Dropdown Menu-->
|
||||
<div class="grid grid-cols-1 px-3 py-2 space-y-2 shadow-xl">
|
||||
<button onClick="copyLink('${id}')" data-tooltip-target="${id}-copy" data-tooltip-trigger="click" class="tooltip dropdown-item w-full rounded-md p-2 text-color-primary hover:bg-tertiary-hover">
|
||||
<i data-lucide="link" class="w-4 h-4 mr-2 inline"></i>
|
||||
Copy Link
|
||||
</button>
|
||||
<div id="${id}-copy" role="tooltip" class="inline-block absolute invisible z-10 py-2 px-3 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
|
||||
Link copied to clipboard!
|
||||
<div class="tooltip-arrow" data-popper-arrow></div>
|
||||
</div>
|
||||
|
||||
<button onClick="deleteItem('${id}', '${deleteId}')" data-tooltip-target="${id}-delete" data-tooltip-trigger="click"
|
||||
class="tooltip dropdown-item w-full rounded-md p-2 text-color-primary hover:bg-tertiary-hover">
|
||||
<i data-lucide="trash" class="w-4 h-4 mr-2 inline"></i>
|
||||
Delete
|
||||
</button>
|
||||
<div id="${id}-delete" role="tooltip" class="inline-block absolute invisible z-10 py-2 px-3 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
|
||||
Item is being deleted, page will refresh when finished.
|
||||
<div class="tooltip-arrow" data-popper-arrow></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End File Dropdown Menu-->
|
||||
</div>
|
||||
<!-- File Dropdown -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- End File Header -->
|
||||
|
||||
<div class="space-y-3">
|
||||
|
||||
<a target="_blank" href='${itemURL}'>
|
||||
<div class="mt-2 flex flex-wrap items-center justify-center">
|
||||
<img class="h-20 w-auto rounded-md object-cover object-center md:h-24 lg:h-24"
|
||||
src='${itemURL}/direct' alt=${originalName} />
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="has-name-tooltip text-center">
|
||||
<a target="_blank" href='${itemURL}' class="text-base font-medium text-color-primary hover:text-color-accent md:text-lg lg:text-lg">
|
||||
<span class='name-tooltip rounded shadow-lg p-2 bg-primary text-color-primary -mt-8'>${originalName}</span>
|
||||
<p class="truncate">${originalName}</p>
|
||||
</a>
|
||||
<div class="text-xs text-gray-400 md:text-sm lg:text-sm">
|
||||
${timeStamp}
|
||||
</div>
|
||||
<div class="text-xs text-gray-400">
|
||||
${size}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,12 @@
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-center flex-col items-center space-y-2">
|
||||
<svg class="animate-spin text-purple-400 w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 2v6h-6"></path>
|
||||
<path d="M3 12a9 9 0 0 1 15-6.7L21 8"></path>
|
||||
<path d="M3 22v-6h6"></path>
|
||||
<path d="M21 12a9 9 0 0 1-15 6.7L3 16"></path>
|
||||
</svg>
|
||||
<span class="font-semibold text-white">Loading more files...</span>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,184 @@
|
||||
<script>
|
||||
function ready(fn) {
|
||||
if (document.readyState != 'loading') {
|
||||
fn()
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fn)
|
||||
}
|
||||
}
|
||||
|
||||
ready(function () {
|
||||
|
||||
// Set the default number of current pagination
|
||||
let defaultNumber = 0
|
||||
|
||||
// Transfer ASS system variables from EJS to front end
|
||||
const assSecure = <%- assSecure %>;
|
||||
const assDomain = '<%- assDomain %>'
|
||||
// Variables used in converting size
|
||||
const k = 1024
|
||||
const dm = 2
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
|
||||
// Data (I dont like this being here ngl)
|
||||
const userData = <%- JSON.stringify(usersDataObj.data) %>;
|
||||
|
||||
// When pagination reach the end, its still add more items with undefined array, remove it
|
||||
const currentPaginationRaw = []
|
||||
const currentPagination = currentPaginationRaw.filter(Boolean)
|
||||
|
||||
function appendHtml(items, card, type) {
|
||||
items.insertAdjacentHTML(type, card)
|
||||
}
|
||||
|
||||
function showData() {
|
||||
// Check if the current pahe has no data
|
||||
if (currentPagination.length == 0) {
|
||||
// Push the first userData page to currentPagination
|
||||
currentPagination.push(userData[0])
|
||||
}
|
||||
// Loops the first userData page when page loaded
|
||||
userData[0].forEach(item => {
|
||||
const items = document.getElementById('appendItems')
|
||||
const i = Math.floor(Math.log(item.size) / Math.log(k))
|
||||
let card = ``
|
||||
// Variables used in card items
|
||||
const { originalName, fileExtension, id, deleteId } = item
|
||||
const size = parseFloat((item.size / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
|
||||
const timeStamp = new Date(item.timestamp).toISOString().split('T')[0]
|
||||
const itemURL = assSecure ? `https://${assDomain}/${item.id}` : `http://${assDomain}/${item.id}`
|
||||
// The card items
|
||||
if (item.type == 'image') {
|
||||
card = `<%- include("./image-item") %>`
|
||||
} else {
|
||||
card = `<%- include("./other-item") %>`
|
||||
}
|
||||
appendHtml(items, card, 'beforeend')
|
||||
})
|
||||
}
|
||||
showData()
|
||||
|
||||
// Once the user reaches the end of the currentPagination content (bottom of page)
|
||||
document.addEventListener('scroll', () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = document.documentElement
|
||||
// Refresh icon with spin animation
|
||||
const spinLoading = `<%- include("./loading") %>`
|
||||
// No more items to load text
|
||||
const endLoop = `<%- include("./no-more-data") %>`
|
||||
// Loading items animation
|
||||
const loading = document.getElementById('loading')
|
||||
// Add class invisible to hide loading animation at first load
|
||||
loading.classList.add('invisible')
|
||||
// Check if the users scroll distance has reached the bottom of page
|
||||
if (clientHeight + scrollTop >= scrollHeight - 2) {
|
||||
// Show the hidden loading animation
|
||||
if (loading.classList.contains('invisible')) {
|
||||
loading.classList.remove('invisible')
|
||||
}
|
||||
// Check if the userData length is greater than current pagination data, if so still need to load more pages
|
||||
if (userData.length > currentPagination.length) {
|
||||
// Show spin lodaing
|
||||
loading.innerHTML = spinLoading
|
||||
// Set timer to load more data
|
||||
setTimeout(appendData, 2000)
|
||||
// else its end of the pagination
|
||||
} else {
|
||||
// Show no items icon
|
||||
loading.innerHTML = endLoop
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// This will append more cards to the page when we reach the bottom if there is more to load
|
||||
function appendData() {
|
||||
// Check if currentPagination is greater than the default number.
|
||||
if (defaultNumber < currentPagination.length) {
|
||||
defaultNumber++
|
||||
const morePage = defaultNumber
|
||||
|
||||
if (morePage != userData.length) {
|
||||
// Push the next page from userData into current paginationData
|
||||
currentPagination.push(userData[morePage])
|
||||
// Loops through the new pagination data
|
||||
userData[morePage].forEach(item => {
|
||||
const items = document.getElementById('appendItems')
|
||||
const i = Math.floor(Math.log(item.size) / Math.log(k))
|
||||
let card = ``
|
||||
// Variables used in card items
|
||||
const { originalName, fileExtension, id, deleteId } = item
|
||||
const size = parseFloat((item.size / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
|
||||
const timeStamp = new Date(item.timestamp).toISOString().split('T')[0]
|
||||
const itemURL = assSecure ? `https://${assDomain}/${item.id}` : `http://${assDomain}/${item.id}`
|
||||
// The card items
|
||||
if (item.type == 'image') {
|
||||
card = `<%- include("./image-item") %>`
|
||||
} else {
|
||||
card = `<%- include("./other-item") %>`
|
||||
}
|
||||
appendHtml(items, card, 'beforeend')
|
||||
})
|
||||
// We trigger the onClick events for the drop down buttons on the appended cards
|
||||
triggerAppearedHtml()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the current items
|
||||
let currentItems = []
|
||||
function triggerAppearedHtml() {
|
||||
// Grab the dropdown buttons in all the page for the item cards
|
||||
const trigger = document.querySelectorAll('.dropdownFileBtn')
|
||||
let totalLengthCurrentPagination = 0
|
||||
for (let index = 0; index < currentPagination.length; index++) {
|
||||
// Get the length of every current pagination
|
||||
const lengthEveryItems = currentPagination[index].length
|
||||
// Store it into totalLengthCurrentPagination
|
||||
totalLengthCurrentPagination += lengthEveryItems
|
||||
}
|
||||
// Get the last items from currentItems
|
||||
const lastItemAppeared = currentItems.slice(-1)[0]
|
||||
// If there is no lastItemAppeared the pagination has not fired yet, so set it with the first [0] current pagination length,
|
||||
// Which is the first page in the first reload, else the pagination has fired then it will choose lastItemAppeared
|
||||
const firstLoop = !lastItemAppeared ? currentPagination[0].length : lastItemAppeared
|
||||
// Setting this into a smaller variable name to reduce line size & be more readable in the loop below
|
||||
const lastLoop = totalLengthCurrentPagination
|
||||
let Items = []
|
||||
// Finally loop through the newest items
|
||||
for (let index = firstLoop; index < lastLoop; index++) {
|
||||
Items.push(index)
|
||||
// Add the click event listener to the buttons
|
||||
trigger[index].addEventListener('click', () => {
|
||||
let timer
|
||||
const findSibling = trigger[index].nextElementSibling
|
||||
if (findSibling.classList.contains('opacity-0')) {
|
||||
window.clearTimeout(timer)
|
||||
findSibling.classList.remove('opacity-0', 'translate-y-6', 'invisible')
|
||||
findSibling.classList.add('translate-y-0', 'opacity-100')
|
||||
} else {
|
||||
findSibling.classList.add('opacity-0', 'translate-y-6')
|
||||
findSibling.classList.remove('translate-y-0', 'opacity-100')
|
||||
|
||||
//Set timer to hide the dropdown
|
||||
//the value of timer '250' must be same as the tailwind class 'duration-250' in the class dropdownFile attribute
|
||||
timer = window.setTimeout(() => {
|
||||
findSibling.classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
// Click outside event
|
||||
window.addEventListener('click', (eve) => {
|
||||
if (!trigger[index].contains(eve.target) && !findSibling.contains(eve.target)) {
|
||||
findSibling.classList.add('opacity-0', 'translate-y-6')
|
||||
findSibling.classList.remove('translate-y-0', 'opacity-100')
|
||||
// Same as above
|
||||
timer = window.setTimeout(() => {
|
||||
findSibling.classList.add('invisible')
|
||||
}, 250)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
// Slice Items to get the current items, and push it to currentItems
|
||||
currentItems.push(Items.slice(-1)[0] + 1)
|
||||
}
|
||||
})
|
||||
</script>
|
@ -0,0 +1,11 @@
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-center flex-col items-center space-y-2">
|
||||
<svg class="text-purple-400 w-10 h-10" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<path d="M16 16s-1.5-2-4-2-4 2-4 2"></path>
|
||||
<line x1="9" y1="9" x2="9.01" y2="9"></line>
|
||||
<line x1="15" y1="9" x2="15.01" y2="9"></line>
|
||||
</svg>
|
||||
<span class="font-semibold text-white">You have no more files to load!</span>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,81 @@
|
||||
<div class="bg-tertiary h-auto w-36 cursor-pointer rounded-md p-3 transition duration-300 ease-in-out hover:scale-105 hover:shadow-xl sm:w-44 md:w-[139px] lg:w-40">
|
||||
<!-- File Header -->
|
||||
<div class="flex flex-row flex-nowrap items-center justify-between">
|
||||
<!--We will add this and style it when we add multi-delete, for now eggplant
|
||||
<input class="accent-blue-700 rounded-md h-3 w-4 md:h-4 md:w-5 lg:h-4 lg:w-4" type="checkbox" />
|
||||
-->
|
||||
<span>🍆</span>
|
||||
|
||||
<div class="relative">
|
||||
<!-- File Dropdown Button -->
|
||||
<button class="dropdownFileBtn relative text-gray-400">
|
||||
<svg class="relative h-3 w-3 md:h-4 md:w-4 lg:h-4 lg:w-4" xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle class="relative" cx="12" cy="12" r="1"></circle>
|
||||
<circle class="relative" cx="12" cy="5" r="1"></circle>
|
||||
<circle class="relative" cx="12" cy="19" r="1"></circle>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- End File Dropdown Button -->
|
||||
|
||||
<!-- File Dropdown -->
|
||||
<div class="dropdownFile duration-250 bg-tertiary invisible absolute top-6 right-0 z-10 h-auto w-36 translate-y-6 rounded-lg opacity-0 shadow-lg transition ease-linear">
|
||||
<!-- File Dropdown Menu-->
|
||||
<div class="grid grid-cols-1 px-3 py-2 space-y-2 shadow-xl">
|
||||
<button onClick="copyLink('${id}')" data-tooltip-target="${id}-copy" data-tooltip-trigger="click" class="tooltip dropdown-item w-full rounded-md p-2 text-color-primary hover:bg-tertiary-hover">
|
||||
<i data-lucide="link" class="w-4 h-4 mr-2 inline"></i>
|
||||
Copy Link
|
||||
</button>
|
||||
<div id="${id}-copy" role="tooltip" class="inline-block absolute invisible z-10 py-2 px-3 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
|
||||
Link copied to clipboard!
|
||||
<div class="tooltip-arrow" data-popper-arrow></div>
|
||||
</div>
|
||||
|
||||
<button onClick="deleteItem('${id}', '${deleteId}')" data-tooltip-target="${id}-delete" data-tooltip-trigger="click"
|
||||
class="tooltip dropdown-item w-full rounded-md p-2 text-color-primary hover:bg-tertiary-hover">
|
||||
<i data-lucide="trash" class="w-4 h-4 mr-2 inline"></i>
|
||||
Delete
|
||||
</button>
|
||||
<div id="${id}-delete" role="tooltip" class="inline-block absolute invisible z-10 py-2 px-3 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 tooltip dark:bg-gray-700">
|
||||
Item is being deleted, page will refresh when finished.
|
||||
<div class="tooltip-arrow" data-popper-arrow></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End File Dropdown Menu-->
|
||||
</div>
|
||||
<!-- File Dropdown -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- End File Header -->
|
||||
|
||||
<div class="space-y-3">
|
||||
|
||||
<a target="_blank" href='${itemURL}'>
|
||||
<div class="relatiive mt-2 flex flex-wrap items-center justify-center">
|
||||
<svg class="relative h-20 w-auto fill-gray-400 md:h-24 lg:h-24"
|
||||
xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="0" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14.5 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V7.5L14.5 2z"> </path>
|
||||
<polyline points="14 2 14 8 20 8"></polyline>
|
||||
</svg>
|
||||
<div class="absolute text-sm font-medium text-color-primary">
|
||||
${fileExtension}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div class="has-name-tooltip text-center">
|
||||
<a target="_blank" href='${itemURL}' class="text-base font-medium text-color-primary hover:text-color-accent hober:bg-secondary md:text-lg lg:text-lg">
|
||||
<span class='name-tooltip rounded shadow-lg p-2 bg-primary text-color-primary -mt-8'>${originalName}</span>
|
||||
<p class="truncate">${originalName}</p>
|
||||
</a>
|
||||
<div class="text-xs text-gray-400 md:text-sm lg:text-sm">
|
||||
${timeStamp}
|
||||
</div>
|
||||
<div class="text-xs text-gray-400">
|
||||
${size}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,40 +0,0 @@
|
||||
<div class="mt-8 flex flex-nowrap justify-end">
|
||||
<div class="basis-full px-0 md:basis-2/3 md:px-12 lg:basis-3/4 lg:px-12">
|
||||
<div
|
||||
class="flex flex-row flex-wrap items-center justify-center space-x-3 text-sm text-color-primary md:justify-start md:text-base lg:justify-start lg:text-base">
|
||||
<button>
|
||||
<svg class="h-auto w-4 md:w-6 lg:w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="11 17 6 12 11 7"></polyline>
|
||||
<polyline points="18 17 13 12 18 7"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button>
|
||||
<svg class="h-auto w-4 md:w-6 lg:w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="15 18 9 12 15 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button class="bg-tertiary rounded-mdpy-2 px-4">1</button>
|
||||
<button class="py-2 px-4">2</button>
|
||||
<button class="py-2 px-4">3</button>
|
||||
|
||||
<button>
|
||||
<svg class="h-auto w-4 md:w-6 lg:w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button>
|
||||
<svg class="h-auto w-4 md:w-6 lg:w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="13 17 18 12 13 7"></polyline>
|
||||
<polyline points="6 17 11 12 6 7"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,3 +1,10 @@
|
||||
<script src="/js/app.js"></script>
|
||||
<script src="/js/components.js"></script>
|
||||
<script src="/js/theme/theme-switcher.js"></script>
|
||||
<% if(path=='/' ){ %>
|
||||
<script src="/js/app.js"></script>
|
||||
<script src="/js/components.js"></script>
|
||||
<script src="/js/theme/theme-switcher.js"></script>
|
||||
<% } %>
|
||||
<% if(path=='/admin' ){ %>
|
||||
<script src="/js/app.js"></script>
|
||||
<script src="/js/theme/theme-switcher.js"></script>
|
||||
<% } %>
|
||||
|
||||
|
Loading…
Reference in new issue