This commit is contained in:
zadam 2019-05-02 22:24:43 +02:00
parent 63ab82a076
commit 0d11cadc18
17 changed files with 264 additions and 264 deletions

View File

@ -149,27 +149,4 @@
.chrome-tabs.chrome-tabs-is-sorting .chrome-tab:not(.chrome-tab-is-dragging),
.chrome-tabs:not(.chrome-tabs-is-sorting) .chrome-tab.chrome-tab-was-just-dragged {
transition: transform 120ms ease-in-out;
}
.chrome-tabs .chrome-tabs-bottom-bar {
position: absolute;
bottom: 0;
height: 4px;
left: 0;
width: 100%;
background: #fff;
z-index: 10;
}
.chrome-tabs-optional-shadow-below-bottom-bar {
position: relative;
height: 1px;
width: 100%;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1' viewBox='0 0 1 1'><rect x='0' y='0' width='1' height='1' fill='rgba(0, 0, 0, .17)'></rect></svg>");
background-size: 1px 1px;
background-repeat: repeat-x;
background-position: 0% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
.chrome-tabs-optional-shadow-below-bottom-bar {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' viewBox='0 0 2 2'><rect x='0' y='0' width='2' height='1' fill='rgba(0, 0, 0, .27)'></rect></svg>");
}
}
}

View File

