mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2024-04-21 12:32:08 +00:00
feature (rewrite): filepage frontend
This commit is contained in:
@@ -3,19 +3,16 @@
|
||||
z-index: 5;
|
||||
}
|
||||
.component_breadcrumb .breadcrumb {
|
||||
background: white;
|
||||
border-bottom: 2px solid rgba(100, 100, 100, 0.05);
|
||||
transition: 1s ease border-bottom;
|
||||
margin: 0 0 0px 0;
|
||||
z-index: 1000;
|
||||
padding: 3px 0;
|
||||
padding: 3px 0 3px 10px;
|
||||
}
|
||||
.component_breadcrumb .breadcrumb .ul {
|
||||
list-style-type: none;
|
||||
margin: 0 auto;
|
||||
width: 95%;
|
||||
max-width: 800px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
padding: 0 10px 0 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.component_breadcrumb .breadcrumb .ul > span {
|
||||
display: block;
|
||||
@@ -24,9 +21,9 @@
|
||||
.component_breadcrumb .breadcrumb .ul div, .component_breadcrumb .breadcrumb .ul .li {
|
||||
display: inline-block;
|
||||
}
|
||||
.component_breadcrumb:hover .breadcrumb {
|
||||
border-bottom: 2px solid rgba(100, 100, 100, 0.1);
|
||||
}
|
||||
/* .component_breadcrumb:hover .breadcrumb { */
|
||||
/* border-bottom: 2px solid rgba(100, 100, 100, 0.1); */
|
||||
/* } */
|
||||
.component_breadcrumb .component_logout {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
|
||||
@@ -16,7 +16,6 @@ class ComponentBreadcrumb extends HTMLDivElement {
|
||||
</a>
|
||||
`;
|
||||
const paths = (this.getAttribute("path") || "").replace(new RegExp("/$"), "").split("/");
|
||||
console.log(paths);
|
||||
const htmlPathChunks = paths.map((chunk, idx) => {
|
||||
const label = idx === 0 ? "Filestash" : chunk;
|
||||
const link = paths.slice(0, idx + 1).join("/") + "/";
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
.component_filemanager_shell {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
.component_filemanager_shell .component_sidebar {
|
||||
width: 240px;
|
||||
padding: 10px;
|
||||
}
|
||||
.component_filemanager_shell .component_sidebar > h3 {
|
||||
padding-left: 10px;
|
||||
margin-bottom: 5px;
|
||||
color: var(--light);
|
||||
font-size: 1rem;
|
||||
}
|
||||
.component_filemanager_shell .component_sidebar > div {
|
||||
background: rgba(0,0,0,0.1);
|
||||
padding-left: 10px;
|
||||
width: 90%;
|
||||
height: 50px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.component_filemanager_shell [is="component-breadcrumb"]:hover ~ [data-bind="filemanager-children"],
|
||||
.component_filemanager_shell [data-bind="sidebar"]:hover ~ div > [data-bind="filemanager-children"] {
|
||||
border-color: rgba(100, 100, 100, 0.1);
|
||||
}
|
||||
|
||||
.component_filemanager_shell [data-bind="filemanager-children"] {
|
||||
border-top: 2px solid rgba(0,0,0,0.02);
|
||||
border-left: 2px solid rgba(0,0,0,0.02);
|
||||
transition: 1000ms ease border-color;
|
||||
border-top-left-radius: 15px;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
.component_filemanager_shell [data-bind="sidebar"].hidden ~ div > [data-bind="filemanager-children"] {
|
||||
border-top-left-radius: 0;
|
||||
border-left: none;
|
||||
}
|
||||
.component_filemanager_shell [data-bind="sidebar"].hidden ~ div > [is="component-breadcrumb"] > .component_breadcrumb,
|
||||
.component_filemanager_shell [data-bind="sidebar"].hidden ~ div > [data-bind="filemanager-children"] > div {
|
||||
width: 95%;
|
||||
margin: 0 auto;
|
||||
max-width: 820px;
|
||||
}
|
||||
.component_filemanager_shell [data-bind="sidebar"].hidden ~ div [is="component-breadcrumb"] {
|
||||
background: white;
|
||||
}
|
||||
.component_filemanager_shell [data-bind="sidebar"].hidden ~ div > [data-bind="filemanager-children"] {
|
||||
background: var(--bg-color);
|
||||
}
|
||||
.component_filemanager_shell .component_filesystem {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.component_filemanager_shell [data-bind="filemanager-children"] > div,
|
||||
.component_filemanager_shell [is="component-breadcrumb"] {
|
||||
max-width: 2100px;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { createElement, createRender } from "../lib/skeleton/index.js";
|
||||
import { qs } from "../lib/dom.js";
|
||||
import { CSS } from "../helpers/loader.js";
|
||||
|
||||
export default function(ctrl) {
|
||||
const $page = createElement(`
|
||||
<div class="component_filemanager_shell" style="flex-direction:row">
|
||||
<div data-bind="sidebar" class="hidden"></div>
|
||||
<div style="width:100%;display: flex; flex-direction: column;">
|
||||
<div is="component-breadcrumb" path="/home/mickael/Documents/projects/"></div>
|
||||
<div class="scroll-y" data-bind="filemanager-children"></div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
return async function(render) {
|
||||
render($page);
|
||||
|
||||
// feature1: setup the childrens
|
||||
ctrl(createRender(qs($page, `[data-bind="filemanager-children"]`)));
|
||||
ctrlSidebar(createRender(qs($page, `[data-bind="sidebar"]`)));
|
||||
|
||||
qs($page, `[is="component-breadcrumb"]`).setAttribute(
|
||||
"path",
|
||||
decodeURIComponent(location.pathname).replace(new RegExp("/files"), ""),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function ctrlSidebar(render) {
|
||||
// Quick Access:
|
||||
// - home folders
|
||||
// - indexedDB folders
|
||||
// Shared Drive:
|
||||
// - shared links (rwd)
|
||||
// Tags:
|
||||
// - name + color
|
||||
const $comp = createElement(`
|
||||
<div class="component_sidebar">
|
||||
<br><br>
|
||||
|
||||
<h3>Quick Access</h3>
|
||||
<div></div>
|
||||
|
||||
<h3>Shared Drive</h3>
|
||||
<div></div>
|
||||
|
||||
<h3>Tags</h3>
|
||||
<div></div>
|
||||
|
||||
<style>${await CSS(import.meta.url, "decorator_shell_filemanager.css")}</style>
|
||||
</div>
|
||||
`);
|
||||
render($comp);
|
||||
}
|
||||
@@ -42,10 +42,25 @@ class Loader extends window.HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// function tap(sideEffectFn) {
|
||||
// return (source) => {
|
||||
// // TODO: use source.lift
|
||||
// console.log("SOURCE", source)
|
||||
// source.lift({
|
||||
// call: (subscriber, source) => {
|
||||
// console.log(source, subscriber);
|
||||
// return subscriber;
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
const tap = rxjs.tap;
|
||||
|
||||
customElements.define("component-loader", Loader);
|
||||
|
||||
export default createElement("<component-loader></component-loader>");
|
||||
export function toggle($node, show = false) {
|
||||
if (show === true) return rxjs.tap(() => $node.appendChild(createElement("<component-loader></component-loader>")));
|
||||
else return rxjs.tap(() => $node.querySelector("component-loader")?.remove());
|
||||
if (show === true) return tap(() => $node.appendChild(createElement("<component-loader></component-loader>")));
|
||||
else return tap(() => $node.querySelector("component-loader")?.remove());
|
||||
}
|
||||
|
||||
@@ -49,21 +49,21 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
--bg-color: #fafafa;
|
||||
--bg-color: #fafafa; /*#fafafa;*/
|
||||
--color: #57595A;
|
||||
--emphasis: #466372;
|
||||
--primary: #9AD1ED;
|
||||
--emphasis-primary: #c5e2f1;
|
||||
--emphasis-secondary: #466372;
|
||||
--light: #909090;
|
||||
--super-light: #f9fafc;
|
||||
--super-light: #fafafa;
|
||||
--error: #f26d6d;
|
||||
--success: #63d9b1;
|
||||
--dark: #313538;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-family: system-ui, sans-serif;
|
||||
-webkit-text-size-adjust:100%;
|
||||
}
|
||||
body {
|
||||
@@ -22,8 +22,8 @@ export default function(render = createRender(qs(document.body, "[role=\"main\"]
|
||||
<h1>${t("Oops!")}</h1>
|
||||
<h2>${t(msg)}</h2>
|
||||
<p>
|
||||
<button class="light" data-bind="details">More details</button>
|
||||
<button class="primary" data-bind="refresh">Refresh</button>
|
||||
<button class="light" data-bind="details">${t("More details")}</button>
|
||||
<button class="primary" data-bind="refresh">${t("Refresh")}</button>
|
||||
<pre class="hidden"><code>${trace}</code></pre>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.component_page_filespage .error {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
import { createElement, createRender } from "../lib/skeleton/index.js";
|
||||
import rxjs, { effect } from "../lib/rx.js";
|
||||
import { qs } from "../lib/dom.js";
|
||||
import { CSS } from "../helpers/loader.js";
|
||||
import WithShell from "../components/decorator_shell_filemanager.js"
|
||||
|
||||
import { getState$ } from "./filespage/state.js";
|
||||
import componentFilesystem from "./filespage/filesystem.js";
|
||||
import { getState$ } from "./filespage/ctrl_filesystem_state.js";
|
||||
import componentFilesystem from "./filespage/ctrl_filesystem.js";
|
||||
import componentSubmenu from "./filespage/ctrl_submenu.js";
|
||||
|
||||
import "../components/breadcrumb.js";
|
||||
|
||||
export default function(render) {
|
||||
const currentPath = decodeURIComponent(location.pathname).replace(new RegExp("/files"), "");
|
||||
export default WithShell(function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_page_filespage">
|
||||
<div is="component-breadcrumb" path="${currentPath}"></div>
|
||||
<div class="page_container">
|
||||
<div class="scroll-y">
|
||||
<div is="frequent-access"></div>
|
||||
<div is="component-submenu"></div>
|
||||
<div is="component-filesystem"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div is="frequent_access" class="hidden"></div>
|
||||
<div is="component_submenu" class="hidden"></div>
|
||||
<div is="component_filesystem"></div>
|
||||
<style>${css}</style>
|
||||
</div>
|
||||
`);
|
||||
@@ -31,7 +28,10 @@ export default function(render) {
|
||||
));
|
||||
|
||||
// feature2: render the filesystem
|
||||
componentFilesystem(createRender($page.querySelector("[is=\"component-filesystem\"]")));
|
||||
}
|
||||
componentFilesystem(createRender(qs($page, "[is=\"component_filesystem\"]")));
|
||||
|
||||
// feature3: render the menubar
|
||||
componentSubmenu(createRender(qs($page, "[is=\"component_submenu\"]")))
|
||||
});
|
||||
|
||||
const css = await CSS(import.meta.url, "ctrl_filespage.css");
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { createElement } from "../lib/skeleton/index.js";
|
||||
import WithShell from "../components/decorator_shell_filemanager.js"
|
||||
|
||||
import "../components/breadcrumb.js";
|
||||
|
||||
export default function(render) {
|
||||
const currentPath = decodeURIComponent(location.pathname).replace(new RegExp("/view"), "");
|
||||
export default WithShell(function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_page_filespage">
|
||||
<div is="component-breadcrumb" path="${currentPath}" animateOut="test"></div>
|
||||
<div class="page_container">
|
||||
<div class="component_page_viewerpage">
|
||||
viewerpage - TODO
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
render($page);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.list .container_fs {
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: 1px 2700px;
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
import { createElement } from "../../lib/skeleton/index.js";
|
||||
import { animate, slideYIn } from "../../lib/animate.js";
|
||||
import rxjs, { effect } from "../../lib/rx.js";
|
||||
import { CSS } from "../../helpers/loader.js";
|
||||
import { qs } from "../../lib/dom.js";
|
||||
import { ApplicationError } from "../../lib/error.js";
|
||||
import { toggle as toggleLoader } from "../../components/loader.js";
|
||||
import ctrlError from "../ctrl_error.js";
|
||||
|
||||
import { createThing, allocateMemory, css } from "./thing.js";
|
||||
import { handleError, getFiles } from "./ctrl_filesystem_state.js";
|
||||
import { ls } from "./model_files.js";
|
||||
|
||||
export default async function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_filesystem">
|
||||
<div class="ifscroll-before">
|
||||
<div></div><div></div>
|
||||
<div></div><div></div>
|
||||
</div>
|
||||
<div class="list"></div>
|
||||
<div class="ifscroll-after">
|
||||
<div></div><div></div>
|
||||
<div></div><div></div>
|
||||
</div>
|
||||
<style>${await css}</style>
|
||||
<style>${await CSS(import.meta.url, "ctrl_filesystem.css")}</style>
|
||||
</div>
|
||||
`);
|
||||
render($page);
|
||||
|
||||
// feature: virtual scrolling
|
||||
const path = location.pathname.replace(new RegExp("^/files"), "");
|
||||
effect(rxjs.of(path).pipe(
|
||||
toggleLoader($page, true),
|
||||
rxjs.mergeMap(() => new Promise((done) => setTimeout(() => done({
|
||||
files: new Array(400).fill(1),
|
||||
}), 1000))),
|
||||
toggleLoader($page, false),
|
||||
rxjs.mergeMap(({ files }) => {
|
||||
const BLOCK_SIZE = 8;
|
||||
const COLUMN_PER_ROW = 2;
|
||||
const FILE_HEIGHT = 160;
|
||||
const size = Math.min(files.length, BLOCK_SIZE * COLUMN_PER_ROW);
|
||||
allocateMemory(BLOCK_SIZE * COLUMN_PER_ROW);
|
||||
const $fs = document.createDocumentFragment();
|
||||
for (let i = 0; i < size; i++) {
|
||||
$fs.appendChild(createThing({
|
||||
name: `file ${i}`,
|
||||
type: "file",
|
||||
link: "/view/test.txt",
|
||||
}));
|
||||
}
|
||||
const $list = qs($page, ".list");
|
||||
const $listBefore = qs($page, ".ifscroll-before");
|
||||
const $listAfter = qs($page, ".ifscroll-after");
|
||||
|
||||
const height = (Math.floor(files.length / COLUMN_PER_ROW) - BLOCK_SIZE) * FILE_HEIGHT;
|
||||
const setHeight = (size) => {
|
||||
$listBefore.style.height = `${size}px`;
|
||||
$listAfter.style.height = `${height - size}px`;
|
||||
};
|
||||
setHeight(0);
|
||||
animate($list, { time: 200, keyframes: slideYIn(5) });
|
||||
$list.appendChild($fs);
|
||||
if (files.length === size) return rxjs.EMPTY;
|
||||
return rxjs.of({
|
||||
files,
|
||||
currentState: 0,
|
||||
BLOCK_SIZE, COLUMN_PER_ROW, FILE_HEIGHT,
|
||||
setHeight,
|
||||
$list,
|
||||
});
|
||||
}),
|
||||
rxjs.mergeMap(({
|
||||
files,
|
||||
BLOCK_SIZE, COLUMN_PER_ROW, FILE_HEIGHT,
|
||||
currentState,
|
||||
height, setHeight,
|
||||
$list,
|
||||
}) => rxjs.fromEvent(
|
||||
$page.parentElement.parentElement.parentElement,
|
||||
"scroll", { passive: true },
|
||||
).pipe(
|
||||
rxjs.map((e) => Math.min(
|
||||
Math.ceil(Math.max(0, e.target.scrollTop) / FILE_HEIGHT),
|
||||
// cap state value when BLOCK_SIZE is larger than minimum value. This is to
|
||||
// prevent issues when scrolling fast to the bottom (aka diff > 1)
|
||||
Math.ceil(files.length / COLUMN_PER_ROW) - BLOCK_SIZE,
|
||||
)),
|
||||
rxjs.distinctUntilChanged(),
|
||||
rxjs.debounce(() => new rxjs.Observable((observer) => {
|
||||
const id = requestAnimationFrame(() => observer.next());
|
||||
return () => cancelAnimationFrame(id);
|
||||
})),
|
||||
rxjs.tap((nextState) => {
|
||||
// STEP1: calculate the virtual scroll paramameters
|
||||
let diff = nextState - currentState;
|
||||
const diffSgn = Math.sign(diff);
|
||||
if (Math.abs(diff) > BLOCK_SIZE) diff = diffSgn * BLOCK_SIZE; // fast scroll
|
||||
let fileStart = nextState * COLUMN_PER_ROW;
|
||||
if (diffSgn > 0) { // => scroll down
|
||||
// eg: files[15] BLOCK_SIZE=1 COLUMN_PER_ROW=1
|
||||
// -----------[currentState:0]--------------------------[nextState:5]---------
|
||||
// -----------[fileStart=5+1=6]
|
||||
fileStart += BLOCK_SIZE * COLUMN_PER_ROW;
|
||||
// -----------[fileStart=6-min(5,1)=5]
|
||||
fileStart -= Math.min(diff, BLOCK_SIZE) * COLUMN_PER_ROW;
|
||||
}
|
||||
let fileEnd = fileStart + diffSgn * diff * COLUMN_PER_ROW;
|
||||
|
||||
if (fileStart >= files.length) throw new ApplicationError(
|
||||
"INTERNAL_ERROR",
|
||||
`assert failed in virtual scroll range[${fileStart}:${fileEnd}] length[${files.length}]`,
|
||||
); else if (fileEnd > files.length) {
|
||||
// occur when files.length isn't a multiple of COLUMN_PER_ROW and
|
||||
// we've scrolled to the bottom of the list
|
||||
nextState = Math.floor(files.length / COLUMN_PER_ROW) - BLOCK_SIZE;
|
||||
fileEnd = files.length;
|
||||
do {
|
||||
// add some padding to fileEnd to balance the list to the
|
||||
// nearest COLUMN_PER_ROW
|
||||
fileEnd += 1;
|
||||
} while (fileEnd % COLUMN_PER_ROW !== 0);
|
||||
}
|
||||
|
||||
// STEP2: create the new elements
|
||||
const $fs = document.createDocumentFragment();
|
||||
let n = 0;
|
||||
for (let i = fileStart; i < fileEnd; i++) {
|
||||
const file = files[i];
|
||||
if (file === undefined) $fs.appendChild(createThing({
|
||||
name: "dummy",
|
||||
}))
|
||||
else $fs.appendChild(createThing({
|
||||
name: `file - ${i}`,
|
||||
type: "file",
|
||||
link: "/view/test.txt",
|
||||
}));
|
||||
n += 1;
|
||||
}
|
||||
// console.log(`n[${n}] state[${currentState} -> ${nextState}] files[${fileStart}:${fileEnd}]`)
|
||||
|
||||
// STEP3: update the DOM
|
||||
if (diffSgn > 0) { // scroll down
|
||||
// console.log("DOWN", n);
|
||||
// // if (!isInViewport($list.firstChild)) // TODO
|
||||
$list.appendChild($fs);
|
||||
for (let i = 0; i < n; i++) $list.firstChild.remove();
|
||||
} else { // scroll up
|
||||
// console.log("UP", n)
|
||||
$list.insertBefore($fs, $list.firstChild);
|
||||
for (let i = 0; i < n; i++) $list.lastChild.remove();
|
||||
}
|
||||
setHeight(nextState * FILE_HEIGHT);
|
||||
currentState = nextState;
|
||||
}),
|
||||
)),
|
||||
rxjs.catchError(ctrlError()),
|
||||
));
|
||||
|
||||
// feature2: fs in "search" mode
|
||||
// TODO
|
||||
}
|
||||
|
||||
function isInViewport(element) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return rect.bottom > 0;
|
||||
}
|
||||
+2
@@ -35,3 +35,5 @@ export const onNewDirectory = () => {
|
||||
export const onSearch = () => {
|
||||
console.log("SEARCH");
|
||||
};
|
||||
|
||||
export const getFiles = (n) => {}
|
||||
@@ -0,0 +1,133 @@
|
||||
.component_submenu.sticky {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
background: var(--bg-color);
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.component_submenu {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
.component_submenu .menubar {
|
||||
font-size: 15px;
|
||||
line-height: 15px;
|
||||
height: 15px;
|
||||
margin-top: 5px;
|
||||
color: var(--light);
|
||||
margin: 5px 0 10px 0;
|
||||
/* Create Buttons */
|
||||
}
|
||||
.component_submenu .menubar > span, .component_submenu .menubar form label {
|
||||
display: inline-block;
|
||||
margin-top: -5px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
background-position: center;
|
||||
}
|
||||
.component_submenu .menubar > span:active, .component_submenu .menubar > span:hover, .component_submenu .menubar form label:active, .component_submenu .menubar form label:hover {
|
||||
color: var(--color);
|
||||
}
|
||||
.component_submenu .menubar > span:hover, .component_submenu .menubar form label:hover {
|
||||
transition: background 0.4s;
|
||||
background: #ffffff00 radial-gradient(circle, transparent 1%, var(--bg-color) 1%) center/15000%;
|
||||
}
|
||||
.component_submenu .menubar > span:active, .component_submenu .menubar form label:active {
|
||||
background-color: #00000033;
|
||||
background-size: 100%;
|
||||
transition: background 0s;
|
||||
}
|
||||
.component_submenu .menubar > span {
|
||||
padding: 5px 8px;
|
||||
letter-spacing: 0.06em;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
color: var(--light);
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
.component_submenu .menubar > div {
|
||||
cursor: pointer;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.component_submenu .menubar .view {
|
||||
float: right;
|
||||
padding: 2px;
|
||||
transition: 0.15s ease-out background;
|
||||
margin-right: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
.component_submenu .menubar .view .search, .component_submenu .menubar .view.list-grid, .component_submenu .menubar .view > .dropdown_button, .component_submenu .menubar .view form > label {
|
||||
min-width: inherit;
|
||||
border-radius: 2px;
|
||||
padding: 5px;
|
||||
margin: 2px 0 2px 0;
|
||||
}
|
||||
.component_submenu .menubar .view.list-grid, .component_submenu .menubar .view .dropdown_button, .component_submenu .menubar .view .search {
|
||||
background-position: center;
|
||||
}
|
||||
.component_submenu .menubar .view.list-grid:hover, .component_submenu .menubar .view .dropdown_button:hover, .component_submenu .menubar .view .search:hover {
|
||||
transition: background 0.4s;
|
||||
background: #ffffff00 radial-gradient(circle, transparent 1%, var(--bg-color) 1%) center/15000%;
|
||||
}
|
||||
.component_submenu .menubar .view.list-grid:active, .component_submenu .menubar .view .dropdown_button:active, .component_submenu .menubar .view .search:active {
|
||||
background-color: #00000033;
|
||||
background-size: 100%;
|
||||
transition: background 0s;
|
||||
}
|
||||
.component_submenu .menubar .view .dropdown_container .component_icon {
|
||||
box-sizing: border-box;
|
||||
border: 2px solid rgba(0, 0, 0, 0);
|
||||
}
|
||||
.component_submenu .menubar .view.list-grid, .component_submenu .menubar .view .search {
|
||||
margin-top: -5px !important;
|
||||
}
|
||||
.component_submenu .menubar .view.component_dropdown {
|
||||
margin-top: -10px;
|
||||
}
|
||||
.component_submenu .menubar .view.component_dropdown.active .dropdown_button {
|
||||
box-shadow: none;
|
||||
}
|
||||
.component_submenu .menubar.search_focus form input {
|
||||
transition: 0.2s width ease-in;
|
||||
opacity: 1;
|
||||
}
|
||||
.component_submenu .menubar form {
|
||||
float: right;
|
||||
margin-top: -3px;
|
||||
}
|
||||
.component_submenu .menubar form input {
|
||||
opacity: 0;
|
||||
font-size: 1em;
|
||||
margin-top: -3px;
|
||||
border: none;
|
||||
background: inherit;
|
||||
border-bottom: 2px solid var(--light);
|
||||
color: var(--color);
|
||||
}
|
||||
.component_submenu .menubar.search_focus > span {
|
||||
display: none;
|
||||
}
|
||||
.component_submenu .menubar .component_icon {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
}
|
||||
|
||||
.component_submenu .submenuwithSelection-appear {
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
transform: translateY(3px);
|
||||
transition: opacity 0.2s ease, transform 0.4s ease;
|
||||
}
|
||||
|
||||
.component_submenu .submenuwithSelection-appear.submenuwithSelection-appear-active {
|
||||
opacity: 1;
|
||||
transform: translateY(0px);
|
||||
}
|
||||
|
||||
.dark-mode .component_submenu input#search {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { createElement, createRender } from "../../lib/skeleton/index.js";
|
||||
import { CSS } from "../../helpers/loader.js";
|
||||
|
||||
export default async function(render) {
|
||||
|
||||
const $page = createElement(`
|
||||
<div class="component_submenu">
|
||||
<style>${css}</style>
|
||||
<div class="action left">
|
||||
<button>New File</button>
|
||||
<button>New Folder</button>
|
||||
</div>
|
||||
<div class="action right">
|
||||
<button>
|
||||
<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj4KICA8cGF0aCBzdHlsZT0iZmlsbDojNjI2NDY5O2ZpbGwtb3BhY2l0eToxIiBkPSJNNTA1IDQ0Mi43TDQwNS4zIDM0M2MtNC41LTQuNS0xMC42LTctMTctN0gzNzJjMjcuNi0zNS4zIDQ0LTc5LjcgNDQtMTI4QzQxNiA5My4xIDMyMi45IDAgMjA4IDBTMCA5My4xIDAgMjA4czkzLjEgMjA4IDIwOCAyMDhjNDguMyAwIDkyLjctMTYuNCAxMjgtNDR2MTYuM2MwIDYuNCAyLjUgMTIuNSA3IDE3bDk5LjcgOTkuN2M5LjQgOS40IDI0LjYgOS40IDMzLjkgMGwyOC4zLTI4LjNjOS40LTkuNCA5LjQtMjQuNi4xLTM0ek0yMDggMzM2Yy03MC43IDAtMTI4LTU3LjItMTI4LTEyOCAwLTcwLjcgNTcuMi0xMjggMTI4LTEyOCA3MC43IDAgMTI4IDU3LjIgMTI4IDEyOCAwIDcwLjctNTcuMiAxMjgtMTI4IDEyOHoiIC8+Cjwvc3ZnPgo=" alt="search_dark">
|
||||
</button>
|
||||
<button>
|
||||
<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj4KICA8cGF0aCBzdHlsZT0iZmlsbDojNjI2NDY5O2ZpbGwtb3BhY2l0eToxIiBkPSJtIDEzMy4zMzMsNTYgdiA2NCBjIDAsMTMuMjU1IC0xMC43NDUsMjQgLTI0LDI0IEggMjQgQyAxMC43NDUsMTQ0IDAsMTMzLjI1NSAwLDEyMCBWIDU2IEMgMCw0Mi43NDUgMTAuNzQ1LDMyIDI0LDMyIGggODUuMzMzIGMgMTMuMjU1LDAgMjQsMTAuNzQ1IDI0LDI0IHogbSAzNzkuMzM0LDIzMiB2IC02NCBjIDAsLTEzLjI1NSAtMTAuNzQ1LC0yNCAtMjQsLTI0IEggMjEzLjMzMyBjIC0xMy4yNTUsMCAtMjQsMTAuNzQ1IC0yNCwyNCB2IDY0IGMgMCwxMy4yNTUgMTAuNzQ1LDI0IDI0LDI0IGggMjc1LjMzMyBjIDEzLjI1NiwwIDI0LjAwMSwtMTAuNzQ1IDI0LjAwMSwtMjQgeiBtIDAsLTE2OCBWIDU2IGMgMCwtMTMuMjU1IC0xMC43NDUsLTI0IC0yNCwtMjQgSCAyMTMuMzMzIGMgLTEzLjI1NSwwIC0yNCwxMC43NDUgLTI0LDI0IHYgNjQgYyAwLDEzLjI1NSAxMC43NDUsMjQgMjQsMjQgaCAyNzUuMzMzIGMgMTMuMjU2LDAgMjQuMDAxLC0xMC43NDUgMjQuMDAxLC0yNCB6IE0gMTA5LjMzMywyMDAgSCAyNCBDIDEwLjc0NSwyMDAgMCwyMTAuNzQ1IDAsMjI0IHYgNjQgYyAwLDEzLjI1NSAxMC43NDUsMjQgMjQsMjQgaCA4NS4zMzMgYyAxMy4yNTUsMCAyNCwtMTAuNzQ1IDI0LC0yNCB2IC02NCBjIDAsLTEzLjI1NSAtMTAuNzQ1LC0yNCAtMjQsLTI0IHogTSAwLDM5MiB2IDY0IGMgMCwxMy4yNTUgMTAuNzQ1LDI0IDI0LDI0IGggODUuMzMzIGMgMTMuMjU1LDAgMjQsLTEwLjc0NSAyNCwtMjQgdiAtNjQgYyAwLC0xMy4yNTUgLTEwLjc0NSwtMjQgLTI0LC0yNCBIIDI0IEMgMTAuNzQ1LDM2OCAwLDM3OC43NDUgMCwzOTIgWiBtIDE4OS4zMzMsMCB2IDY0IGMgMCwxMy4yNTUgMTAuNzQ1LDI0IDI0LDI0IGggMjc1LjMzMyBjIDEzLjI1NSwwIDI0LC0xMC43NDUgMjQsLTI0IHYgLTY0IGMgMCwtMTMuMjU1IC0xMC43NDUsLTI0IC0yNCwtMjQgSCAyMTMuMzMzIGMgLTEzLjI1NSwwIC0yNCwxMC43NDUgLTI0LDI0IHoiIC8+Cjwvc3ZnPgo=" alt="list">
|
||||
</button>
|
||||
<button>
|
||||
<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMjAgNTEyIj4KICA8cGF0aCBzdHlsZT0iZmlsbDojNjI2NDY5O2ZpbGwtb3BhY2l0eToxIiBkPSJNNDEgMjg4aDIzOGMyMS40IDAgMzIuMSAyNS45IDE3IDQxTDE3NyA0NDhjLTkuNCA5LjQtMjQuNiA5LjQtMzMuOSAwTDI0IDMyOWMtMTUuMS0xNS4xLTQuNC00MSAxNy00MXptMjU1LTEwNUwxNzcgNjRjLTkuNC05LjQtMjQuNi05LjQtMzMuOSAwTDI0IDE4M2MtMTUuMSAxNS4xLTQuNCA0MSAxNyA0MWgyMzhjMjEuNCAwIDMyLjEtMjUuOSAxNy00MXoiIC8+Cjwvc3ZnPgo=" alt="sort">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
render($page);
|
||||
}
|
||||
|
||||
const css = `
|
||||
.component_submenu {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.component_submenu .action.left {
|
||||
margin-left: 2px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.component_submenu .action.right {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.component_submenu .action.right button img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.component_submenu .action.right button,
|
||||
.component_submenu .action.left button {
|
||||
background: var(--bg-color);
|
||||
border: 2px solid rgba(100, 100, 100, 0.05);
|
||||
padding: 5px 10px;
|
||||
}
|
||||
`
|
||||
|
||||
export async function OldOne(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_submenu">
|
||||
<style>${await CSS(import.meta.url, "ctrl_submenu.css")}</style>
|
||||
<div class="menubar no-select"><span class="button-new-file">New File</span><span class="button-new-folder">New Folder</span>
|
||||
<div class="component_dropdown view sort ">
|
||||
<div class="dropdown_button"><img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMjAgNTEyIj4KICA8cGF0aCBzdHlsZT0iZmlsbDojNjI2NDY5O2ZpbGwtb3BhY2l0eToxIiBkPSJNNDEgMjg4aDIzOGMyMS40IDAgMzIuMSAyNS45IDE3IDQxTDE3NyA0NDhjLTkuNCA5LjQtMjQuNiA5LjQtMzMuOSAwTDI0IDMyOWMtMTUuMS0xNS4xLTQuNC00MSAxNy00MXptMjU1LTEwNUwxNzcgNjRjLTkuNC05LjQtMjQuNi05LjQtMzMuOSAwTDI0IDE4M2MtMTUuMSAxNS4xLTQuNCA0MSAxNyA0MWgyMzhjMjEuNCAwIDMyLjEtMjUuOSAxNy00MXoiIC8+Cjwvc3ZnPgo=" alt="sort"></div>
|
||||
<div class="dropdown_container">
|
||||
<ul>
|
||||
<li>
|
||||
<div>Sort By Type<span><span style="float: right;"><img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj4KICA8cGF0aCBzdHlsZT0iZmlsbDojOTA5MDkwO2ZpbGwtb3BhY2l0eToxIiBkPSJNMTczLjg5OCA0MzkuNDA0bC0xNjYuNC0xNjYuNGMtOS45OTctOS45OTctOS45OTctMjYuMjA2IDAtMzYuMjA0bDM2LjIwMy0zNi4yMDRjOS45OTctOS45OTggMjYuMjA3LTkuOTk4IDM2LjIwNCAwTDE5MiAzMTIuNjkgNDMyLjA5NSA3Mi41OTZjOS45OTctOS45OTcgMjYuMjA3LTkuOTk3IDM2LjIwNCAwbDM2LjIwMyAzNi4yMDRjOS45OTcgOS45OTcgOS45OTcgMjYuMjA2IDAgMzYuMjA0bC0yOTQuNCAyOTQuNDAxYy05Ljk5OCA5Ljk5Ny0yNi4yMDcgOS45OTctMzYuMjA0LS4wMDF6IiAvPgo8L3N2Zz4K" alt="check"></span></span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>Sort By Date</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>Sort By Name</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view list-grid"><img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj4KICA8cGF0aCBzdHlsZT0iZmlsbDojNjI2NDY5O2ZpbGwtb3BhY2l0eToxIiBkPSJtIDEzMy4zMzMsNTYgdiA2NCBjIDAsMTMuMjU1IC0xMC43NDUsMjQgLTI0LDI0IEggMjQgQyAxMC43NDUsMTQ0IDAsMTMzLjI1NSAwLDEyMCBWIDU2IEMgMCw0Mi43NDUgMTAuNzQ1LDMyIDI0LDMyIGggODUuMzMzIGMgMTMuMjU1LDAgMjQsMTAuNzQ1IDI0LDI0IHogbSAzNzkuMzM0LDIzMiB2IC02NCBjIDAsLTEzLjI1NSAtMTAuNzQ1LC0yNCAtMjQsLTI0IEggMjEzLjMzMyBjIC0xMy4yNTUsMCAtMjQsMTAuNzQ1IC0yNCwyNCB2IDY0IGMgMCwxMy4yNTUgMTAuNzQ1LDI0IDI0LDI0IGggMjc1LjMzMyBjIDEzLjI1NiwwIDI0LjAwMSwtMTAuNzQ1IDI0LjAwMSwtMjQgeiBtIDAsLTE2OCBWIDU2IGMgMCwtMTMuMjU1IC0xMC43NDUsLTI0IC0yNCwtMjQgSCAyMTMuMzMzIGMgLTEzLjI1NSwwIC0yNCwxMC43NDUgLTI0LDI0IHYgNjQgYyAwLDEzLjI1NSAxMC43NDUsMjQgMjQsMjQgaCAyNzUuMzMzIGMgMTMuMjU2LDAgMjQuMDAxLC0xMC43NDUgMjQuMDAxLC0yNCB6IE0gMTA5LjMzMywyMDAgSCAyNCBDIDEwLjc0NSwyMDAgMCwyMTAuNzQ1IDAsMjI0IHYgNjQgYyAwLDEzLjI1NSAxMC43NDUsMjQgMjQsMjQgaCA4NS4zMzMgYyAxMy4yNTUsMCAyNCwtMTAuNzQ1IDI0LC0yNCB2IC02NCBjIDAsLTEzLjI1NSAtMTAuNzQ1LC0yNCAtMjQsLTI0IHogTSAwLDM5MiB2IDY0IGMgMCwxMy4yNTUgMTAuNzQ1LDI0IDI0LDI0IGggODUuMzMzIGMgMTMuMjU1LDAgMjQsLTEwLjc0NSAyNCwtMjQgdiAtNjQgYyAwLC0xMy4yNTUgLTEwLjc0NSwtMjQgLTI0LC0yNCBIIDI0IEMgMTAuNzQ1LDM2OCAwLDM3OC43NDUgMCwzOTIgWiBtIDE4OS4zMzMsMCB2IDY0IGMgMCwxMy4yNTUgMTAuNzQ1LDI0IDI0LDI0IGggMjc1LjMzMyBjIDEzLjI1NSwwIDI0LC0xMC43NDUgMjQsLTI0IHYgLTY0IGMgMCwtMTMuMjU1IC0xMC43NDUsLTI0IC0yNCwtMjQgSCAyMTMuMzMzIGMgLTEzLjI1NSwwIC0yNCwxMC43NDUgLTI0LDI0IHoiIC8+Cjwvc3ZnPgo=" alt="list"></div>
|
||||
<div class="view">
|
||||
<form><label class="view search"><div><img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj4KICA8cGF0aCBzdHlsZT0iZmlsbDojNjI2NDY5O2ZpbGwtb3BhY2l0eToxIiBkPSJNNTA1IDQ0Mi43TDQwNS4zIDM0M2MtNC41LTQuNS0xMC42LTctMTctN0gzNzJjMjcuNi0zNS4zIDQ0LTc5LjcgNDQtMTI4QzQxNiA5My4xIDMyMi45IDAgMjA4IDBTMCA5My4xIDAgMjA4czkzLjEgMjA4IDIwOCAyMDhjNDguMyAwIDkyLjctMTYuNCAxMjgtNDR2MTYuM2MwIDYuNCAyLjUgMTIuNSA3IDE3bDk5LjcgOTkuN2M5LjQgOS40IDI0LjYgOS40IDMzLjkgMGwyOC4zLTI4LjNjOS40LTkuNCA5LjQtMjQuNi4xLTM0ek0yMDggMzM2Yy03MC43IDAtMTI4LTU3LjItMTI4LTEyOCAwLTcwLjcgNTcuMi0xMjggMTI4LTEyOCA3MC43IDAgMTI4IDU3LjIgMTI4IDEyOCAwIDcwLjctNTcuMiAxMjgtMTI4IDEyOHoiIC8+Cjwvc3ZnPgo=" alt="search_dark"></div></label><span><input type="text" id="search" placeholder="search" name="search" autocomplete="off" value="" style="width: 0px;"><label for="search" class="hidden">search</label></span></form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
render($page);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { createElement } from "../../lib/skeleton/index.js";
|
||||
import rxjs, { effect } from "../../lib/rx.js";
|
||||
import { qs } from "../../lib/dom.js";
|
||||
|
||||
import { toggle as toggleLoader } from "../../components/loader.js";
|
||||
|
||||
import { createThing, css } from "./thing.js";
|
||||
import { handleError } from "./state.js";
|
||||
import { ls } from "./model_files.js";
|
||||
|
||||
export default async function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_container">
|
||||
<div class="list"></div>
|
||||
<style>${await css}</style>
|
||||
</div>
|
||||
`);
|
||||
render($page);
|
||||
|
||||
// feature1: files on the current path
|
||||
const path = location.pathname.replace(new RegExp("^/files"), "");
|
||||
effect(rxjs.of(path).pipe(
|
||||
toggleLoader($page, true),
|
||||
ls(), // TODO: ls_from_cache then ls_from_server
|
||||
toggleLoader($page, false),
|
||||
rxjs.tap(({ files }) => {
|
||||
const $fs = document.createDocumentFragment();
|
||||
for (let i = 0; i < files.length && i < 100; i++) {
|
||||
if (!files[i]) continue;
|
||||
$fs.appendChild(createThing({
|
||||
name: files[i].name,
|
||||
// type: files[i].type,
|
||||
// size: files[i].size,
|
||||
// time: files[i].time,
|
||||
link: (files[i].type === "file" ? "/view" : "/files") + path + files[i].name + (files[i].type === "file" ? "" : "/"),
|
||||
}));
|
||||
}
|
||||
qs($page, ".list").appendChild($fs);
|
||||
}),
|
||||
handleError()
|
||||
));
|
||||
|
||||
// feature2: fs in "search" mode
|
||||
// TODO
|
||||
}
|
||||
@@ -109,8 +109,8 @@
|
||||
|
||||
/* GRID & LIST VIEW */
|
||||
.list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, 50%);
|
||||
}
|
||||
.list > .component_thing {
|
||||
width: 100%;
|
||||
@@ -119,60 +119,60 @@
|
||||
margin: 0px 0 2px 0;
|
||||
}
|
||||
.list > .component_thing.view-grid {
|
||||
width: 25%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
transition: 0.1s ease transform;
|
||||
}
|
||||
.list > .component_thing.view-grid .box {
|
||||
height: 160px;
|
||||
}
|
||||
@media (max-width: 699px) {
|
||||
.list > .component_thing.view-grid {
|
||||
width: 33.33%;
|
||||
}
|
||||
.list > .component_thing.view-grid .box {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 670px) {
|
||||
.list > .component_thing.view-grid .box {
|
||||
height: 170px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 550px) {
|
||||
.list > .component_thing.view-grid {
|
||||
width: 50%;
|
||||
}
|
||||
.list > .component_thing.view-grid .box {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.list > .component_thing.view-grid .box {
|
||||
height: 170px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 400px) {
|
||||
.list > .component_thing.view-grid .box {
|
||||
height: 140px;
|
||||
}
|
||||
.list > .component_thing.view-grid .box .info_extension {
|
||||
font-size: 0.8em !important;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 340px) {
|
||||
.list > .component_thing.view-grid .box {
|
||||
height: 130px;
|
||||
}
|
||||
height: 156px;
|
||||
}
|
||||
/* @media (max-width: 699px) { */
|
||||
/* .list > .component_thing.view-grid { */
|
||||
/* width: 33.33%; */
|
||||
/* } */
|
||||
/* .list > .component_thing.view-grid .box { */
|
||||
/* height: 200px; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* @media (max-width: 670px) { */
|
||||
/* .list > .component_thing.view-grid .box { */
|
||||
/* height: 170px; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* @media (max-width: 550px) { */
|
||||
/* .list > .component_thing.view-grid { */
|
||||
/* width: 50%; */
|
||||
/* } */
|
||||
/* .list > .component_thing.view-grid .box { */
|
||||
/* height: 200px; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* @media (max-width: 480px) { */
|
||||
/* .list > .component_thing.view-grid .box { */
|
||||
/* height: 170px; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* @media (max-width: 400px) { */
|
||||
/* .list > .component_thing.view-grid .box { */
|
||||
/* height: 140px; */
|
||||
/* } */
|
||||
/* .list > .component_thing.view-grid .box .info_extension { */
|
||||
/* font-size: 0.8em !important; */
|
||||
/* padding: 3px 10px; */
|
||||
/* } */
|
||||
/* } */
|
||||
/* @media (max-width: 340px) { */
|
||||
/* .list > .component_thing.view-grid .box { */
|
||||
/* height: 130px; */
|
||||
/* } */
|
||||
/* } */
|
||||
.list > .component_thing.view-grid .box {
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
border-width: 0;
|
||||
box-sizing: border-box;
|
||||
border: 2px solid rgba(100, 100, 100, 0.1);
|
||||
border: 2px solid rgba(100, 100, 100, 0.05);
|
||||
border-radius: 5px;
|
||||
}
|
||||
.list > .component_thing.view-grid .box > span > img {
|
||||
|
||||
@@ -7,7 +7,7 @@ const $tmpl = createElement(`
|
||||
<div class="box">
|
||||
<div class="component_checkbox"><input type="checkbox"><span class="indicator"></span></div>
|
||||
<span>
|
||||
<img class="component_icon" draggable="false" src="https://demo.filestash.app/assets/icons/folder.svg" alt="directory">
|
||||
<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBoZWlnaHQ9IjE2IiB3aWR0aD0iMTYiPgogIDxnIHRyYW5zZm9ybT0ibWF0cml4KDAuODY2NjY0MzEsMCwwLDAuODY2NjcsLTE3Mi4wNDU3OCwtODY0LjMyNzU5KSIgc3R5bGU9ImZpbGw6Izc1YmJkOTtmaWxsLW9wYWNpdHk6MC45NDExNzY0NztmaWxsLXJ1bGU6ZXZlbm9kZCI+CiAgICA8cGF0aCBzdHlsZT0iZmlsbDojNzViYmQ5O2ZpbGwtb3BhY2l0eTowLjk0MTE3NjQ3O2ZpbGwtcnVsZTpldmVub2RkIiBkPSJtIDIwMC4yLDk5OS43MiBjIC0wLjI4OTEzLDAgLTAuNTMxMjUsMC4yNDIxIC0wLjUzMTI1LDAuNTMxMiB2IDEyLjc4NCBjIDAsMC4yOTg1IDAuMjMyNjQsMC41MzEyIDAuNTMxMjUsMC41MzEyIGggMTUuMDkxIGMgMC4yOTg2LDAgMC41MzEyNCwtMC4yMzI3IDAuNTMxMjQsLTAuNTMxMiBsIDRlLTQsLTEwLjQ3NCBjIDAsLTAuMjg4OSAtMC4yNDIxMSwtMC41MzM4IC0wLjUzMTI0LC0wLjUzMzggbCAtNy41NDU3LDVlLTQgLTIuMzA3NiwtMi4zMDc4MyB6IiAvPgogIDwvZz4KICA8ZyB0cmFuc2Zvcm09Im1hdHJpeCgwLjg2NjY3LDAsMCwwLjg2NjY3LC0xNzIuMDQ2OTIsLTg2NC43ODM0KSIgc3R5bGU9ImZpbGw6IzlhZDFlZDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZCI+CiAgICA8cGF0aCBzdHlsZT0iZmlsbDojOWFkMWVkO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkIiBkPSJtIDIwMC4yLDk5OS43MiBjIC0wLjI4OTEzLDAgLTAuNTMxMjUsMC4yNDIxIC0wLjUzMTI1LDAuNTMxMiB2IDEyLjc4NCBjIDAsMC4yOTg1IDAuMjMyNjQsMC41MzEyIDAuNTMxMjUsMC41MzEyIGggMTUuMDkxIGMgMC4yOTg2LDAgMC41MzEyNCwtMC4yMzI3IDAuNTMxMjQsLTAuNTMxMiBsIDRlLTQsLTEwLjQ3NCBjIDAsLTAuMjg4OSAtMC4yNDIxMSwtMC41MzM4IC0wLjUzMTI0LC0wLjUzMzggbCAtNy41NDU3LDVlLTQgLTIuMzA3NiwtMi4zMDc4MyB6IiAvPgogIDwvZz4KPC9zdmc+Cg==" alt="directory">
|
||||
</span>
|
||||
<span class="component_filename">
|
||||
<span class="file-details">
|
||||
@@ -15,17 +15,15 @@ const $tmpl = createElement(`
|
||||
</span>
|
||||
</span>
|
||||
<span class="component_datetime"><span>06/06/2020</span></span>
|
||||
<div class="component_action">
|
||||
<span><img class="component_icon" draggableg="false" src="https://demo.filestash.app/assets/icons/edit.svg" alt="edit"></span>
|
||||
<span><img class="component_icon" draggable="false" src="https://demo.filestash.app/assets/icons/delete.svg" alt="delete"></span>
|
||||
<span><img class="component_icon" draggable="false" src="https://demo.filestash.app/assets/icons/share.svg" alt="share"></span>
|
||||
</div>
|
||||
<div class="component_action"></div>
|
||||
<div class="selectionOverlay"></div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
`);
|
||||
|
||||
export const css = CSS(import.meta.url, "thing.css");
|
||||
|
||||
// a filesystem "thing" is typically either a file or folder which have a lot of behavior builtin.
|
||||
// Probably one day we can rename that to something more clear but the gist is a thing can be
|
||||
// displayed in list mode / grid mode, have some substate to enable loading state for upload,
|
||||
@@ -39,7 +37,7 @@ export function createThing({
|
||||
link = "",
|
||||
// permissions = {}
|
||||
}) {
|
||||
const $thing = $tmpl.cloneNode(true);
|
||||
const $thing = $get();
|
||||
if ($thing instanceof HTMLElement) {
|
||||
const $label = $thing.querySelector(".component_filename .file-details > span");
|
||||
if ($label instanceof HTMLElement) $label.textContent = name;
|
||||
@@ -48,4 +46,19 @@ export function createThing({
|
||||
return $thing;
|
||||
}
|
||||
|
||||
export const css = CSS(import.meta.url, "thing.css");
|
||||
function $get() {
|
||||
// the very first implementation was:
|
||||
return $tmpl.cloneNode(true);
|
||||
// the major issue was cloneNode is slow and would often make us miss an animationFrame. A much more
|
||||
// efficient approach is to use a ring buffer of node we reuse as we scroll around
|
||||
if (bufferIdx >= $tmplBuffer.length) bufferIdx = 0;
|
||||
const $node = $tmplBuffer[bufferIdx];
|
||||
bufferIdx += 1;
|
||||
// console.log($node);
|
||||
return $node;
|
||||
}
|
||||
let $tmplBuffer = [];
|
||||
let bufferIdx = 0;
|
||||
export function allocateMemory(size) {
|
||||
$tmplBuffer = Array.apply(null, {length: size}).map(() => $tmpl.cloneNode(true))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/admin/assets/css/reset.css">
|
||||
<link rel="stylesheet" href="/admin/assets/css/designsystem.css">
|
||||
<title>Admin Console</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/assets/css/reset.css">
|
||||
<link rel="stylesheet" href="/assets/css/designsystem.css">
|
||||
<script type="module" src="/assets/components/loader.js"></script>
|
||||
<title></title>
|
||||
</head>
|
||||
@@ -21,10 +21,11 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="module" src="/assets/components/modal.js"></script>
|
||||
<component-modal></component-modal>
|
||||
<script type="module" src="/assets/components/notification.js"></script>
|
||||
<script type="module" src="/assets/components/modal.js" defer></script>
|
||||
|
||||
<component-notification></component-notification>
|
||||
<script type="module" src="/assets/components/notification.js" defer></script>
|
||||
|
||||
<noscript>
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user