Commit 776e2861 authored by Nicolas Pernoud's avatar Nicolas Pernoud
Browse files

feat: reworked looks with custom bulma style

parent 1080f299
Pipeline #5036 passed with stages
in 2 minutes and 33 seconds
vestibule
__debug_bin
miscellaneous/mock_onlyoffice/data
node_modules/
miscellaneous/bulma/css/
\ No newline at end of file
......@@ -116,7 +116,6 @@ Loosely based on Webfront (https://github.com/nf/webfront), by Andrew Gerrand, G
Uses :
- Bulma : https://bulma.io/, https://github.com/jgthms/bulma (MIT Licence)
- Bulma Fluent : https://mubaidr.js.org/bulma-fluent/#/, https://github.com/mubaidr/bulma-fluent (MIT Licence)
- Animate.css : https://daneden.github.io/animate.css/, https://github.com/daneden/animate.css (MIT Licence)
- Font Awesome : https://fontawesome.com, https://github.com/FortAwesome/Font-Awesome (Font Awesome Free License)
- Secure IO : https://secure-io.org, https://github.com/secure-io/sio-go (MIT Licence), lots of thanks to @aead (Andreas Auernhammer) who has been a great help in understanding the library and for his cryptography insights
......@@ -129,7 +128,7 @@ Uses :
The product is licenced under **_GNU AFFERO GENERAL PUBLIC LICENSE Version 3_**, it is made primarily by Nicolas Pernoud, a member of **Métropole de Lyon**, on professional time (some), and personal time (most). It is used on Métropole de Lyon "alpha" lab to allow quick prototyping and proof of concepts.
![Alpha logo](miscellaneous/images/logo_alpha_couleurs_RVB.png "Alpha logo")
<img src="miscellaneous/images/logo_alpha_couleurs_RVB.png" alt="alpha logo" style="height:100px;">
## Beeing part of the project
......
@charset "utf-8";
// Brand colors
$deep-blue: #0d47a1;
$nice-red: #c2185b;
$grey: #78909c;
$light-grey: #b0bec5;
$very-light-grey: #eceff1;
// Bulma's global variables
$primary: $deep-blue;
$dark: $grey;
$light: $light-grey;
// Bulma's component variables
$body-background-color: $very-light-grey;
$card-content-padding: 2rem;
$navbar-item-img-max-height: 2.5rem;
$navbar-background-color: $light-grey;
$navbar-item-hover-color: $nice-red;
$navbar-item-hover-background-color: $dark;
$navbar-item-active-color: $nice-red;
$navbar-item-active-background-color: $very-light-grey;
$progress-border-radius: 0px;
$progress-indeterminate-duration: 1s;
// Bulma imports
@import "node_modules/bulma/sass/utilities/_all.sass";
@import "node_modules/bulma/sass/base/_all.sass";
//@import "node_modules/bulma/sass/components/breadcrumb.sass";
@import "node_modules/bulma/sass/components/card.sass";
@import "node_modules/bulma/sass/components/dropdown.sass";
//@import "node_modules/bulma/sass/components/level.sass";
//@import "node_modules/bulma/sass/components/list.sass";
@import "node_modules/bulma/sass/components/media.sass";
//@import "node_modules/bulma/sass/components/menu.sass";
//@import "node_modules/bulma/sass/components/message.sass";
@import "node_modules/bulma/sass/components/modal.sass";
@import "node_modules/bulma/sass/components/navbar.sass";
//@import "node_modules/bulma/sass/components/pagination.sass";
//@import "node_modules/bulma/sass/components/panel.sass";
//@import "node_modules/bulma/sass/components/tabs.sass";
//@import "node_modules/bulma/sass/elements/box.sass";
@import "node_modules/bulma/sass/elements/button.sass";
@import "node_modules/bulma/sass/elements/container.sass";
@import "node_modules/bulma/sass/elements/content.sass";
@import "node_modules/bulma/sass/elements/form.sass";
@import "node_modules/bulma/sass/elements/icon.sass";
@import "node_modules/bulma/sass/elements/image.sass";
@import "node_modules/bulma/sass/elements/notification.sass";
@import "node_modules/bulma/sass/elements/other.sass";
@import "node_modules/bulma/sass/elements/progress.sass";
@import "node_modules/bulma/sass/elements/table.sass";
//@import "node_modules/bulma/sass/elements/tag.sass";
@import "node_modules/bulma/sass/elements/title.sass";
@import "node_modules/bulma/sass/form/shared.sass";
//@import "node_modules/bulma/sass/form/checkbox-radio.sass";
@import "node_modules/bulma/sass/form/file.sass";
@import "node_modules/bulma/sass/form/input-textarea.sass";
@import "node_modules/bulma/sass/form/select.sass";
@import "node_modules/bulma/sass/form/tools.sass";
@import "node_modules/bulma/sass/grid/columns.sass";
//@import "node_modules/bulma/sass/grid/tiles.sass";
@import "node_modules/bulma/sass/layout/footer.sass";
//@import "node_modules/bulma/sass/layout/hero.sass";
@import "node_modules/bulma/sass/layout/section.sass";
#!/bin/bash
rm ../../web/assets/bulma.min.css
ln -s $(pwd)/css/bulma.css $(pwd)/../../web/assets/bulma.min.css
This diff is collapsed.
{
"name": "vestibulma",
"version": "1.0.0",
"description": "Bulma for vestibule",
"main": "sass/mystyles.scss",
"scripts": {
"build": "npm run build-clean && npm run build-sass && npm run build-autoprefix && npm run build-cleancss",
"build-autoprefix": "postcss --use autoprefixer --map false --output css/bulma.css css/bulma.css",
"build-cleancss": "cleancss -o ../../web/assets/bulma.min.css css/bulma.css",
"build-clean": "rimraf css",
"build-sass": "node-sass --output-style expanded --source-map true bulma.scss css/bulma.css",
"deploy": "npm run build",
"start": "npm run build-sass -- --watch"
},
"author": "Nicolas Pernoud",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"autoprefixer": "^9.7.6",
"bulma": "^0.8.2",
"clean-css-cli": "^4.3.0",
"node-sass": "^4.13.1",
"postcss-cli": "^7.1.0",
"rimraf": "^3.0.2"
}
}
miscellaneous/images/app_config.png