@ -41,12 +41,7 @@
const tabTemplate = `
<div class="chrome-tab">
<div class="chrome-tab-dividers"></div>
<div class="chrome-tab-background">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"><defs><symbol id="chrome-tab-geometry-left" viewBox="0 0 214 36"><path d="M17 0h197v36H0v-2c4.5 0 9-3.5 9-8V8c0-4.5 3.5-8 8-8z"/></symbol><symbol id="chrome-tab-geometry-right" viewBox="0 0 214 36"><use xlink:href="#chrome-tab-geometry-left"/></symbol><clipPath id="crop"><rect class="mask" width="100%" height="100%" x="0"/></clipPath></defs><svg width="52%" height="100%"><use xlink:href="#chrome-tab-geometry-left" width="214" height="36" class="chrome-tab-geometry"/></svg><g transform="scale(-1, 1)"><svg width="52%" height="100%" x="-100%" y="0"><use xlink:href="#chrome-tab-geometry-right" width="214" height="36" class="chrome-tab-geometry"/></svg></g></svg>
</div>
<div class="chrome-tab-content">
<div class="chrome-tab-favicon"></div>
<div class="chrome-tab-title"></div>
<div class="chrome-tab-drag-handle"></div>
<div class="chrome-tab-close"></div>
@ -211,6 +206,8 @@
this.cleanUpPreviouslyDraggedTabs()
this.layoutTabs()
this.setupDraggabilly()
return tabEl
}
setTabCloseEventListener(tabEl) {
@ -251,15 +248,6 @@
updateTab(tabEl, tabProperties) {
tabEl.querySelector('.chrome-tab-title').textContent = tabProperties.title
const faviconEl = tabEl.querySelector('.chrome-tab-favicon')
if (tabProperties.favicon) {
faviconEl.style.backgroundImage = `url('${ tabProperties.favicon }')`
faviconEl.removeAttribute('hidden', '')
} else {
faviconEl.setAttribute('hidden', '')
faviconEl.removeAttribute('style')
}
if (tabProperties.id) {
tabEl.setAttribute('data-tab-id', tabProperties.id)
}

View File

@ -157,13 +157,3 @@ noteTypeService.init();
linkService.init();
noteAutocompleteService.init();
$(document).ready(() => {
const el = $('.chrome-tabs')[0];
const chromeTabs = new ChromeTabs();
chromeTabs.init(el);
el.addEventListener('activeTabChange', ({detail}) => console.log('Active tab changed', detail.tabEl));
el.addEventListener('tabAdd', ({detail}) => console.log('Tab added', detail.tabEl));
el.addEventListener('tabRemove', ({detail}) => console.log('Tab removed', detail.tabEl));
});

View File

@ -36,6 +36,9 @@ async function getAttributes() {
}
async function showAttributes() {
// FIXME tabs
return;
$promotedAttributesContainer.empty();
$attributeList.hide();
$attributeListInner.empty();

View File

@ -106,9 +106,9 @@ function init() {
// of opening the link in new window/tab
$(document).on('click', "a[data-action='note']", goToLink);
$(document).on('click', 'div.popover-content a, div.ui-tooltip-content a', goToLink);
$(document).on('dblclick', '#note-detail-text a', goToLink);
$(document).on('click', '#note-detail-render a', goToLink);
$(document).on('click', '#note-detail-text.ck-read-only a', goToLink);
$(document).on('dblclick', '.note-detail-text a', goToLink);
$(document).on('click', '.note-detail-render a', goToLink);
$(document).on('click', '.note-detail-text.ck-read-only a', goToLink);
$(document).on('click', 'span.ck-button__label', e => {
// this is a link preview dialog from CKEditor link editing
// for some reason clicked element is span

View File

@ -13,7 +13,15 @@ import noteDetailSearch from "./note_detail_search.js";
import noteDetailRender from "./note_detail_render.js";
import noteDetailRelationMap from "./note_detail_relation_map.js";
const $noteTabsContainer = $("#note-tab-container");
const $noteTabContentsContainer = $("#note-tab-container");
const el = $('.chrome-tabs')[0];
const chromeTabs = new ChromeTabs();
chromeTabs.init(el);
el.addEventListener('activeTabChange', ({detail}) => console.log('Active tab changed', detail.tabEl));
el.addEventListener('tabAdd', ({detail}) => console.log('Tab added', detail.tabEl));
el.addEventListener('tabRemove', ({detail}) => console.log('Tab removed', detail.tabEl));
const componentClasses = {
'code': noteDetailCode,
@ -26,17 +34,17 @@ const componentClasses = {
};
class NoteContext {
constructor(noteId) {
constructor(note) {
/** @type {NoteFull} */
this.note = null;
this.noteId = noteId;
this.$noteTab = $noteTabsContainer.find(`[data-note-id="${noteId}"]`);
this.$noteTitle = this.$noteTab.find(".note-title");
this.$noteDetailComponents = this.$noteTab.find(".note-detail-component");
this.$protectButton = this.$noteTab.find(".protect-button");
this.$unprotectButton = this.$noteTab.find(".unprotect-button");
this.$childrenOverview = this.$noteTab.find(".children-overview");
this.$scriptArea = this.$noteTab.find(".note-detail-script-area");
this.note = note;
this.noteId = note.noteId;
this.$noteTabContent = $noteTabContentsContainer.find(`[data-note-id="${this.noteId}"]`);
this.$noteTitle = this.$noteTabContent.find(".note-title");
this.$noteDetailComponents = this.$noteTabContent.find(".note-detail-component");
this.$protectButton = this.$noteTabContent.find(".protect-button");
this.$unprotectButton = this.$noteTabContent.find(".unprotect-button");
this.$childrenOverview = this.$noteTabContent.find(".children-overview");
this.$scriptArea = this.$noteTabContent.find(".note-detail-script-area");
this.isNoteChanged = false;
this.components = {};
@ -47,6 +55,19 @@ class NoteContext {
treeService.setNoteTitle(this.noteId, title);
});
this.tab = chromeTabs.addTab({
title: note.title,
favicon: false
});
}
setNote(note) {
this.noteId = note.noteId;
this.note = note;
this.$noteTabContent.attr('data-note-id', note.noteId);
chromeTabs.updateTab(this.tab, {title: note.title});
}
getComponent(type) {
@ -135,20 +156,20 @@ class NoteContext {
}
updateNoteView() {
this.$noteTab.toggleClass("protected", this.note.isProtected);
this.$noteTabContent.toggleClass("protected", this.note.isProtected);
this.$protectButton.toggleClass("active", this.note.isProtected);
this.$protectButton.prop("disabled", this.note.isProtected);
this.$unprotectButton.toggleClass("active", !this.note.isProtected);
this.$unprotectButton.prop("disabled", !this.note.isProtected || !protectedSessionHolder.isProtectedSessionAvailable());
for (const clazz of Array.from(this.$noteTab[0].classList)) { // create copy to safely iterate over while removing classes
for (const clazz of Array.from(this.$noteTabContent[0].classList)) { // create copy to safely iterate over while removing classes
if (clazz.startsWith("type-") || clazz.startsWith("mime-")) {
this.$noteTab.removeClass(clazz);
this.$noteTabContent.removeClass(clazz);
}
}
this.$noteTab.addClass(utils.getNoteTypeClass(this.note.type));
this.$noteTab.addClass(utils.getMimeTypeClass(this.note.mime));
this.$noteTabContent.addClass(utils.getNoteTypeClass(this.note.type));
this.$noteTabContent.addClass(utils.getMimeTypeClass(this.note.mime));
}
}

View File

@ -13,7 +13,7 @@ import attributeService from "./attributes.js";
import utils from "./utils.js";
import importDialog from "../dialogs/import.js";
const $noteTabsContainer = $("#note-tab-container");
const $noteTabContentsContainer = $("#note-tab-container");
const $savedIndicator = $("#saved-indicator");
let noteChangeDisabled = false;
@ -43,18 +43,11 @@ async function reload() {
await loadNoteDetail(getActiveNoteId());
}
async function openInTab(noteId) {
await loadNoteDetail(noteId, true);
}
async function switchToNote(noteId) {
if (Object.keys(noteContexts).length === 0) {
const tabContent = $("#note-tab-content-template").clone();
tabContent.removeAttr('id');
tabContent.attr('data-note-id', noteId);
$noteTabsContainer.append(tabContent);
noteContexts[noteId] = new NoteContext(noteId);
}
//if (getActiveNoteId() !== noteId) {
await saveNotesIfChanged();
@ -71,7 +64,7 @@ function onNoteChange(func) {
}
async function saveNotesIfChanged() {
for (const ctx of Object.values(noteContexts)) {
for (const ctx of noteContexts) {
await ctx.saveNoteIfChanged();
}
@ -93,13 +86,15 @@ async function handleProtectedSession() {
return newSessionCreated;
}
/** @type {Object.<string, NoteContext>} */
const noteContexts = {};
/** @type {NoteContext[]} */
const noteContexts = [];
/** @returns {NoteContext} */
function getContext(noteId) {
if (noteId in noteContexts) {
return noteContexts[noteId];
const noteContext = noteContexts.find(nc => nc.noteId === noteId);
if (noteContext) {
return noteContext;
}
else {
throw new Error(`Can't find note context for ${noteId}`);
@ -108,21 +103,36 @@ function getContext(noteId) {
/** @returns {NoteContext} */
function getActiveContext() {
const currentTreeNode = treeService.getActiveNode();
return getContext(currentTreeNode.data.noteId);
}
function showTab(noteId) {
for (const ctx of Object.values(noteContexts)) {
ctx.$noteTab.toggle(ctx.noteId === noteId);
for (const ctx of noteContexts) {
if (ctx.$noteTabContent.is(":visible")) {
return ctx;
}
}
}
async function loadNoteDetail(noteId) {
const ctx = getContext(noteId);
function showTab(noteId) {
for (const ctx of noteContexts) {
ctx.$noteTabContent.toggle(ctx.noteId === noteId);
}
}
async function loadNoteDetail(noteId, newTab = false) {
const loadedNote = await loadNote(noteId);
if (noteContexts.length === 0 || newTab) {
const tabContent = $("#note-tab-content-template").clone();
tabContent.removeAttr('id');
tabContent.attr('data-note-id', noteId);
$noteTabContentsContainer.append(tabContent);
noteContexts.push(new NoteContext(loadedNote));
}
const ctx = getActiveContext();
ctx.setNote(loadedNote);
// we will try to render the new note only if it's still the active one in the tree
// this is useful when user quickly switches notes (by e.g. holding down arrow) so that we don't
// try to render all those loaded notes one after each other. This only guarantees that correct note
@ -247,11 +257,11 @@ messagingService.subscribeToSyncMessages(syncData => {
}
});
$noteTabsContainer.on("dragover", e => e.preventDefault());
$noteTabContentsContainer.on("dragover", e => e.preventDefault());
$noteTabsContainer.on("dragleave", e => e.preventDefault());
$noteTabContentsContainer.on("dragleave", e => e.preventDefault());
$noteTabsContainer.on("drop", e => {
$noteTabContentsContainer.on("drop", e => {
importDialog.uploadFiles(getActiveNoteId(), e.originalEvent.dataTransfer.files, {
safeImport: true,
shrinkImages: true,
@ -269,6 +279,7 @@ setInterval(saveNotesIfChanged, 3000);
export default {
reload,
openInTab,
switchToNote,
loadNote,
getActiveNote,

View File

@ -3,65 +3,74 @@ import server from "./server.js";
import protectedSessionHolder from "./protected_session_holder.js";
import noteDetailService from "./note_detail.js";
const $component = $('#note-detail-file');
class NoteDetailFile {
/**
* @param {NoteContext} ctx
*/
constructor(ctx) {
this.$component = ctx.$noteTabContent.find('.note-detail-file');
this.$fileNoteId = ctx.$noteTabContent.find(".file-note-id");
this.$fileName = ctx.$noteTabContent.find(".file-filename");
this.$fileType = ctx.$noteTabContent.find(".file-filetype");
this.$fileSize = ctx.$noteTabContent.find(".file-filesize");
this.$previewRow = ctx.$noteTabContent.find(".file-preview-row");
this.$previewContent = ctx.$noteTabContent.find(".file-preview-content");
this.$downloadButton = ctx.$noteTabContent.find(".file-download");
this.$openButton = ctx.$noteTabContent.find(".file-open");
const $fileNoteId = $("#file-note-id");
const $fileName = $("#file-filename");
const $fileType = $("#file-filetype");
const $fileSize = $("#file-filesize");
const $previewRow = $("#file-preview-row");
const $previewContent = $("#file-preview-content");
const $downloadButton = $("#file-download");
const $openButton = $("#file-open");
this.$downloadButton.click(() => utils.download(this.getFileUrl()));
async function show() {
const activeNote = noteDetailService.getActiveNote();
this.$openButton.click(() => {
if (utils.isElectron()) {
const open = require("open");
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
$component.show();
$fileNoteId.text(activeNote.noteId);
$fileName.text(attributeMap.originalFileName || "?");
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
$fileType.text(activeNote.mime);
if (activeNote.content) {
$previewRow.show();
$previewContent.text(activeNote.content);
}
else {
$previewRow.hide();
open(this.getFileUrl());
}
else {
window.location.href = this.getFileUrl();
}
});
}
// open doesn't work for protected notes since it works through browser which isn't in protected session
$openButton.toggle(!activeNote.isProtected);
async show() {
const activeNote = noteDetailService.getActiveNote();
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
this.$component.show();
this.$fileNoteId.text(activeNote.noteId);
this.$fileName.text(attributeMap.originalFileName || "?");
this.$fileSize.text((attributeMap.fileSize || "?") + " bytes");
this.$fileType.text(activeNote.mime);
if (activeNote.content) {
this.$previewRow.show();
this.$previewContent.text(activeNote.content);
}
else {
this.$previewRow.hide();
}
// open doesn't work for protected notes since it works through browser which isn't in protected session
this.$openButton.toggle(!activeNote.isProtected);
}
getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
}
getContent() {}
focus() {}
onNoteChange() {}
cleanup() {}
scrollToTop() {}
}
$downloadButton.click(() => utils.download(getFileUrl()));
$openButton.click(() => {
if (utils.isElectron()) {
const open = require("open");
open(getFileUrl());
}
else {
window.location.href = getFileUrl();
}
});
function getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
}
export default {
show,
getContent: () => null,
focus: () => null,
onNoteChange: () => null,
cleanup: () => null,
scrollToTop: () => null
}
export default NoteDetailFile;

View File

@ -1,75 +1,85 @@
import utils from "./utils.js";
import protectedSessionHolder from "./protected_session_holder.js";
import noteDetailService from "./note_detail.js";
import infoService from "./info.js";
import server from "./server.js";
const $component = $('#note-detail-image');
const $imageWrapper = $('#note-detail-image-wrapper');
const $imageView = $('#note-detail-image-view');
class NoteDetailImage {
/**
* @param {NoteContext} ctx
*/
constructor(ctx) {
this.$component = ctx.$noteTabContent.find('.note-detail-image');
this.$imageWrapper = ctx.$noteTabContent.find('.note-detail-image-wrapper');
this.$imageView = ctx.$noteTabContent.find('.note-detail-image-view');
this.$copyToClipboardButton = ctx.$noteTabContent.find(".image-copy-to-clipboard");
this.$fileName = ctx.$noteTabContent.find(".image-filename");
this.$fileType = ctx.$noteTabContent.find(".image-filetype");
this.$fileSize = ctx.$noteTabContent.find(".image-filesize");
const $imageDownloadButton = $("#image-download");
const $copyToClipboardButton = $("#image-copy-to-clipboard");
const $fileName = $("#image-filename");
const $fileType = $("#image-filetype");
const $fileSize = $("#image-filesize");
this.$imageDownloadButton = ctx.$noteTabContent.find(".image-download");
this.$imageDownloadButton.click(() => utils.download(this.getFileUrl()));
async function show() {
const activeNote = noteDetailService.getActiveNote();
this.$copyToClipboardButton.click(() => {
this.$imageWrapper.attr('contenteditable','true');
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
try {
this.selectImage(this.$imageWrapper.get(0));
$component.show();
const success = document.execCommand('copy');
$fileName.text(attributeMap.originalFileName || "?");
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
$fileType.text(activeNote.mime);
$imageView.prop("src", `api/images/${activeNote.noteId}/${activeNote.title}`);
}
$imageDownloadButton.click(() => utils.download(getFileUrl()));
function selectImage(element) {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
$copyToClipboardButton.click(() => {
$imageWrapper.attr('contenteditable','true');
try {
selectImage($imageWrapper.get(0));
const success = document.execCommand('copy');
if (success) {
infoService.showMessage("Image copied to the clipboard");
}
else {
infoService.showAndLogError("Could not copy the image to clipboard.");
}
if (success) {
infoService.showMessage("Image copied to the clipboard");
}
else {
infoService.showAndLogError("Could not copy the image to clipboard.");
}
}
finally {
window.getSelection().removeAllRanges();
this.$imageWrapper.removeAttr('contenteditable');
}
});
}
finally {
window.getSelection().removeAllRanges();
$imageWrapper.removeAttr('contenteditable');
}
});
function getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
async show() {
const activeNote = noteDetailService.getActiveNote();
const attributes = await server.get('notes/' + activeNote.noteId + '/attributes');
const attributeMap = utils.toObject(attributes, l => [l.name, l.value]);
this.$component.show();
this.$fileName.text(attributeMap.originalFileName || "?");
this.$fileSize.text((attributeMap.fileSize || "?") + " bytes");
this.$fileType.text(activeNote.mime);
this.$imageView.prop("src", `api/images/${activeNote.noteId}/${activeNote.title}`);
}
selectImage(element) {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol
return utils.getHost() + "/api/notes/" + noteDetailService.getActiveNoteId() + "/download";
}
getContent() {}
focus() {}
onNoteChange() {}
cleanup() {}
scrollToTop() {
this.$component.scrollTop(0);
}
}
export default {
show,
getContent: () => null,
focus: () => null,
onNoteChange: () => null,
cleanup: () => null,
scrollToTop: () => $component.scrollTop(0)
}
export default NoteDetailImage

View File

@ -9,7 +9,7 @@ class NoteDetailText {
*/
constructor(ctx) {
this.ctx = ctx;
this.$component = ctx.$noteTab.find('.note-detail-text');
this.$component = ctx.$noteTabContent.find('.note-detail-text');
this.textEditor = null;
this.$component.on("dblclick", "img", e => {
@ -53,7 +53,7 @@ class NoteDetailText {
this.$component.show();
this.textEditor.setData(this.ctx.note.content);
// this.textEditor.setData(this.ctx.note.content);
}
getContent() {

View File

@ -485,7 +485,7 @@ function initFancyTree(tree) {
});
$tree.on('contextmenu', '.fancytree-node', function(e) {
treeContextMenuService.getContextMenuItems(e).then(contextMenuItems => {
treeContextMenuService.getContextMenuItems(e).then(([node, contextMenuItems]) => {
contextMenuWidget.initContextMenu(e, contextMenuItems, treeContextMenuService.selectContextMenuItem);
});

View File

@ -11,6 +11,7 @@ import infoService from "./info.js";
import treeCache from "./tree_cache.js";
import syncService from "./sync.js";
import hoistedNoteService from './hoisted_note.js';
import noteDetailService from './note_detail.js';
let clipboardIds = [];
let clipboardMode = null;
@ -103,6 +104,7 @@ async function getTopLevelItems(event) {
const insertChildNoteEnabled = note.type !== 'search';
return [
{ title: "Open in new tab", cmd: "openInTab", uiIcon: "empty" },
{ title: "Insert note after <kbd>Ctrl+O</kbd>", cmd: "insertNoteAfter", uiIcon: "plus",
items: insertNoteAfterEnabled ? getNoteTypeItems("insertNoteAfter") : null,
enabled: insertNoteAfterEnabled },
@ -143,9 +145,7 @@ async function getTopLevelItems(event) {
async function getContextMenuItems(event) {
const items = await getTopLevelItems(event);
// Activate node on right-click
const node = $.ui.fancytree.getNode(event);
node.setActive();
// right click resets selection to just this node
// this is important when e.g. you right click on a note while having different note active
@ -153,14 +153,17 @@ async function getContextMenuItems(event) {
node.setSelected(true);
treeService.clearSelectedNodes();
return items;
return [node, items];
}
async function selectContextMenuItem(event, cmd) {
// context menu is always triggered on current node
const node = treeService.getActiveNode();
if (cmd.startsWith("insertNoteAfter")) {
if (cmd === 'openInTab') {
noteDetailService.openInTab(node.data.noteId);
}
else if (cmd.startsWith("insertNoteAfter")) {
const parentNoteId = node.data.parentNoteId;
const isProtected = await treeUtils.getParentProtectedStatus(node);
const type = cmd.split("_")[1];

View File

@ -31,7 +31,6 @@ body {
#note-tab-container {
grid-area: tab-container;
min-height: 0;
min-height: 0;
}
#search-box {
@ -148,7 +147,7 @@ li.dropdown-submenu:hover > ul.dropdown-menu {
border: 1px solid var(--main-border-color);
}
#note-info-table td, #note-info-table th {
.note-info-table td, .note-info-table th {
padding: 15px;
}

View File

@ -50,7 +50,7 @@ html, body {
padding-left: 35px;
}
#note-title-row {
.note-title-row {
display: flex;
padding-left: 15px;
flex-shrink: 0;

View File

@ -48,7 +48,7 @@ button.close {
color: var(--main-text-color) !important;
}
#note-title {
.note-title {
margin-left: 15px;
margin-right: 10px;
font-size: 150%;
@ -95,7 +95,7 @@ ul.fancytree-container {
content: "\e9ba";
}
#note-title[readonly] {
.note-title[readonly] {
background: inherit;
}
@ -103,13 +103,17 @@ ul.fancytree-container {
display: none;
}
#note-tab-content-template {
display: none;
}
.note-tab-content {
display: flex;
flex-direction: column;
height: 100%;
}
#note-detail-component-wrapper {
.note-detail-component-wrapper {
flex-grow: 100;
position: relative;
overflow: auto;
@ -125,14 +129,14 @@ ul.fancytree-container {
display: none;
}
#note-detail-text h1 { font-size: 2.0em; }
#note-detail-text h2 { font-size: 1.8em; }
#note-detail-text h3 { font-size: 1.6em; }
#note-detail-text h4 { font-size: 1.4em; }
#note-detail-text h5 { font-size: 1.2em; }
#note-detail-text h6 { font-size: 1.1em; }
.note-detail-text h1 { font-size: 2.0em; }
.note-detail-text h2 { font-size: 1.8em; }
.note-detail-text h3 { font-size: 1.6em; }
.note-detail-text h4 { font-size: 1.4em; }
.note-detail-text h5 { font-size: 1.2em; }
.note-detail-text h6 { font-size: 1.1em; }
#note-detail-text {
.note-detail-text {
border: 0 !important;
box-shadow: none !important;
/* This is because with empty content height of editor is 0 and it's impossible to click into it */
@ -142,7 +146,7 @@ ul.fancytree-container {
font-family: var(--detail-text-font-family);
}
#note-detail-text p:first-child, #note-detail-text::before {
.note-detail-text p:first-child, .note-detail-text::before {
margin-top: 0;
}
@ -352,12 +356,12 @@ div.ui-tooltip {
color: #aaa !important;
}
#note-detail-code {
.note-detail-code {
min-height: 200px;
overflow: auto;
}
#note-detail-render {
.note-detail-render {
min-height: 200px;
}
@ -376,7 +380,7 @@ div.ui-tooltip {
border-right: none;
}
#note-type-dropdown {
.note-type-dropdown {
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
@ -403,7 +407,7 @@ div.ui-tooltip {
margin-right: 5px;
}
#file-table th, #file-table td {
.file-table th, .file-table td {
padding: 10px;
font-size: larger;
}
@ -464,7 +468,7 @@ div.ui-tooltip {
background-color: var(--button-disabled-background-color) !important;
}
#note-path-list a.current {
.note-path-list a.current {
font-weight: bold;
}
@ -473,12 +477,12 @@ button.icon-button {
padding: 2px;
}
#note-actions {
.note-actions {
margin-left: 10px;
margin-right: 10px;
}
#note-actions .dropdown-menu {
.note-actions .dropdown-menu {
width: 15em;
}
@ -495,7 +499,7 @@ button.icon-button {
padding: 0;
}
#note-detail-promoted-attributes {
.note-detail-promoted-attributes {
margin: auto;
/* setting the display to block since "table" doesn't support scrolling */
display: block;
@ -505,15 +509,15 @@ button.icon-button {
overflow: auto;
}
#note-detail-promoted-attributes td, #note-detail-promoted-attributes th {
.note-detail-promoted-attributes td, .note-detail-promoted-attributes th {
padding: 5px;
}
#note-detail-image {
.note-detail-image {
text-align: center;
}
#note-detail-image-view {
.note-detail-image-view {
max-width: 100%;
}
@ -521,7 +525,7 @@ pre:not(.CodeMirror-line) {
color: var(--main-text-color) !important;
}
#file-preview-content {
.file-preview-content {
background-color: var(--accented-background-color);
padding: 15px;
max-width: 600px;
@ -580,7 +584,7 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
padding: 10px;
}
#note-detail-render-help {
.note-detail-render-help {
margin: 50px;
padding: 20px;
}

View File

@ -16,7 +16,7 @@
<th>File size:</th>
<td class="file-filesize"></td>
</tr>
<tr id="file-preview-row">
<tr class="file-preview-row">
<th>Preview:</th>
<td>
<pre class="file-preview-content"></pre>

View File

@ -1,20 +1,5 @@
<div class="chrome-tabs">
<div class="chrome-tabs-content">
<div class="chrome-tab">
<div class="chrome-tab-content">
<div class="chrome-tab-title">Google</div>
<div class="chrome-tab-drag-handle"></div>
<div class="chrome-tab-close"></div>
</div>
</div>
<div class="chrome-tab" active>
<div class="chrome-tab-content">
<div class="chrome-tab-title">Facebook</div>
<div class="chrome-tab-drag-handle"></div>
<div class="chrome-tab-close"></div>
</div>
</div>
</div>
<div class="chrome-tabs-content"></div>
</div>
<div id="note-tab-container">