49.1 KB | W: | H:

miscellaneous/images/app_config.png

35.9 KB | W: | H:

miscellaneous/images/app_config.png
miscellaneous/images/app_config.png
miscellaneous/images/app_config.png
miscellaneous/images/app_config.png
  • 2-up
  • Swipe
  • Onion skin
miscellaneous/images/apps_list.png

35.6 KB | W: | H:

miscellaneous/images/apps_list.png

33.9 KB | W: | H:

miscellaneous/images/apps_list.png
miscellaneous/images/apps_list.png
miscellaneous/images/apps_list.png
miscellaneous/images/apps_list.png
  • 2-up
  • Swipe
  • Onion skin
miscellaneous/images/dav_config.png

44.2 KB | W: | H:

miscellaneous/images/dav_config.png

35.2 KB | W: | H:

miscellaneous/images/dav_config.png
miscellaneous/images/dav_config.png
miscellaneous/images/dav_config.png
miscellaneous/images/dav_config.png
  • 2-up
  • Swipe
  • Onion skin
miscellaneous/images/davs_list.png

37.4 KB | W: | H:

miscellaneous/images/davs_list.png

40.4 KB | W: | H:

miscellaneous/images/davs_list.png
miscellaneous/images/davs_list.png
miscellaneous/images/davs_list.png
miscellaneous/images/davs_list.png
  • 2-up
  • Swipe
  • Onion skin
miscellaneous/images/file_preview.png

26.8 KB | W: | H:

miscellaneous/images/file_preview.png

16.3 KB | W: | H:

miscellaneous/images/file_preview.png
miscellaneous/images/file_preview.png
miscellaneous/images/file_preview.png
miscellaneous/images/file_preview.png
  • 2-up
  • Swipe
  • Onion skin
miscellaneous/images/login.png

16.4 KB | W: | H:

miscellaneous/images/login.png

16.3 KB | W: | H:

miscellaneous/images/login.png
miscellaneous/images/login.png
miscellaneous/images/login.png
miscellaneous/images/login.png
  • 2-up
  • Swipe
  • Onion skin
miscellaneous/images/opened_app.png

35.1 KB | W: | H:

miscellaneous/images/opened_app.png

31.4 KB | W: | H:

miscellaneous/images/opened_app.png
miscellaneous/images/opened_app.png
miscellaneous/images/opened_app.png
miscellaneous/images/opened_app.png
  • 2-up
  • Swipe
  • Onion skin
miscellaneous/images/opened_dav.png

41.4 KB | W: | H:

miscellaneous/images/opened_dav.png

30.5 KB | W: | H:

miscellaneous/images/opened_dav.png
miscellaneous/images/opened_dav.png
miscellaneous/images/opened_dav.png
miscellaneous/images/opened_dav.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -72,7 +72,7 @@
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
<path
style="fill:#ff6600;fill-opacity:1;stroke-width:0.83692497"
style="fill:#0d47a1;fill-opacity:1;stroke-width:0.83692497"
d="M 85.498214,7.8627842 170.16488,27.58243 v 78.41994 l -84.666666,23.38841 z"
id="rect820"
inkscape:connector-curvature="0"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -171,12 +171,10 @@ function appTemplate(app) {
cleanApp(app);
return /* HTML */ `
<div id="apps-app-${app.id}" class="card icon-card">
<div class="card-content has-text-centered">
<button id="apps-app-open-${app.id}" class="button is-large is-white">
<span class="icon is-medium" style="color:${app.color};">
<i class="fas fa-2x fa-${app.icon ? app.icon : "file"}"></i>
</span>
</button>
<div class="card-content has-text-centered" id="apps-app-open-${app.id}">
<span class="icon is-medium" style="color:${app.color};">
<i class="fas fa-3x fa-${app.icon ? app.icon : "file"}"></i>
</span>
</div>
<p class="has-text-centered"><strong>${app.name ? app.name : app.id}</strong></p>
<div class="card-footer">
......
......@@ -138,12 +138,10 @@ function davTemplate(dav) {
const free = dav.totalgb - dav.usedgb;
return /* HTML */ `
<div id="davs-dav-${dav.id}" class="card icon-card">
<div class="card-content has-text-centered">
<button id="davs-dav-open-${dav.id}" class="button is-large is-white">
<span class="icon is-medium" style="color:${dav.color};">
<i class="fas fa-2x fa-${dav.icon ? dav.icon : "file"}"></i>
</span>
</button>
<div id="davs-dav-open-${dav.id}" class="card-content has-text-centered">
<span class="icon is-medium" style="color:${dav.color};">
<i class="fas fa-3x fa-${dav.icon ? dav.icon : "file"}"></i>
</span>
</div>
<p class="has-text-centered"><strong>${dav.name ? dav.name : dav.id}</strong></p>
<div class="card-footer">
......@@ -162,7 +160,9 @@ function davTemplate(dav) {
${user.isAdmin ? '<a class="dropdown-item has-text-danger" id="davs-dav-delete-' + dav.id + '"><i class="fas fa-trash-alt"></i><strong> Delete</strong></a>' : ""}
<hr class="dropdown-divider" />
<div class="dropdown-item">
<p><progress class="progress is-${GetColor(du)}" value="${dav.usedgb}" max="${dav.totalgb}"></progress>${dav.usedgb !== undefined ? free + " GB free" : ""}</p>
<p>
<progress class="progress is-${GetColor(du)} is-small" value="${dav.usedgb}" max="${dav.totalgb}"></progress>${dav.usedgb !== undefined ? free + " GB free" : ""}
</p>
<hr class="dropdown-divider" />
<p><strong>${dav.host}</strong></p>
<p>Serves ${dav.root} directory, with ${dav.writable ? "read/write" : "read only"} access</p>
......
......@@ -26,7 +26,7 @@ export class Explorer {
<button class="delete" aria-label="close" id="explorer-modal-close"></button>
</header>
<section id="explorer-modal-content" class="modal-card-body"></section>
<progress id="explorer-modal-progress" class="progress is-primary" style="margin-bottom:0px;"></progress>
<progress id="explorer-modal-progress" class="progress is-primary is-small" style="margin-bottom:0px;"></progress>
<footer id="explorer-modal-footer" class="modal-card-foot">
<div class="buttons" id="explorer-modal-footer-buttons">
<button id="explorer-modal-back" class="button is-success">
......@@ -58,10 +58,10 @@ export class Explorer {
</footer>
`;
this.user = await Auth.GetUser();
document.getElementById(`explorer-modal-close`).addEventListener("click", function() {
document.getElementById(`explorer-modal-close`).addEventListener("click", function () {
const modal = card.parentNode;
AnimateCSS(modal, "fadeOut");
AnimateCSS(card, "zoomOut", function() {
AnimateCSS(card, "zoomOut", function () {
modal.classList.remove("is-active");
});
});
......@@ -75,7 +75,7 @@ export class Explorer {
document.getElementById(`explorer-modal-newtxt`).addEventListener("click", () => {
this.newTxt();
});
document.getElementById(`explorer-modal-upload`).addEventListener("change", e => {
document.getElementById(`explorer-modal-upload`).addEventListener("change", (e) => {
this.upload(e.srcElement.files);
});
}
......@@ -92,9 +92,9 @@ export class Explorer {
method: "PROPFIND",
headers: new Headers({
Depth: "1",
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 207) {
throw new Error(`Files could not be fetched (status ${response.status})`);
......@@ -110,10 +110,10 @@ export class Explorer {
displayFiles() {
// Create template
const markup = this.files.map(file => this.fileTemplate(file)).join("");
const markup = this.files.map((file) => this.fileTemplate(file)).join("");
document.getElementById("explorer-modal-content").innerHTML = markup;
// Register events
this.files.map(file => {
this.files.map((file) => {
this.registerEvents(file);
});
}
......@@ -190,15 +190,15 @@ export class Explorer {
const response = await fetch(location.origin + "/api/common/Share", {
method: "POST",
headers: new Headers({
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include",
body: JSON.stringify({
sharedfor: "external_editor",
lifespan: 1,
url: this.hostname + file.path,
readonly: false
})
readonly: false,
}),
});
if (response.status !== 200) {
throw new Error(`Share token could not be made (status ${response.status})`);
......@@ -217,37 +217,37 @@ export class Explorer {
});
if (this.readwrite) {
document.getElementById(`file-${file.id}-rename`).addEventListener("click", event => {
document.getElementById(`file-${file.id}-rename`).addEventListener("click", (event) => {
event.stopPropagation();
this.rename(file);
});
document.getElementById(`file-${file.id}-cut`).addEventListener("click", event => {
document.getElementById(`file-${file.id}-cut`).addEventListener("click", (event) => {
event.stopPropagation();
this.moveOrCopy(file, false);
});
document.getElementById(`file-${file.id}-copy`).addEventListener("click", event => {
document.getElementById(`file-${file.id}-copy`).addEventListener("click", (event) => {
event.stopPropagation();
this.moveOrCopy(file, true);
});
if (GetType(file) === "text") {
document.getElementById(`file-${file.id}-edit`).addEventListener("click", event => {
document.getElementById(`file-${file.id}-edit`).addEventListener("click", (event) => {
event.stopPropagation();
const editModal = new Edit(this.fullHostname, file);
editModal.show(true);
});
}
document.getElementById(`file-${file.id}-delete`).addEventListener("click", event => {
document.getElementById(`file-${file.id}-delete`).addEventListener("click", (event) => {
event.stopPropagation();
this.delete(file);
});
}
if (!(this.encrypted && file.isDir)) {
document.getElementById(`file-${file.id}-download`).addEventListener("click", event => {
document.getElementById(`file-${file.id}-download`).addEventListener("click", (event) => {
event.stopPropagation();
this.download(file);
});
}
document.getElementById(`file-${file.id}-share`).addEventListener("click", event => {
document.getElementById(`file-${file.id}-share`).addEventListener("click", (event) => {
event.stopPropagation();
const shareModal = new Share(this.hostname, file);
shareModal.show(true);
......@@ -290,9 +290,9 @@ export class Explorer {
method: "MOVE",
headers: new Headers({
Destination: this.fullHostname + path(this.path, renameModal.getElementsByTagName("input")[0].value),
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 201) {
throw new Error(`File could not be renamed (status ${response.status})`);
......@@ -303,12 +303,12 @@ export class Explorer {
} catch (e) {
HandleError(e);
}
AnimateCSS(renameModal, "fadeOut", function() {
AnimateCSS(renameModal, "fadeOut", function () {
renameModal.parentNode.removeChild(renameModal);
});
});
renameModal.querySelector("#" + "explorer-rename-cancel").addEventListener("click", () => {
AnimateCSS(renameModal, "fadeOut", function() {
AnimateCSS(renameModal, "fadeOut", function () {
renameModal.parentNode.removeChild(renameModal);
});
});
......@@ -339,9 +339,9 @@ export class Explorer {
method: isCopy ? "COPY" : "MOVE",
headers: new Headers({
Destination: this.fullHostname + path(this.path, file.name),
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 201) {
throw new Error(`File could not be pasted (status ${response.status})`);
......@@ -350,12 +350,12 @@ export class Explorer {
} catch (e) {
HandleError(e);
}
AnimateCSS(pasteControl, "zoomOut", function() {
AnimateCSS(pasteControl, "zoomOut", function () {
pasteControl.parentNode.removeChild(pasteControl);
});
});
pasteControl.getElementsByTagName("a")[1].addEventListener("click", async () => {
AnimateCSS(pasteControl, "zoomOut", function() {
AnimateCSS(pasteControl, "zoomOut", function () {
pasteControl.parentNode.removeChild(pasteControl);
});
});
......@@ -369,9 +369,9 @@ export class Explorer {
const response = await fetch(this.fullHostname + folder.path, {
method: "MKCOL",
headers: new Headers({
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 201) {
throw new Error(`Folder could not be created (status ${response.status})`);
......@@ -387,15 +387,15 @@ export class Explorer {
const newTxtName = "New Text.txt";
const txt = { name: newTxtName, isDir: false, type: "text", size: 0, lastModified: new Date(), path: path(this.path, newTxtName), id: this.files.length + 1 };
try {
if (this.files.some(file => file.name === newTxtName)) {
if (this.files.some((file) => file.name === newTxtName)) {
throw new Error(`Text document already exists`);
}
const response = await fetch(this.fullHostname + txt.path, {
method: "PUT",
headers: new Headers({
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 201) {
throw new Error(`Text document could not be created (status ${response.status})`);
......@@ -413,14 +413,14 @@ export class Explorer {
const response = await fetch(this.fullHostname + file.path, {
method: "DELETE",
headers: new Headers({
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 204) {
throw new Error(`File could not be deleted (status ${response.status})`);
}
this.files = this.files.filter(el => el.name !== file.name);
this.files = this.files.filter((el) => el.name !== file.name);
this.displayFiles();
} catch (e) {
HandleError(e);
......@@ -440,13 +440,13 @@ export class Explorer {
let msg = document.createElement("div");
msg.innerHTML = /* HTML */ `
<div class="content"><p>${file.name} (file: ${fileIdx}/${files.length})</p></div>
<progress class="progress is-primary" value="0" max="100" style="margin-bottom: 0px;"></progress>
<progress class="progress is-primary is-small" value="0" max="100" style="margin-bottom: 0px;"></progress>
`;
msg.classList.add("is-info", "notification", "uploader", "animated", "fadeInUp", "faster");
const delBtn = document.createElement("button");
let xhr = new XMLHttpRequest();
// track upload progress
xhr.upload.onprogress = function(e) {
xhr.upload.onprogress = function (e) {
msg.getElementsByTagName("progress")[0].value = (e.loaded / e.total) * 100;
};
delBtn.addEventListener("click", async () => {
......@@ -455,9 +455,9 @@ export class Explorer {
const response = await fetch(this.fullHostname + file.path, {
method: "DELETE",
headers: new Headers({
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 204) {
throw new Error(`Cancelled file could not be deleted (status ${response.status})`);
......@@ -479,7 +479,7 @@ export class Explorer {
type: file.type,
size: file.size,
lastModified: file.lastModified,
id: id
id: id,
});
this.displayFiles();
}
......@@ -487,7 +487,7 @@ export class Explorer {
console.error(e.statusText);
Messages.Show("is-warning", e.statusText);
}
AnimateCSS(msg, "fadeOutDown", function() {
AnimateCSS(msg, "fadeOutDown", function () {
msg.parentNode.removeChild(msg);
});
}
......@@ -501,21 +501,21 @@ export class Explorer {
if (xhr.status === 0) {
reject({
status: xhr.status,
statusText: `Upload of ${file.name} cancelled`
statusText: `Upload of ${file.name} cancelled`,
});
} else if (xhr.status == 201) {
resolve(xhr.status);
} else {
reject({
status: xhr.status,
statusText: `Error uploading ${file.name} (status ${xhr.status})`
statusText: `Error uploading ${file.name} (status ${xhr.status})`,
});
}
};
xhr.onerror = function(e) {
xhr.onerror = function (e) {
reject({
status: this.status,
statusText: `Error uploading ${file.name} (status ${xhr.status})`
statusText: `Error uploading ${file.name} (status ${xhr.status})`,
});
};
xhr.open("PUT", this.fullHostname + file.path);
......@@ -529,15 +529,15 @@ export class Explorer {
const response = await fetch(location.origin + "/api/common/Share", {
method: "POST",
headers: new Headers({
"XSRF-Token": this.user.xsrftoken
"XSRF-Token": this.user.xsrftoken,
}),
credentials: "include",
body: JSON.stringify({
sharedfor: "download",
lifespan: 1,
url: this.hostname + file.path,
readonly: true
})
readonly: true,
}),
});
if (response.status !== 200) {
throw new Error(`Share token could not be made (status ${response.status})`);
......@@ -608,9 +608,9 @@ export async function LoadImage(image, url, user) {
const response = await fetch(url, {
method: "GET",
headers: new Headers({
"XSRF-Token": user.xsrftoken
"XSRF-Token": user.xsrftoken,
}),
credentials: "include"
credentials: "include",
});
if (response.status !== 200) {
throw new Error(`Error loading image (status ${response.status})`);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment