mirror of
https://github.com/zadam/trilium.git
synced 2025-12-01 04:54:25 +01:00
Merge branch 'main' of github.com:TriliumNext/Trilium
This commit is contained in:
commit
e2f0e4089f
@ -16,7 +16,7 @@
|
||||
"fs-extra": "11.3.2",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"typedoc": "0.28.14",
|
||||
"typedoc": "0.28.15",
|
||||
"typedoc-plugin-missing-exports": "4.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -487,7 +487,7 @@ type EventMappings = {
|
||||
relationMapResetPanZoom: { ntxId: string | null | undefined };
|
||||
relationMapResetZoomIn: { ntxId: string | null | undefined };
|
||||
relationMapResetZoomOut: { ntxId: string | null | undefined };
|
||||
activeNoteChanged: {};
|
||||
activeNoteChanged: {ntxId: string | null | undefined};
|
||||
showAddLinkDialog: AddLinkOpts;
|
||||
showIncludeDialog: IncludeNoteOpts;
|
||||
openBulkActionsDialog: {
|
||||
|
||||
@ -165,7 +165,7 @@ export default class TabManager extends Component {
|
||||
const activeNoteContext = this.getActiveContext();
|
||||
this.updateDocumentTitle(activeNoteContext);
|
||||
|
||||
this.triggerEvent("activeNoteChanged", {}); // trigger this even in on popstate event
|
||||
this.triggerEvent("activeNoteChanged", {ntxId:activeNoteContext?.ntxId}); // trigger this even in on popstate event
|
||||
}
|
||||
|
||||
calculateHash(): string {
|
||||
|
||||
@ -32,6 +32,7 @@ import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
|
||||
|
||||
const MOBILE_CSS = `
|
||||
<style>
|
||||
span.keyboard-shortcut,
|
||||
kbd {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import Color, { ColorInstance } from "color";
|
||||
import Debouncer from "../../utils/debouncer";
|
||||
import FNote from "../../entities/fnote";
|
||||
import froca from "../../services/froca";
|
||||
import { isMobile } from "../../services/utils";
|
||||
|
||||
const COLOR_PALETTE = [
|
||||
"#e64d4d", "#e6994d", "#e5e64d", "#99e64d", "#4de64d", "#4de699",
|
||||
@ -62,13 +63,13 @@ export default function NoteColorPicker(props: NoteColorPickerProps) {
|
||||
} else {
|
||||
attributes.removeOwnedLabelByName(note, "color");
|
||||
}
|
||||
|
||||
|
||||
setCurrentColor(color);
|
||||
}
|
||||
}, [note, currentColor]);
|
||||
|
||||
return <div className="note-color-picker">
|
||||
|
||||
|
||||
<ColorCell className="color-cell-reset"
|
||||
tooltip={t("note-color.clear-color")}
|
||||
color={null}
|
||||
@ -81,8 +82,8 @@ export default function NoteColorPicker(props: NoteColorPickerProps) {
|
||||
<path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
|
||||
</svg>
|
||||
</ColorCell>
|
||||
|
||||
|
||||
|
||||
|
||||
{COLOR_PALETTE.map((color) => (
|
||||
<ColorCell key={color}
|
||||
tooltip={t("note-color.set-color")}
|
||||
@ -128,7 +129,6 @@ function CustomColorCell(props: ColorCellProps) {
|
||||
const colorInput = useRef<HTMLInputElement>(null);
|
||||
const colorInputDebouncer = useRef<Debouncer<string | null> | null>(null);
|
||||
const callbackRef = useRef(props.onSelect);
|
||||
const isSafari = useRef(/^((?!chrome|android).)*safari/i.test(navigator.userAgent));
|
||||
|
||||
useEffect(() => {
|
||||
colorInputDebouncer.current = new Debouncer(250, (color) => {
|
||||
@ -160,13 +160,13 @@ function CustomColorCell(props: ColorCellProps) {
|
||||
}, [pickedColor]);
|
||||
|
||||
return <div style={`--foreground: ${getForegroundColor(props.color)};`}
|
||||
onClick={(e) => {
|
||||
// The color picker dropdown will close on Safari if the parent context menu is
|
||||
onClick={isMobile() ? (e) => {
|
||||
// The color picker dropdown will close on some browser if the parent context menu is
|
||||
// dismissed, so stop the click propagation to prevent dismissing the menu.
|
||||
isSafari.current && e.stopPropagation();
|
||||
}}>
|
||||
e.stopPropagation();
|
||||
} : undefined}>
|
||||
<ColorCell {...props}
|
||||
color={pickedColor}
|
||||
color={pickedColor}
|
||||
className={clsx("custom-color-cell", {
|
||||
"custom-color-cell-empty": (pickedColor === null)
|
||||
})}
|
||||
@ -201,4 +201,4 @@ function tryParseColor(colorStr: string): ColorInstance | null {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import clsx from "clsx";
|
||||
import {readCssVar} from "../utils/css-var";
|
||||
import Color, { ColorInstance } from "color";
|
||||
|
||||
const registeredClasses = new Set<string>();
|
||||
const colorsWithHue = new Set<string>();
|
||||
|
||||
// Read the color lightness limits defined in the theme as CSS variables
|
||||
|
||||
@ -26,19 +28,23 @@ function createClassForColor(colorString: string | null) {
|
||||
if (!registeredClasses.has(className)) {
|
||||
const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!,
|
||||
darkThemeColorMinLightness!);
|
||||
const hue = getHue(color);
|
||||
|
||||
$("head").append(`<style>
|
||||
.${className}, span.fancytree-active.${className} {
|
||||
--light-theme-custom-color: ${adjustedColor.lightThemeColor};
|
||||
--dark-theme-custom-color: ${adjustedColor.darkThemeColor};
|
||||
--custom-color-hue: ${getHue(color) ?? 'unset'};
|
||||
--custom-color-hue: ${hue ?? 'unset'};
|
||||
}
|
||||
</style>`);
|
||||
|
||||
registeredClasses.add(className);
|
||||
if (hue) {
|
||||
colorsWithHue.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
return className;
|
||||
return clsx(className, colorsWithHue.has(className) && "with-hue");
|
||||
}
|
||||
|
||||
function parseColor(color: string) {
|
||||
|
||||
@ -4,6 +4,10 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dropdown-menu:not(.static).calendar-dropdown-menu {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.calendar-dropdown-widget {
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
|
||||
@ -25,7 +25,8 @@
|
||||
--bs-body-font-weight: var(--main-font-weight) !important;
|
||||
--bs-body-color: var(--main-text-color) !important;
|
||||
--bs-body-bg: var(--main-background-color) !important;
|
||||
--ck-mention-list-max-height: 500px;
|
||||
--ck-mention-list-max-height: 500px;
|
||||
--tn-modal-max-height: 90vh;
|
||||
}
|
||||
|
||||
body#trilium-app.motion-disabled *,
|
||||
@ -212,6 +213,16 @@ input::placeholder,
|
||||
background-color: var(--modal-backdrop-color) !important;
|
||||
}
|
||||
|
||||
body.mobile .modal .modal-dialog {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.mobile .modal .modal-content {
|
||||
border-radius: var(--bs-modal-border-radius) var(--bs-modal-border-radius) 0 0;
|
||||
}
|
||||
|
||||
.component {
|
||||
contain: size;
|
||||
}
|
||||
@ -581,11 +592,6 @@ button.btn-sm {
|
||||
color: var(--left-pane-text-color);
|
||||
}
|
||||
|
||||
.btn.active:not(.btn-primary) {
|
||||
background-color: var(--button-disabled-background-color) !important;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.ck.ck-block-toolbar-button {
|
||||
transform: translateX(7px);
|
||||
color: var(--muted-text-color);
|
||||
@ -706,11 +712,6 @@ table.promoted-attributes-in-tooltip th {
|
||||
z-index: 32767 !important;
|
||||
}
|
||||
|
||||
.tooltip-trigger {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bs-tooltip-bottom .tooltip-arrow::before {
|
||||
border-bottom-color: var(--main-border-color) !important;
|
||||
}
|
||||
@ -1006,9 +1007,17 @@ div[data-notify="container"] {
|
||||
font-family: var(--monospace-font-family);
|
||||
}
|
||||
|
||||
svg.ck-icon .note-icon {
|
||||
color: var(--main-text-color);
|
||||
font-size: 20px;
|
||||
svg.ck-icon {
|
||||
&.ck-icon_inherit-color {
|
||||
* {
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
&.note-icon {
|
||||
color: var(--main-text-color);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.ck-content {
|
||||
@ -1117,10 +1126,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.note-detail-empty {
|
||||
margin: 50px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 0.5rem 1rem 0.5rem 1rem !important; /* make modal header padding slightly smaller */
|
||||
}
|
||||
@ -1316,7 +1321,7 @@ body.mobile #context-menu-container.mobile-bottom-menu {
|
||||
inset-inline-end: 0 !important;
|
||||
bottom: 0 !important;
|
||||
top: unset !important;
|
||||
max-height: 70vh;
|
||||
max-height: var(--tn-modal-max-height);
|
||||
overflow: auto !important;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
@ -1379,6 +1384,20 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.right-dropdown-widget .right-dropdown-button {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tooltip-trigger {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#launcher-pane.horizontal .right-dropdown-widget {
|
||||
width: 53px;
|
||||
}
|
||||
@ -1554,12 +1573,15 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
@media (max-width: 991px) {
|
||||
body.mobile #launcher-pane .dropdown.global-menu > .dropdown-menu.show,
|
||||
body.mobile #launcher-container .dropdown > .dropdown-menu.show {
|
||||
--dropdown-bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
||||
position: fixed !important;
|
||||
bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size)) !important;
|
||||
bottom: var(--dropdown-bottom) !important;
|
||||
top: unset !important;
|
||||
inset-inline-start: 0 !important;
|
||||
inset-inline-end: 0 !important;
|
||||
transform: unset !important;
|
||||
overflow-y: auto;
|
||||
max-height: calc(var(--tn-modal-max-height) - var(--dropdown-bottom));
|
||||
}
|
||||
|
||||
#mobile-sidebar-container {
|
||||
|
||||
@ -41,6 +41,9 @@
|
||||
--cmd-button-keyboard-shortcut-color: white;
|
||||
--cmd-button-disabled-opacity: 0.5;
|
||||
|
||||
--button-group-active-button-background: #ffffff4e;
|
||||
--button-group-active-button-text-color: white;
|
||||
|
||||
--icon-button-color: currentColor;
|
||||
--icon-button-hover-background: var(--hover-item-background-color);
|
||||
--icon-button-hover-color: var(--hover-item-text-color);
|
||||
@ -98,6 +101,7 @@
|
||||
--menu-item-delimiter-color: #ffffff1c;
|
||||
--menu-item-group-header-color: #ffffff91;
|
||||
--menu-section-background-color: #fefefe08;
|
||||
--menu-submenu-mobile-background-color: rgba(0, 0, 0, 0.15);
|
||||
|
||||
--modal-backdrop-color: #000;
|
||||
--modal-shadow-color: rgba(0, 0, 0, .5);
|
||||
@ -300,7 +304,7 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
|
||||
border-color: var(--muted-text-color) !important;
|
||||
}
|
||||
|
||||
.tinted-quick-edit-dialog {
|
||||
.quick-edit-dialog-wrapper.with-hue {
|
||||
--modal-background-color: hsl(var(--custom-color-hue), 8.8%, 11.2%);
|
||||
--modal-border-color: hsl(var(--custom-color-hue), 9.4%, 25.1%);
|
||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 13.2%, 20.8%);
|
||||
|
||||
@ -41,6 +41,9 @@
|
||||
--cmd-button-keyboard-shortcut-color: black;
|
||||
--cmd-button-disabled-opacity: 0.5;
|
||||
|
||||
--button-group-active-button-background: #00000026;
|
||||
--button-group-active-button-text-color: black;
|
||||
|
||||
--icon-button-color: currentColor;
|
||||
--icon-button-hover-background: var(--hover-item-background-color);
|
||||
--icon-button-hover-color: var(--hover-item-text-color);
|
||||
@ -276,7 +279,7 @@
|
||||
--custom-bg-color: hsl(var(--custom-color-hue), 37%, 89%, 1);
|
||||
}
|
||||
|
||||
.tinted-quick-edit-dialog {
|
||||
.quick-edit-dialog-wrapper.with-hue {
|
||||
--modal-background-color: hsl(var(--custom-color-hue), 56%, 96%);
|
||||
--modal-border-color: hsl(var(--custom-color-hue), 33%, 41%);
|
||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%);
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
|
||||
--menu-padding-size: 8px;
|
||||
--menu-item-icon-vert-offset: -2px;
|
||||
--menu-submenu-mobile-background-color: rgba(255, 255, 255, 0.15);
|
||||
|
||||
--more-accented-background-color: var(--card-background-hover-color);
|
||||
|
||||
@ -99,6 +100,14 @@
|
||||
--tree-item-dark-theme-min-color-lightness: 65;
|
||||
}
|
||||
|
||||
body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.selectable-text {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
body.backdrop-effects-disabled {
|
||||
/* Backdrop effects are disabled, replace the menu background color with the
|
||||
* no-backdrop fallback color */
|
||||
@ -308,6 +317,19 @@ body.mobile #context-menu-cover {
|
||||
&.show {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
&.global-menu-cover {
|
||||
bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
||||
|
||||
@media (min-width: 992px) {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu.mobile-bottom-menu,
|
||||
body.mobile .dropdown.global-menu .dropdown-menu {
|
||||
border-radius: var(--dropdown-border-radius) var(--dropdown-border-radius) 0 0;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-menu {
|
||||
@ -316,9 +338,8 @@ body.mobile .dropdown-menu {
|
||||
--hover-item-background-color: var(--card-background-color);
|
||||
font-size: 1em !important;
|
||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||
border-radius: var(--dropdown-border-radius) var(--dropdown-border-radius) 0 0;
|
||||
position: relative;
|
||||
|
||||
|
||||
.dropdown-toggle::after {
|
||||
top: 0.5em;
|
||||
right: var(--dropdown-menu-padding-horizontal);
|
||||
@ -334,8 +355,8 @@ body.mobile .dropdown-menu {
|
||||
margin-bottom: 0;
|
||||
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal) !important;
|
||||
background: var(--card-background-color);
|
||||
border-bottom: 1px solid var(--main-border-color) !important;
|
||||
border-radius: 0;
|
||||
border-bottom: 1px solid var(--menu-item-delimiter-color) !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.dropdown-item:first-of-type,
|
||||
@ -367,19 +388,38 @@ body.mobile .dropdown-menu {
|
||||
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal);
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
--menu-background-color: --menu-submenu-mobile-background-color;
|
||||
--bs-dropdown-divider-margin-y: 0.25rem;
|
||||
border-radius: 0;
|
||||
max-height: 0;
|
||||
transition: max-height 100ms ease-in;
|
||||
display: block !important;
|
||||
|
||||
&.show {
|
||||
max-height: 1000px;
|
||||
padding: 0.5rem 0.75rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.submenu-open {
|
||||
.dropdown-toggle {
|
||||
padding-bottom: var(--dropdown-menu-padding-vertical);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
--menu-background-color: rgba(0, 0, 0, 0.15);
|
||||
border-radius: 0;
|
||||
.dropdown-custom-item:has(.note-color-picker) {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
.note-color-picker {
|
||||
padding: 0;
|
||||
width: fit-content;
|
||||
|
||||
.color-cell {
|
||||
--color-picker-cell-size: 26px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
.modal .modal-header .btn-close,
|
||||
.modal .modal-header .help-button,
|
||||
.modal .modal-header .custom-title-bar-button,
|
||||
#toast-container .toast .toast-header .btn-close {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -55,15 +56,17 @@
|
||||
font-family: boxicons;
|
||||
}
|
||||
|
||||
.modal .modal-header .help-button {
|
||||
.modal .modal-header .help-button,
|
||||
.modal .modal-header .custom-title-bar-button {
|
||||
margin-inline-end: 0;
|
||||
font-size: calc(var(--modal-control-button-size) * .75);
|
||||
font-size: calc(var(--modal-control-button-size) * .70);
|
||||
font-family: unset;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.modal .modal-header .btn-close:hover,
|
||||
.modal .modal-header .help-button:hover,
|
||||
.modal .modal-header .custom-title-bar-button:hover,
|
||||
#toast-container .toast .toast-header .btn-close:hover {
|
||||
background: var(--modal-control-button-hover-background);
|
||||
color: var(--modal-control-button-hover-color);
|
||||
@ -71,6 +74,7 @@
|
||||
|
||||
.modal .modal-header .btn-close:active,
|
||||
.modal .modal-header .help-button:active,
|
||||
.modal .modal-header .custom-title-bar-button:active,
|
||||
#toast-container .toast .toast-header .btn-close:active {
|
||||
transform: scale(.85);
|
||||
}
|
||||
|
||||
@ -146,6 +146,14 @@ button.btn.btn-success kbd {
|
||||
outline: 2px solid var(--input-focus-outline-color);
|
||||
}
|
||||
|
||||
/* Button groups */
|
||||
|
||||
/* Active button */
|
||||
:root .btn-group button.btn.active {
|
||||
background-color: var(--button-group-active-button-background);
|
||||
color: var(--button-group-active-button-text-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input boxes
|
||||
*/
|
||||
|
||||
@ -124,12 +124,8 @@
|
||||
|
||||
/* The container */
|
||||
|
||||
.note-split.empty-note {
|
||||
--max-content-width: 70%;
|
||||
}
|
||||
|
||||
.note-split.empty-note div.note-detail {
|
||||
margin: 50px auto;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* The search results list */
|
||||
|
||||
@ -345,7 +345,7 @@ body[dir=ltr] #launcher-container {
|
||||
*/
|
||||
|
||||
.calendar-dropdown-widget {
|
||||
padding: 12px;
|
||||
padding: 18px;
|
||||
color: var(--calendar-color);
|
||||
user-select: none;
|
||||
}
|
||||
@ -1448,6 +1448,14 @@ div.promoted-attribute-cell .multiplicity:has(span) span {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div.promoted-attribute-cell.promoted-attribute-label-color {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
div.promoted-attribute-cell.promoted-attribute-label-color .input-group {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* Floating buttons
|
||||
*/
|
||||
|
||||
@ -1557,7 +1557,8 @@
|
||||
"refresh-saved-search-results": "刷新保存的搜索结果",
|
||||
"create-child-note": "创建子笔记",
|
||||
"unhoist": "取消聚焦",
|
||||
"toggle-sidebar": "切换侧边栏"
|
||||
"toggle-sidebar": "切换侧边栏",
|
||||
"dropping-not-allowed": "不允许移动笔记到此处。"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "保持此窗口置顶"
|
||||
@ -1660,7 +1661,8 @@
|
||||
"duplicate-launcher": "复制启动器 <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "自动检测"
|
||||
"auto-detect-language": "自动检测",
|
||||
"keeps-crashing": "编辑组件时持续崩溃。请尝试重启 Trilium。如果问题仍然存在,请考虑提交错误报告。"
|
||||
},
|
||||
"highlighting": {
|
||||
"title": "代码块",
|
||||
@ -2096,7 +2098,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "当前正在查看一个只读笔记。",
|
||||
"auto-read-only-note": "这条笔记以只读模式显示便于快速加载。",
|
||||
"auto-read-only-learn-more": "了解更多",
|
||||
"edit-note": "编辑笔记"
|
||||
},
|
||||
"note-color": {
|
||||
|
||||
@ -70,7 +70,7 @@
|
||||
"cancel": "Zrušit",
|
||||
"ok": "OK",
|
||||
"confirmation": "Potvrzení",
|
||||
"are_you_sure_remove_note": "Opravdu chcete odstranit poznámku „{{title}}“ z mapy vztahů?",
|
||||
"are_you_sure_remove_note": "Opravdu chcete odstranit poznámku „{{title}}“ z mapy vztahů? ",
|
||||
"if_you_dont_check": "Pokud tuto možnost nezaškrtnete, poznámka bude odstraněna pouze z mapy vztahů.",
|
||||
"also_delete_note": "Odstraňte také poznámku"
|
||||
},
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Benutzerdefiniertes Skript konnte nicht geladen werden",
|
||||
"message": "Skript von der Notiz mit der ID \"{{id}}\", und dem Titel \"{{title}}\" konnte nicht ausgeführt werden wegen:\n\n{{message}}"
|
||||
"message": "Skript aus der Notiz \"{{title}}\" mit der ID \"{{id}}\", konnte nicht ausgeführt werden wegen:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
@ -41,7 +41,8 @@
|
||||
"save": "Speichern",
|
||||
"branch_prefix_saved": "Zweigpräfix wurde gespeichert.",
|
||||
"branch_prefix_saved_multiple": "Der Zweigpräfix wurde für {{count}} Zweige gespeichert.",
|
||||
"edit_branch_prefix_multiple": "Präfix für {{count}} Zweige bearbeiten"
|
||||
"edit_branch_prefix_multiple": "Branch-Präfix für {{count}} Zweige bearbeiten",
|
||||
"affected_branches": "Betroffene Zweige ({{count}}):"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Massenaktionen",
|
||||
@ -770,7 +771,10 @@
|
||||
"board": "Tafel",
|
||||
"include_archived_notes": "Zeige archivierte Notizen",
|
||||
"presentation": "Präsentation",
|
||||
"expand_all_levels": "Alle Ebenen erweitern"
|
||||
"expand_all_levels": "Alle Ebenen erweitern",
|
||||
"expand_tooltip": "Erweitert die direkten Unterelemente dieser Sammlung (eine Ebene tiefer). Für weitere Optionen auf den Pfeil rechts klicken.",
|
||||
"expand_first_level": "Direkte Unterelemente erweitern",
|
||||
"expand_nth_level": "{{depth}} Ebenen erweitern"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
|
||||
@ -1517,7 +1521,8 @@
|
||||
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
|
||||
"create-child-note": "Unternotiz anlegen",
|
||||
"unhoist": "Fokus verlassen",
|
||||
"toggle-sidebar": "Seitenleiste ein-/ausblenden"
|
||||
"toggle-sidebar": "Seitenleiste ein-/ausblenden",
|
||||
"dropping-not-allowed": "Ablegen von Notizen an dieser Stelle ist nicht zulässig."
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Dieses Fenster immer oben halten"
|
||||
@ -1620,7 +1625,8 @@
|
||||
"duplicate-launcher": "Launcher duplizieren <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "Automatisch erkannt"
|
||||
"auto-detect-language": "Automatisch erkannt",
|
||||
"keeps-crashing": "Die Bearbeitungskomponente stürzt immer wieder ab. Bitte starten Sie Trilium neu. Wenn das Problem weiterhin besteht, erstellen Sie einen Fehlerbericht."
|
||||
},
|
||||
"highlighting": {
|
||||
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
|
||||
@ -2089,9 +2095,8 @@
|
||||
"slide-overview": "Übersicht der Folien ein-/ausblenden"
|
||||
},
|
||||
"read-only-info": {
|
||||
"read-only-note": "Aktuell wird eine Notiz nur im Lese-Modus angezeigt.",
|
||||
"read-only-note": "Aktuelle Notiz wird im Lese-Modus angezeigt.",
|
||||
"auto-read-only-note": "Diese Notiz wird im Nur-Lesen-Modus angezeigt, um ein schnelleres Laden zu ermöglichen.",
|
||||
"auto-read-only-learn-more": "Mehr erfahren",
|
||||
"edit-note": "Notiz bearbeiten"
|
||||
},
|
||||
"calendar_view": {
|
||||
|
||||
@ -112,6 +112,7 @@
|
||||
},
|
||||
"help": {
|
||||
"title": "Cheatsheet",
|
||||
"editShortcuts": "Edit keyboard shortcuts",
|
||||
"noteNavigation": "Note navigation",
|
||||
"goUpDown": "go up/down in the list of notes",
|
||||
"collapseExpand": "collapse/expand node",
|
||||
@ -1647,7 +1648,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "Currently viewing a read-only note.",
|
||||
"auto-read-only-note": "This note is shown in a read-only mode for faster loading.",
|
||||
"auto-read-only-learn-more": "Learn more",
|
||||
"edit-note": "Edit note"
|
||||
},
|
||||
"note_types": {
|
||||
|
||||
@ -2096,7 +2096,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "Actualmente, está viendo una nota de solo lectura.",
|
||||
"auto-read-only-note": "Esta nota se muestra en modo de solo lectura para una carga más rápida.",
|
||||
"auto-read-only-learn-more": "Para saber más",
|
||||
"edit-note": "Editar nota"
|
||||
},
|
||||
"calendar_view": {
|
||||
|
||||
@ -2092,7 +2092,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "Stai visualizzando una nota di sola lettura.",
|
||||
"auto-read-only-note": "Questa nota viene visualizzata in modalità di sola lettura per un caricamento più rapido.",
|
||||
"auto-read-only-learn-more": "Per saperne di più",
|
||||
"edit-note": "Modifica nota"
|
||||
},
|
||||
"calendar_view": {
|
||||
|
||||
@ -1212,7 +1212,8 @@
|
||||
"unhoist": "ホイスト解除",
|
||||
"saved-search-note-refreshed": "保存した検索ノートが更新されました。",
|
||||
"refresh-saved-search-results": "保存した検索結果を更新",
|
||||
"toggle-sidebar": "サイドバーを切り替え"
|
||||
"toggle-sidebar": "サイドバーを切り替え",
|
||||
"dropping-not-allowed": "この場所にノートをドロップすることはできません。"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "一括操作",
|
||||
@ -1266,7 +1267,8 @@
|
||||
"reset_launcher_confirm": "本当に「{{title}}」をリセットしますか? このノート(およびその子ノート)のすべてのデータと設定が失われ、ランチャーは元の場所に戻ります。"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "自動検出"
|
||||
"auto-detect-language": "自動検出",
|
||||
"keeps-crashing": "編集コンポーネントがクラッシュし続けます。Trilium を再起動してください。問題が解決しない場合は、バグレポートの作成をご検討ください。"
|
||||
},
|
||||
"highlighting": {
|
||||
"title": "コードブロック",
|
||||
@ -2096,7 +2098,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "現在、読み取り専用のノートを表示しています。",
|
||||
"auto-read-only-note": "このノートは読み込みを高速化するために読み取り専用モードで表示されています。",
|
||||
"auto-read-only-learn-more": "さらに詳しく",
|
||||
"edit-note": "ノートを編集"
|
||||
},
|
||||
"note-color": {
|
||||
|
||||
@ -39,7 +39,9 @@
|
||||
"edit_branch_prefix": "브랜치 접두사 편집",
|
||||
"help_on_tree_prefix": "트리 접두사에 대한 도움말",
|
||||
"prefix": "접두사: ",
|
||||
"branch_prefix_saved": "브랜치 접두사가 저장되었습니다."
|
||||
"branch_prefix_saved": "브랜치 접두사가 저장되었습니다.",
|
||||
"edit_branch_prefix_multiple": "{{count}}개의 지점 접두사 편집",
|
||||
"branch_prefix_saved_multiple": "{{count}}개의 지점에 대해 지점 접두사가 저장되었습니다."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "대량 작업",
|
||||
|
||||
@ -2097,7 +2097,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "Vizualizați o notiță în modul doar în citire.",
|
||||
"auto-read-only-note": "Această notiță este afișată în modul doar în citire din motive de performanță.",
|
||||
"auto-read-only-learn-more": "Mai multe detalii",
|
||||
"edit-note": "Editează notița"
|
||||
},
|
||||
"calendar_view": {
|
||||
|
||||
@ -1516,7 +1516,8 @@
|
||||
"refresh-saved-search-results": "重新整理儲存的搜尋結果",
|
||||
"create-child-note": "建立子筆記",
|
||||
"unhoist": "取消聚焦",
|
||||
"toggle-sidebar": "切換側邊欄"
|
||||
"toggle-sidebar": "切換側邊欄",
|
||||
"dropping-not-allowed": "不允許移動筆記至此處。"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "保持此視窗置頂"
|
||||
@ -1619,7 +1620,8 @@
|
||||
"duplicate-launcher": "複製啟動器 <kbd data-command=\"duplicateSubtree\">"
|
||||
},
|
||||
"editable-text": {
|
||||
"auto-detect-language": "自動檢測"
|
||||
"auto-detect-language": "自動檢測",
|
||||
"keeps-crashing": "編輯元件持續發生崩潰。請嘗試重新啟動 Trilium。若問題仍存在,請考慮提交錯誤報告。"
|
||||
},
|
||||
"highlighting": {
|
||||
"description": "控制文字筆記程式碼區塊中的語法高亮,程式碼筆記不會受到影響。",
|
||||
@ -2096,7 +2098,6 @@
|
||||
"read-only-info": {
|
||||
"read-only-note": "目前正在檢視唯讀筆記。",
|
||||
"auto-read-only-note": "此筆記以唯讀模式顯示以加快載入速度。",
|
||||
"auto-read-only-learn-more": "了解更多",
|
||||
"edit-note": "編輯筆記"
|
||||
},
|
||||
"note-color": {
|
||||
|
||||
@ -28,8 +28,9 @@ export default function NoteDetail() {
|
||||
const { note, type, mime, noteContext, parentComponent } = useNoteInfo();
|
||||
const { ntxId, viewScope } = noteContext ?? {};
|
||||
const isFullHeight = checkFullHeight(noteContext, type);
|
||||
const noteTypesToRender = useRef<{ [ key in ExtendedNoteType ]?: (props: TypeWidgetProps) => VNode }>({});
|
||||
const [ noteTypesToRender, setNoteTypesToRender ] = useState<{ [ key in ExtendedNoteType ]?: (props: TypeWidgetProps) => VNode }>({});
|
||||
const [ activeNoteType, setActiveNoteType ] = useState<ExtendedNoteType>();
|
||||
const widgetRequestId = useRef(0);
|
||||
|
||||
const props: TypeWidgetProps = {
|
||||
note: note!,
|
||||
@ -38,19 +39,28 @@ export default function NoteDetail() {
|
||||
parentComponent,
|
||||
noteContext
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!type) return;
|
||||
const requestId = ++widgetRequestId.current;
|
||||
|
||||
if (!noteTypesToRender.current[type]) {
|
||||
if (!noteTypesToRender[type]) {
|
||||
getCorrespondingWidget(type).then((el) => {
|
||||
if (!el) return;
|
||||
noteTypesToRender.current[type] = el;
|
||||
|
||||
// Ignore stale requests
|
||||
if (requestId !== widgetRequestId.current) return;
|
||||
|
||||
setNoteTypesToRender(prev => ({
|
||||
...prev,
|
||||
[type]: el
|
||||
}));
|
||||
setActiveNoteType(type);
|
||||
});
|
||||
} else {
|
||||
setActiveNoteType(type);
|
||||
}
|
||||
}, [ note, viewScope, type ]);
|
||||
}, [ note, viewScope, type, noteTypesToRender ]);
|
||||
|
||||
// Detect note type changes.
|
||||
useTriliumEvent("entitiesReloaded", async ({ loadResults }) => {
|
||||
@ -95,9 +105,11 @@ export default function NoteDetail() {
|
||||
});
|
||||
|
||||
// Automatically focus the editor.
|
||||
useTriliumEvent("activeNoteChanged", () => {
|
||||
// Restore focus to the editor when switching tabs, but only if the note tree is not already focused.
|
||||
if (!document.activeElement?.classList.contains("fancytree-title")) {
|
||||
useTriliumEvent("activeNoteChanged", ({ ntxId: eventNtxId }) => {
|
||||
if (eventNtxId != ntxId) return;
|
||||
// Restore focus to the editor when switching tabs,
|
||||
// but only if the note tree and the note panel (e.g., note title or note detail) are not focused.
|
||||
if (!document.activeElement?.classList.contains("fancytree-title") && !parentComponent.$widget[0].closest(".note-split")?.contains(document.activeElement)) {
|
||||
parentComponent.triggerCommand("focusOnDetail", { ntxId });
|
||||
}
|
||||
});
|
||||
@ -192,7 +204,7 @@ export default function NoteDetail() {
|
||||
ref={containerRef}
|
||||
class={`note-detail ${isFullHeight ? "full-height" : ""}`}
|
||||
>
|
||||
{Object.entries(noteTypesToRender.current).map(([ itemType, Element ]) => {
|
||||
{Object.entries(noteTypesToRender).map(([ itemType, Element ]) => {
|
||||
return <NoteDetailWrapper
|
||||
Element={Element}
|
||||
key={itemType}
|
||||
|
||||
@ -3,34 +3,33 @@ import { t } from "../services/i18n";
|
||||
import { useIsNoteReadOnly, useNoteContext, useTriliumEvent } from "./react/hooks"
|
||||
import Button from "./react/Button";
|
||||
import InfoBar from "./react/InfoBar";
|
||||
import HelpButton from "./react/HelpButton";
|
||||
|
||||
export default function ReadOnlyNoteInfoBar(props: {}) {
|
||||
const {note, noteContext} = useNoteContext();
|
||||
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
|
||||
const { note, noteContext } = useNoteContext();
|
||||
const { isReadOnly, enableEditing } = useIsNoteReadOnly(note, noteContext);
|
||||
const isExplicitReadOnly = note?.isLabelTruthy("readOnly");
|
||||
|
||||
return <InfoBar className="read-only-note-info-bar-widget"
|
||||
type={(isExplicitReadOnly ? "subtle" : "prominent")}
|
||||
style={{display: (!isReadOnly) ? "none" : undefined}}>
|
||||
|
||||
<div class="read-only-note-info-bar-widget-content">
|
||||
{(isExplicitReadOnly) ? (
|
||||
<div>{t("read-only-info.read-only-note")}</div>
|
||||
) : (
|
||||
<div>
|
||||
{t("read-only-info.auto-read-only-note")}
|
||||
|
||||
<a class="tn-link"
|
||||
href="https://docs.triliumnotes.org/user-guide/concepts/notes/read-only-notes#automatic-read-only-mode">
|
||||
|
||||
{t("read-only-info.auto-read-only-learn-more")}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button text={t("read-only-info.edit-note")}
|
||||
icon="bx-pencil" onClick={() => enableEditing()} />
|
||||
return (
|
||||
<InfoBar
|
||||
className="read-only-note-info-bar-widget"
|
||||
type={(isExplicitReadOnly ? "subtle" : "prominent")}
|
||||
style={{display: (!isReadOnly) ? "none" : undefined}}
|
||||
>
|
||||
<div class="read-only-note-info-bar-widget-content">
|
||||
{(isExplicitReadOnly) ? (
|
||||
<div>{t("read-only-info.read-only-note")}</div>
|
||||
) : (
|
||||
<div>
|
||||
{t("read-only-info.auto-read-only-note")}
|
||||
{" "}
|
||||
<HelpButton helpPage="CoFPLs3dRlXc" />
|
||||
</div>
|
||||
</InfoBar>
|
||||
)}
|
||||
|
||||
}
|
||||
<Button text={t("read-only-info.edit-note")}
|
||||
icon="bx-pencil" onClick={() => enableEditing()} />
|
||||
</div>
|
||||
</InfoBar>
|
||||
);
|
||||
}
|
||||
|
||||
@ -110,7 +110,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
|
||||
private weekNotes: string[] = [];
|
||||
|
||||
constructor(title: string = "", icon: string = "") {
|
||||
super(title, icon, DROPDOWN_TPL);
|
||||
super(title, icon, DROPDOWN_TPL, "calendar-dropdown-menu");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
@ -211,8 +211,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget {
|
||||
const $target = $(e.target);
|
||||
|
||||
// Keep dropdown open when clicking on month select button or year selector area
|
||||
if ($target.closest('.btn.dropdown-toggle.select-button').length ||
|
||||
$target.closest('.calendar-year-selector').length) {
|
||||
if ($target.closest('.btn.dropdown-toggle.select-button').length) {
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
|
||||
const isVerticalLayout = !isHorizontalLayout;
|
||||
const parentComponent = useContext(ParentComponent);
|
||||
const { isUpdateAvailable, latestVersion } = useTriliumUpdateStatus();
|
||||
const isMobileLocal = isMobile();
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
@ -38,6 +39,8 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
|
||||
</div>}
|
||||
</>}
|
||||
noDropdownListStyle
|
||||
onShown={isMobileLocal ? () => document.getElementById("context-menu-cover")?.classList.add("show", "global-menu-cover") : undefined}
|
||||
onHidden={isMobileLocal ? () => document.getElementById("context-menu-cover")?.classList.remove("show", "global-menu-cover") : undefined}
|
||||
>
|
||||
|
||||
<MenuItem command="openNewWindow" icon="bx bx-window-open" text={t("global_menu.open_new_window")} />
|
||||
|
||||
@ -7,9 +7,9 @@ const TPL = /*html*/`
|
||||
<div class="dropdown right-dropdown-widget">
|
||||
<button type="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false"
|
||||
class="bx right-dropdown-button launcher-button"></button>
|
||||
|
||||
<div class="tooltip-trigger"></div>
|
||||
class="bx right-dropdown-button launcher-button">
|
||||
<div class="tooltip-trigger"></div>
|
||||
</button>
|
||||
|
||||
<div class="dropdown-menu"></div>
|
||||
</div>
|
||||
@ -24,14 +24,16 @@ export default class RightDropdownButtonWidget extends BasicWidget {
|
||||
protected dropdown!: Dropdown;
|
||||
protected $tooltip!: JQuery<HTMLElement>;
|
||||
protected tooltip!: Tooltip;
|
||||
private dropdownClass?: string;
|
||||
public $dropdownContent!: JQuery<HTMLElement>;
|
||||
|
||||
constructor(title: string, iconClass: string, dropdownTpl: string) {
|
||||
constructor(title: string, iconClass: string, dropdownTpl: string, dropdownClass?: string) {
|
||||
super();
|
||||
|
||||
this.iconClass = iconClass;
|
||||
this.title = title;
|
||||
this.dropdownTpl = dropdownTpl;
|
||||
this.dropdownClass = dropdownClass;
|
||||
|
||||
this.settings = {
|
||||
titlePlacement: "right"
|
||||
@ -41,15 +43,17 @@ export default class RightDropdownButtonWidget extends BasicWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$dropdownMenu = this.$widget.find(".dropdown-menu");
|
||||
if (this.dropdownClass) {
|
||||
this.$dropdownMenu.addClass(this.dropdownClass);
|
||||
}
|
||||
this.dropdown = Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']")[0], {
|
||||
popperConfig: {
|
||||
placement: this.settings.titlePlacement,
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.attr("title", this.title);
|
||||
this.tooltip = Tooltip.getOrCreateInstance(this.$widget[0], {
|
||||
trigger: "hover",
|
||||
this.$tooltip = this.$widget.find(".tooltip-trigger").attr("title", this.title);
|
||||
this.tooltip = new Tooltip(this.$tooltip[0], {
|
||||
placement: handleRightToLeftPlacement(this.settings.titlePlacement),
|
||||
fallbackPlacements: [ handleRightToLeftPlacement(this.settings.titlePlacement) ]
|
||||
});
|
||||
@ -57,7 +61,9 @@ export default class RightDropdownButtonWidget extends BasicWidget {
|
||||
this.$widget
|
||||
.find(".right-dropdown-button")
|
||||
.addClass(this.iconClass)
|
||||
.on("click", () => this.tooltip.hide());
|
||||
.on("click", () => this.tooltip.hide())
|
||||
.on("mouseenter", () => this.tooltip.show())
|
||||
.on("mouseleave", () => this.tooltip.hide());
|
||||
|
||||
this.$widget.on("show.bs.dropdown", async () => {
|
||||
await this.dropdownShown();
|
||||
|
||||
@ -204,8 +204,19 @@ function AddNewColumn({ api, isInRelationMode }: { api: BoardApi, isInRelationMo
|
||||
setIsCreatingNewColumn(true);
|
||||
}, []);
|
||||
|
||||
const keydownCallback = useCallback((e: KeyboardEvent) => {
|
||||
if (e.key === "Enter") {
|
||||
setIsCreatingNewColumn(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={`board-add-column ${isCreatingNewColumn ? "editing" : ""}`} onClick={addColumnCallback}>
|
||||
<div
|
||||
className={`board-add-column ${isCreatingNewColumn ? "editing" : ""}`}
|
||||
onClick={addColumnCallback}
|
||||
onKeyDown={keydownCallback}
|
||||
tabIndex={300}
|
||||
>
|
||||
{!isCreatingNewColumn
|
||||
? <>
|
||||
<Icon icon="bx bx-plus" />{" "}
|
||||
|
||||
@ -29,7 +29,11 @@ export default class LeftPaneContainer extends FlexContainer<Component> {
|
||||
if (visible) {
|
||||
this.triggerEvent("focusTree", {});
|
||||
} else {
|
||||
this.triggerEvent("focusOnDetail", { ntxId: appContext.tabManager.getActiveContext()?.ntxId });
|
||||
const ntxId = appContext.tabManager.getActiveContext()?.ntxId;
|
||||
const noteContainer = document.querySelector(`.note-split[data-ntx-id="${ntxId}"]`);
|
||||
if (!noteContainer?.contains(document.activeElement)) {
|
||||
this.triggerEvent("focusOnDetail", { ntxId });
|
||||
}
|
||||
}
|
||||
|
||||
options.save("leftPaneVisible", this.currentLeftPaneVisible.toString());
|
||||
|
||||
@ -1,12 +1,8 @@
|
||||
import FlexContainer from "./flex_container.js";
|
||||
import appContext, { type CommandData, type CommandListenerData, type EventData, type EventNames, type NoteSwitchedContext } from "../../components/app_context.js";
|
||||
import type BasicWidget from "../basic_widget.js";
|
||||
import type NoteContext from "../../components/note_context.js";
|
||||
import Component from "../../components/component.js";
|
||||
import splitService from "../../services/resizer.js";
|
||||
interface NoteContextEvent {
|
||||
noteContext: NoteContext;
|
||||
}
|
||||
|
||||
interface SplitNoteWidget extends BasicWidget {
|
||||
hasBeenAlreadyShown?: boolean;
|
||||
|
||||
@ -5,14 +5,24 @@ body.popup-editor-open .ck-clipboard-drop-target-line { z-index: 1000; }
|
||||
|
||||
body.desktop .modal.popup-editor-dialog .modal-dialog {
|
||||
max-width: 75vw;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .modal-dialog {
|
||||
border-bottom-left-radius: var(--bs-modal-border-radius);
|
||||
border-bottom-right-radius: var(--bs-modal-border-radius);
|
||||
}
|
||||
|
||||
body.desktop .modal.popup-editor-dialog .modal-dialog {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.mobile .modal.popup-editor-dialog .modal-dialog {
|
||||
max-width: min(var(--preferred-max-content-width), 95vw);
|
||||
max-height: var(--tn-modal-max-height);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .modal-content {
|
||||
transition: background-color 250ms ease-in;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .modal-header .modal-title {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
@ -23,8 +33,8 @@ body.desktop .modal.popup-editor-dialog .modal-dialog {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .modal-header .title-row > * {
|
||||
margin: 5px;
|
||||
.modal.popup-editor-dialog .modal-header .note-title-widget {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .modal-body {
|
||||
@ -52,13 +62,23 @@ body.desktop .modal.popup-editor-dialog .modal-dialog {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .classic-toolbar-outer-container.visible {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog div.promoted-attributes-container {
|
||||
margin-block: 0;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .classic-toolbar-widget {
|
||||
position: sticky;
|
||||
margin-inline: 8px;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
background: var(--modal-background-color);
|
||||
z-index: 998;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.modal.popup-editor-dialog .note-detail.full-height {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useContext, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import Modal from "../react/Modal";
|
||||
import "./PopupEditor.css";
|
||||
import { useNoteContext, useTriliumEvent } from "../react/hooks";
|
||||
import { useNoteContext, useNoteLabel, useTriliumEvent } from "../react/hooks";
|
||||
import NoteTitleWidget from "../note_title";
|
||||
import NoteIcon from "../note_icon";
|
||||
import NoteContext from "../../components/note_context";
|
||||
@ -18,6 +18,7 @@ import utils from "../../services/utils";
|
||||
import tree from "../../services/tree";
|
||||
import froca from "../../services/froca";
|
||||
import ReadOnlyNoteInfoBar from "../ReadOnlyNoteInfoBar";
|
||||
import MobileEditorToolbar from "../type_widgets/text/mobile_editor_toolbar";
|
||||
|
||||
export default function PopupEditor() {
|
||||
const [ shown, setShown ] = useState(false);
|
||||
@ -59,6 +60,11 @@ export default function PopupEditor() {
|
||||
<DialogWrapper>
|
||||
<Modal
|
||||
title={<TitleRow />}
|
||||
customTitleBarButtons={[{
|
||||
iconClassName: "bx-expand-alt",
|
||||
title: "Switch to full editor",
|
||||
onClick: () => {/* TO DO */}
|
||||
}]}
|
||||
className="popup-editor-dialog"
|
||||
size="lg"
|
||||
show={shown}
|
||||
@ -67,10 +73,15 @@ export default function PopupEditor() {
|
||||
}}
|
||||
onHidden={() => setShown(false)}
|
||||
keepInDom // needed for faster loading
|
||||
noFocus // automatic focus breaks block popup
|
||||
>
|
||||
<ReadOnlyNoteInfoBar />
|
||||
<PromotedAttributes />
|
||||
<StandaloneRibbonAdapter component={FormattingToolbar} />
|
||||
|
||||
{isMobile
|
||||
? <MobileEditorToolbar inPopupEditor />
|
||||
: <StandaloneRibbonAdapter component={FormattingToolbar} />}
|
||||
|
||||
<FloatingButtons items={items} />
|
||||
<NoteDetail />
|
||||
<NoteList media="screen" displayOnlyCollections />
|
||||
@ -83,17 +94,10 @@ export default function PopupEditor() {
|
||||
export function DialogWrapper({ children }: { children: ComponentChildren }) {
|
||||
const { note } = useNoteContext();
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
const [ hasTint, setHasTint ] = useState(false);
|
||||
|
||||
// Apply the tinted-dialog class only if the custom color CSS class specifies a hue
|
||||
useEffect(() => {
|
||||
if (!wrapperRef.current) return;
|
||||
const customHue = getComputedStyle(wrapperRef.current).getPropertyValue("--custom-color-hue");
|
||||
setHasTint(!!customHue);
|
||||
}, [ note ]);
|
||||
useNoteLabel(note, "color"); // to update color class
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef} class={`quick-edit-dialog-wrapper ${note?.getColorClass() ?? ""} ${hasTint ? "tinted-quick-edit-dialog" : ""}`}>
|
||||
<div ref={wrapperRef} class={`quick-edit-dialog-wrapper ${note?.getColorClass() ?? ""}`}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -31,29 +31,29 @@ export default function AboutDialog() {
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("about.homepage")}</th>
|
||||
<td><a className="tn-link external" href="https://github.com/TriliumNext/Trilium" style={forceWordBreak}>https://github.com/TriliumNext/Trilium</a></td>
|
||||
<td className="selectable-text"><a className="tn-link external" href="https://github.com/TriliumNext/Trilium" style={forceWordBreak}>https://github.com/TriliumNext/Trilium</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.app_version")}</th>
|
||||
<td className="app-version">{appInfo?.appVersion}</td>
|
||||
<td className="app-version selectable-text">{appInfo?.appVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.db_version")}</th>
|
||||
<td className="db-version">{appInfo?.dbVersion}</td>
|
||||
<td className="db-version selectable-text">{appInfo?.dbVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.sync_version")}</th>
|
||||
<td className="sync-version">{appInfo?.syncVersion}</td>
|
||||
<td className="sync-version selectable-text">{appInfo?.syncVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.build_date")}</th>
|
||||
<td className="build-date">
|
||||
<td className="build-date selectable-text">
|
||||
{appInfo?.buildDate ? formatDateTime(appInfo.buildDate) : ""}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.build_revision")}</th>
|
||||
<td>
|
||||
<td className="selectable-text">
|
||||
{appInfo?.buildRevision && <a className="tn-link build-revision external" href={`https://github.com/TriliumNext/Trilium/commit/${appInfo.buildRevision}`} target="_blank" style={forceWordBreak}>{appInfo.buildRevision}</a>}
|
||||
</td>
|
||||
</tr>
|
||||
@ -76,8 +76,8 @@ function DirectoryLink({ directory, style }: { directory: string, style?: CSSPro
|
||||
openService.openDirectory(directory);
|
||||
};
|
||||
|
||||
return <a className="tn-link" href="#" onClick={onClick} style={style}>{directory}</a>
|
||||
return <a className="tn-link selectable-text" href="#" onClick={onClick} style={style}>{directory}</a>
|
||||
} else {
|
||||
return <span style={style}>{directory}</span>;
|
||||
return <span className="selectable-text" style={style}>{directory}</span>;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Modal from "../react/Modal.jsx";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import { ComponentChildren } from "preact";
|
||||
import { CommandNames } from "../../components/app_context.js";
|
||||
import appContext, { CommandNames } from "../../components/app_context.js";
|
||||
import RawHtml from "../react/RawHtml.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import keyboard_actions from "../../services/keyboard_actions.js";
|
||||
@ -14,6 +14,7 @@ export default function HelpDialog() {
|
||||
return (
|
||||
<Modal
|
||||
title={t("help.title")} className="help-dialog use-tn-links" minWidth="90%" size="lg" scrollable
|
||||
customTitleBarButtons={[{title: t("help.editShortcuts"), iconClassName: "bxs-pencil", onClick: editShortcuts}]}
|
||||
onHidden={() => setShown(false)}
|
||||
show={shown}
|
||||
>
|
||||
@ -160,3 +161,7 @@ function Card({ title, children }: { title: string, children: ComponentChildren
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function editShortcuts() {
|
||||
appContext.tabManager.openContextWithNote("_optionsShortcuts", { activate: true });
|
||||
}
|
||||
@ -208,7 +208,7 @@ function RevisionPreview({noteContent, revisionItem, showDiff, setShown, onRevis
|
||||
}
|
||||
</div>)}
|
||||
</div>
|
||||
<div className="revision-content use-tn-links" style={{ overflow: "auto", wordBreak: "break-word" }}>
|
||||
<div className="revision-content use-tn-links selectable-text" style={{ overflow: "auto", wordBreak: "break-word" }}>
|
||||
<RevisionContent noteContent={noteContent} revisionItem={revisionItem} fullRevision={fullRevision} showDiff={showDiff}/>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -19,9 +19,11 @@ export interface DropdownProps extends Pick<HTMLProps<HTMLDivElement>, "id" | "c
|
||||
disabled?: boolean;
|
||||
text?: ComponentChildren;
|
||||
forceShown?: boolean;
|
||||
onShown?: () => void;
|
||||
onHidden?: () => void;
|
||||
}
|
||||
|
||||
export default function Dropdown({ id, className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown }: DropdownProps) {
|
||||
export default function Dropdown({ id, className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown, onShown: externalOnShown, onHidden: externalOnHidden }: DropdownProps) {
|
||||
const dropdownRef = useRef<HTMLDivElement | null>(null);
|
||||
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
||||
|
||||
@ -40,10 +42,12 @@ export default function Dropdown({ id, className, buttonClassName, isStatic, chi
|
||||
|
||||
const onShown = useCallback(() => {
|
||||
setShown(true);
|
||||
externalOnShown?.();
|
||||
}, [])
|
||||
|
||||
const onHidden = useCallback(() => {
|
||||
setShown(false);
|
||||
externalOnHidden?.();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useRef, useMemo } from "preact/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
import { ComponentChildren } from "preact";
|
||||
@ -7,9 +8,16 @@ import { Modal as BootstrapModal } from "bootstrap";
|
||||
import { memo } from "preact/compat";
|
||||
import { useSyncedRef } from "./hooks";
|
||||
|
||||
interface CustomTitleBarButton {
|
||||
title: string;
|
||||
iconClassName: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
interface ModalProps {
|
||||
className: string;
|
||||
title: string | ComponentChildren;
|
||||
customTitleBarButtons?: (CustomTitleBarButton | null)[];
|
||||
size: "xl" | "lg" | "md" | "sm";
|
||||
children: ComponentChildren;
|
||||
/**
|
||||
@ -66,9 +74,13 @@ interface ModalProps {
|
||||
* If true, the modal will remain in the DOM even when not shown. This can be useful for certain CSS transitions or when you want to avoid re-mounting the modal content.
|
||||
*/
|
||||
keepInDom?: boolean;
|
||||
/**
|
||||
* If true, the modal will not focus itself after becoming visible.
|
||||
*/
|
||||
noFocus?: boolean;
|
||||
}
|
||||
|
||||
export default function Modal({ children, className, size, title, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable, keepInDom }: ModalProps) {
|
||||
export default function Modal({ children, className, size, title, customTitleBarButtons: titleBarButtons, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable, keepInDom, noFocus }: ModalProps) {
|
||||
const modalRef = useSyncedRef<HTMLDivElement>(externalModalRef);
|
||||
const modalInstanceRef = useRef<BootstrapModal>();
|
||||
const elementToFocus = useRef<Element | null>();
|
||||
@ -100,13 +112,15 @@ export default function Modal({ children, className, size, title, header, footer
|
||||
useEffect(() => {
|
||||
if (show && modalRef.current) {
|
||||
elementToFocus.current = document.activeElement;
|
||||
openDialog($(modalRef.current), !stackable).then(($widget) => {
|
||||
openDialog($(modalRef.current), !stackable, {
|
||||
focus: !noFocus
|
||||
}).then(($widget) => {
|
||||
modalInstanceRef.current = BootstrapModal.getOrCreateInstance($widget[0]);
|
||||
})
|
||||
} else {
|
||||
modalInstanceRef.current?.hide();
|
||||
}
|
||||
}, [ show, modalRef.current ]);
|
||||
}, [ show, modalRef.current, noFocus ]);
|
||||
|
||||
// Memoize styles to prevent recreation on every render
|
||||
const dialogStyle = useMemo<CSSProperties>(() => {
|
||||
@ -142,7 +156,17 @@ export default function Modal({ children, className, size, title, header, footer
|
||||
{helpPageId && (
|
||||
<button className="help-button" type="button" data-in-app-help={helpPageId} title={t("modal.help_title")}>?</button>
|
||||
)}
|
||||
|
||||
{titleBarButtons?.filter((b) => b !== null).map((titleBarButton) => (
|
||||
<button type="button"
|
||||
className={clsx("custom-title-bar-button bx", titleBarButton.iconClassName)}
|
||||
title={titleBarButton.title}
|
||||
onClick={titleBarButton.onClick}>
|
||||
</button>
|
||||
))}
|
||||
|
||||
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label={t("modal.close")}></button>
|
||||
|
||||
</div>
|
||||
|
||||
{onSubmit ? (
|
||||
|
||||
@ -461,27 +461,31 @@ export function useNoteLabelInt(note: FNote | undefined | null, labelName: Filte
|
||||
|
||||
export function useNoteBlob(note: FNote | null | undefined, componentId?: string): FBlob | null | undefined {
|
||||
const [ blob, setBlob ] = useState<FBlob | null>();
|
||||
const requestIdRef = useRef(0);
|
||||
|
||||
function refresh() {
|
||||
note?.getBlob().then(setBlob);
|
||||
async function refresh() {
|
||||
const requestId = ++requestIdRef.current;
|
||||
const newBlob = await note?.getBlob();
|
||||
|
||||
// Only update if this is the latest request.
|
||||
if (requestId === requestIdRef.current) {
|
||||
setBlob(newBlob);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(refresh, [ note?.noteId ]);
|
||||
useEffect(() => { refresh() }, [ note?.noteId ]);
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (!note) return;
|
||||
|
||||
// Check if the note was deleted.
|
||||
if (loadResults.getEntityRow("notes", note.noteId)?.isDeleted) {
|
||||
requestIdRef.current++; // invalidate pending results
|
||||
setBlob(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if a revision occurred.
|
||||
if (loadResults.hasRevisionForNote(note.noteId)) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
if (loadResults.isNoteContentReloaded(note.noteId, componentId)) {
|
||||
if (loadResults.hasRevisionForNote(note.noteId) ||
|
||||
loadResults.isNoteContentReloaded(note.noteId, componentId)) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
@ -791,7 +795,7 @@ export function useKeyboardShortcuts(scope: "code-detail" | "text-detail", conta
|
||||
* and provides a way to switch to editing mode.
|
||||
*/
|
||||
export function useIsNoteReadOnly(note: FNote | null | undefined, noteContext: NoteContext | undefined) {
|
||||
const [isReadOnly, setIsReadOnly] = useState<boolean | undefined>(undefined);
|
||||
const [ isReadOnly, setIsReadOnly ] = useState<boolean | undefined>(undefined);
|
||||
|
||||
const enableEditing = useCallback(() => {
|
||||
if (noteContext?.viewScope) {
|
||||
@ -806,7 +810,7 @@ export function useIsNoteReadOnly(note: FNote | null | undefined, noteContext: N
|
||||
setIsReadOnly(readOnly);
|
||||
});
|
||||
}
|
||||
}, [note, noteContext]);
|
||||
}, [ note, noteContext, noteContext?.viewScope ]);
|
||||
|
||||
useTriliumEvent("readOnlyTemporarilyDisabled", ({noteContext: eventNoteContext}) => {
|
||||
if (noteContext?.ntxId === eventNoteContext.ntxId) {
|
||||
@ -814,7 +818,7 @@ export function useIsNoteReadOnly(note: FNote | null | undefined, noteContext: N
|
||||
}
|
||||
});
|
||||
|
||||
return {isReadOnly, enableEditing};
|
||||
return { isReadOnly, enableEditing };
|
||||
}
|
||||
|
||||
async function isNoteReadOnly(note: FNote, noteContext: NoteContext) {
|
||||
|
||||
@ -17,24 +17,24 @@ export default function FilePropertiesTab({ note }: { note?: FNote | null }) {
|
||||
return (
|
||||
<div className="file-properties-widget">
|
||||
{note && (
|
||||
<table class="file-table">
|
||||
<table className="file-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="text-nowrap">{t("file_properties.note_id")}:</th>
|
||||
<td class="file-note-id">{note.noteId}</td>
|
||||
<th class="text-nowrap">{t("file_properties.original_file_name")}:</th>
|
||||
<td class="file-filename">{originalFileName ?? "?"}</td>
|
||||
<th className="text-nowrap">{t("file_properties.note_id")}:</th>
|
||||
<td className="file-note-id selectable-text">{note.noteId}</td>
|
||||
<th className="text-nowrap">{t("file_properties.original_file_name")}:</th>
|
||||
<td className="file-filename selectable-text">{originalFileName ?? "?"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-nowrap">{t("file_properties.file_type")}:</th>
|
||||
<td class="file-filetype">{note.mime}</td>
|
||||
<th class="text-nowrap">{t("file_properties.file_size")}:</th>
|
||||
<td class="file-filesize">{formatSize(blob?.contentLength ?? 0)}</td>
|
||||
<th className="text-nowrap">{t("file_properties.file_type")}:</th>
|
||||
<td className="file-filetype selectable-text">{note.mime}</td>
|
||||
<th className="text-nowrap">{t("file_properties.file_size")}:</th>
|
||||
<td className="file-filesize selectable-text">{formatSize(blob?.contentLength ?? 0)}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colSpan={4}>
|
||||
<div class="file-buttons">
|
||||
<div className="file-buttons">
|
||||
<Button
|
||||
icon="bx bx-download"
|
||||
text={t("file_properties.download")}
|
||||
|
||||
@ -23,17 +23,17 @@ export default function ImagePropertiesTab({ note, ntxId }: TabContext) {
|
||||
<div style={{ display: "flex", justifyContent: "space-evenly", margin: "10px" }}>
|
||||
<span>
|
||||
<strong>{t("image_properties.original_file_name")}:</strong>{" "}
|
||||
<span>{originalFileName ?? "?"}</span>
|
||||
<span className="selectable-text">{originalFileName ?? "?"}</span>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<strong>{t("image_properties.file_type")}:</strong>{" "}
|
||||
<span>{note.mime}</span>
|
||||
<span className="selectable-text">{note.mime}</span>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<strong>{t("image_properties.file_size")}:</strong>{" "}
|
||||
<span>{formatSize(blob?.contentLength)}</span>
|
||||
<span className="selectable-text">{formatSize(blob?.contentLength)}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ export default function InheritedAttributesTab({ note, componentId }: TabContext
|
||||
|
||||
return (
|
||||
<div className="inherited-attributes-widget">
|
||||
<div className="inherited-attributes-container">
|
||||
<div className="inherited-attributes-container selectable-text">
|
||||
{inheritedAttributes?.length ? (
|
||||
joinElements(inheritedAttributes.map(attribute => (
|
||||
<InheritedAttribute
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ConvertToAttachmentResponse } from "@triliumnext/commons";
|
||||
import { FormDropdownDivider, FormListItem } from "../react/FormList";
|
||||
import { FormDropdownDivider, FormListHeader, FormListItem } from "../react/FormList";
|
||||
import { isElectron as getIsElectron, isMac as getIsMac } from "../../services/utils";
|
||||
import { ParentComponent } from "../react/react_utils";
|
||||
import { t } from "../../services/i18n"
|
||||
@ -113,8 +113,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
|
||||
function DevelopmentActions({ note }: { note: FNote }) {
|
||||
return (
|
||||
<>
|
||||
<FormDropdownDivider />
|
||||
<FormListItem disabled>Development-only Actions</FormListItem>
|
||||
<FormListHeader text="Development-only Actions" />
|
||||
<FormListItem
|
||||
icon="bx bx-printer"
|
||||
onClick={() => window.open(`/?print=#root/${note.noteId}`, "_blank")}
|
||||
|
||||
@ -39,21 +39,21 @@ export default function NoteInfoTab({ note }: TabContext) {
|
||||
<>
|
||||
<div className="note-info-item">
|
||||
<span>{t("note_info_widget.note_id")}:</span>
|
||||
<span className="note-info-id">{note.noteId}</span>
|
||||
<span className="note-info-id selectable-text">{note.noteId}</span>
|
||||
</div>
|
||||
<div className="note-info-item">
|
||||
<span>{t("note_info_widget.created")}:</span>
|
||||
<span>{formatDateTime(metadata?.dateCreated)}</span>
|
||||
<span className="selectable-text">{formatDateTime(metadata?.dateCreated)}</span>
|
||||
</div>
|
||||
<div className="note-info-item">
|
||||
<span>{t("note_info_widget.modified")}:</span>
|
||||
<span>{formatDateTime(metadata?.dateModified)}</span>
|
||||
<span className="selectable-text">{formatDateTime(metadata?.dateModified)}</span>
|
||||
</div>
|
||||
<div className="note-info-item">
|
||||
<span>{t("note_info_widget.type")}:</span>
|
||||
<span>
|
||||
<span className="note-info-type">{note.type}</span>{' '}
|
||||
{note.mime && <span className="note-info-mime">({note.mime})</span>}
|
||||
{note.mime && <span className="note-info-mime selectable-text">({note.mime})</span>}
|
||||
</span>
|
||||
</div>
|
||||
<div className="note-info-item">
|
||||
@ -77,7 +77,7 @@ export default function NoteInfoTab({ note }: TabContext) {
|
||||
/>
|
||||
)}
|
||||
|
||||
<span className="note-sizes-wrapper">
|
||||
<span className="note-sizes-wrapper selectable-text">
|
||||
<span className="note-size">{formatSize(noteSizeResponse?.noteSize)}</span>
|
||||
{" "}
|
||||
{subtreeSizeResponse && subtreeSizeResponse.subTreeNoteCount > 1 &&
|
||||
|
||||
@ -8,6 +8,7 @@ import NoteActions from "./NoteActions";
|
||||
import { KeyboardActionNames } from "@triliumnext/commons";
|
||||
import { RIBBON_TAB_DEFINITIONS } from "./RibbonDefinition";
|
||||
import { TabConfiguration, TitleContext } from "./ribbon-interface";
|
||||
import clsx from "clsx";
|
||||
|
||||
const TAB_CONFIGURATION = numberObjectsInPlace<TabConfiguration>(RIBBON_TAB_DEFINITIONS);
|
||||
|
||||
@ -63,62 +64,61 @@ export default function Ribbon() {
|
||||
}, [ computedTabs, activeTabIndex ]));
|
||||
|
||||
return (
|
||||
<div className="ribbon-container" style={{ contain: "none" }}>
|
||||
{noteContext?.viewScope?.viewMode === "default" && (
|
||||
<>
|
||||
<div className="ribbon-top-row">
|
||||
<div className="ribbon-tab-container">
|
||||
{computedTabs && computedTabs.map(({ title, icon, index, toggleCommand, shouldShow }) => (
|
||||
shouldShow && <RibbonTab
|
||||
icon={icon}
|
||||
title={typeof title === "string" ? title : title(titleContext)}
|
||||
active={index === activeTabIndex}
|
||||
toggleCommand={toggleCommand}
|
||||
onClick={() => {
|
||||
if (activeTabIndex !== index) {
|
||||
setActiveTabIndex(index);
|
||||
} else {
|
||||
// Collapse
|
||||
setActiveTabIndex(undefined);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
className={clsx("ribbon-container", noteContext?.viewScope?.viewMode !== "default" && "hidden-ext")}
|
||||
style={{ contain: "none" }}
|
||||
>
|
||||
<div className="ribbon-top-row">
|
||||
<div className="ribbon-tab-container">
|
||||
{computedTabs && computedTabs.map(({ title, icon, index, toggleCommand, shouldShow }) => (
|
||||
shouldShow && <RibbonTab
|
||||
icon={icon}
|
||||
title={typeof title === "string" ? title : title(titleContext)}
|
||||
active={index === activeTabIndex}
|
||||
toggleCommand={toggleCommand}
|
||||
onClick={() => {
|
||||
if (activeTabIndex !== index) {
|
||||
setActiveTabIndex(index);
|
||||
} else {
|
||||
// Collapse
|
||||
setActiveTabIndex(undefined);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="ribbon-button-container">
|
||||
{ note && <NoteActions note={note} noteContext={noteContext} /> }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ribbon-body-container">
|
||||
{computedTabs && computedTabs.map(tab => {
|
||||
const isActive = tab.index === activeTabIndex;
|
||||
if (!isActive && !tab.stayInDom) {
|
||||
return;
|
||||
}
|
||||
|
||||
const TabContent = tab.content;
|
||||
|
||||
return (
|
||||
<div className={`ribbon-body ${!isActive ? "hidden-ext" : ""}`}>
|
||||
<TabContent
|
||||
note={note}
|
||||
hidden={!isActive}
|
||||
ntxId={ntxId}
|
||||
hoistedNoteId={hoistedNoteId}
|
||||
notePath={notePath}
|
||||
noteContext={noteContext}
|
||||
componentId={componentId}
|
||||
activate={useCallback(() => {
|
||||
setActiveTabIndex(tab.index)
|
||||
}, [setActiveTabIndex])}
|
||||
/>
|
||||
</div>
|
||||
<div className="ribbon-button-container">
|
||||
{ note && <NoteActions note={note} noteContext={noteContext} /> }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ribbon-body-container">
|
||||
{computedTabs && computedTabs.map(tab => {
|
||||
const isActive = tab.index === activeTabIndex;
|
||||
if (!isActive && !tab.stayInDom) {
|
||||
return;
|
||||
}
|
||||
|
||||
const TabContent = tab.content;
|
||||
|
||||
return (
|
||||
<div className={`ribbon-body ${!isActive ? "hidden-ext" : ""}`}>
|
||||
<TabContent
|
||||
note={note}
|
||||
hidden={!isActive}
|
||||
ntxId={ntxId}
|
||||
hoistedNoteId={hoistedNoteId}
|
||||
notePath={notePath}
|
||||
noteContext={noteContext}
|
||||
componentId={componentId}
|
||||
activate={useCallback(() => {
|
||||
setActiveTabIndex(tab.index)
|
||||
}, [setActiveTabIndex])}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ export const RIBBON_TAB_DEFINITIONS: TabConfiguration[] = [
|
||||
&& !(await noteContext?.isReadOnly()),
|
||||
toggleCommand: "toggleRibbonTabClassicEditor",
|
||||
content: FormattingToolbar,
|
||||
activate: true,
|
||||
activate: () => !options.is("editedNotesOpenInRibbon"),
|
||||
stayInDom: true
|
||||
},
|
||||
{
|
||||
@ -50,7 +50,7 @@ export const RIBBON_TAB_DEFINITIONS: TabConfiguration[] = [
|
||||
icon: "bx bx-calendar-edit",
|
||||
content: EditedNotesTab,
|
||||
show: ({ note }) => note?.hasOwnedLabel("dateNote"),
|
||||
activate: ({ note }) => (note?.getPromotedDefinitionAttributes().length === 0 || !options.is("promotedAttributesOpenInRibbon")) && options.is("editedNotesOpenInRibbon")
|
||||
activate: () => options.is("editedNotesOpenInRibbon")
|
||||
},
|
||||
{
|
||||
title: t("book_properties.book_properties"),
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
.note-detail-doc-content {
|
||||
padding: 15px;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.note-detail-doc-content pre {
|
||||
|
||||
@ -1,3 +1,21 @@
|
||||
.note-detail-empty {
|
||||
container-type: size;
|
||||
padding-top: 50px;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.note-detail-empty > * {
|
||||
margin-inline: auto;
|
||||
max-width: 850px;
|
||||
padding-inline: 50px;
|
||||
}
|
||||
|
||||
@container (max-width: 600px) {
|
||||
.note-detail-empty > * {
|
||||
padding-inline: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-notes {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -14,7 +32,8 @@
|
||||
|
||||
.workspace-notes .workspace-note:hover {
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--main-border-color);
|
||||
background-color: var(--icon-button-hover-background);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.note-detail-empty-results .aa-dropdown-menu {
|
||||
@ -24,6 +43,11 @@
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.empty-tab-search label {
|
||||
margin-bottom: 8px;
|
||||
color: var(--muted-text-color);
|
||||
}
|
||||
|
||||
.empty-tab-search .note-autocomplete-input {
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
@ -10,16 +10,16 @@ import FNote from "../../entities/fnote";
|
||||
import search from "../../services/search";
|
||||
import { TypeWidgetProps } from "./type_widget";
|
||||
|
||||
export default function Empty({ }: TypeWidgetProps) {
|
||||
export default function Empty({ ntxId }: TypeWidgetProps) {
|
||||
return (
|
||||
<>
|
||||
<WorkspaceSwitcher />
|
||||
<NoteSearch />
|
||||
<NoteSearch ntxId={ntxId ?? null} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function NoteSearch() {
|
||||
function NoteSearch({ ntxId }: { ntxId: string | null }) {
|
||||
const resultsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const autocompleteRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@ -45,10 +45,9 @@ function NoteSearch() {
|
||||
if (!suggestion?.notePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const activeContext = appContext.tabManager.getActiveContext();
|
||||
if (activeContext) {
|
||||
activeContext.setNote(suggestion.notePath);
|
||||
const activeNoteContext = appContext.tabManager.getNoteContextById(ntxId) ?? appContext.tabManager.getActiveContext();
|
||||
if (activeNoteContext) {
|
||||
activeNoteContext.setNote(suggestion.notePath);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
10
apps/client/src/widgets/type_widgets/NoteMap.css
Normal file
10
apps/client/src/widgets/type_widgets/NoteMap.css
Normal file
@ -0,0 +1,10 @@
|
||||
.note-detail-note-map {
|
||||
&>div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
import { TypeWidgetProps } from "./type_widget";
|
||||
import NoteMapEl from "../note_map/NoteMap";
|
||||
import { useRef } from "preact/hooks";
|
||||
import "./NoteMap.css";
|
||||
|
||||
export default function NoteMap({ note }: TypeWidgetProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -104,7 +104,7 @@ export function BackupList({ backups }: { backups: DatabaseBackup[] }) {
|
||||
backups.map(({ mtime, filePath }) => (
|
||||
<tr>
|
||||
<td>{mtime ? formatDateTime(mtime) : "-"}</td>
|
||||
<td>{filePath}</td>
|
||||
<td className="selectable-text">{filePath}</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
|
||||
@ -226,7 +226,7 @@ function CodeBlockPreview({ theme, wordWrap }: { theme: string, wordWrap: boolea
|
||||
|
||||
return (
|
||||
<div className="note-detail-readonly-text-content ck-content code-sample-wrapper">
|
||||
<pre className="hljs" style={{ marginBottom: 0 }}>
|
||||
<pre className="hljs selectable-text" style={{ marginBottom: 0 }}>
|
||||
<code className="code-sample" style={codeStyle} dangerouslySetInnerHTML={getHtml(code)} />
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
@ -98,6 +98,14 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
||||
editorApi: editorApiRef.current,
|
||||
});
|
||||
},
|
||||
insertDateTimeToTextCommand() {
|
||||
if (!editorApiRef.current) return;
|
||||
const date = new Date();
|
||||
const customDateTimeFormat = options.get("customDateTimeFormat");
|
||||
const dateString = utils.formatDateTime(date, customDateTimeFormat);
|
||||
|
||||
addTextToEditor(dateString);
|
||||
},
|
||||
// Include note functionality note
|
||||
addIncludeNoteToTextCommand() {
|
||||
if (!editorApiRef.current) return;
|
||||
@ -197,14 +205,6 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
||||
});
|
||||
}
|
||||
|
||||
useTriliumEvent("insertDateTimeToText", ({ ntxId: eventNtxId }) => {
|
||||
if (eventNtxId !== ntxId) return;
|
||||
const date = new Date();
|
||||
const customDateTimeFormat = options.get("customDateTimeFormat");
|
||||
const dateString = utils.formatDateTime(date, customDateTimeFormat);
|
||||
|
||||
addTextToEditor(dateString);
|
||||
});
|
||||
useTriliumEvent("addTextToActiveEditor", ({ text }) => {
|
||||
if (!noteContext?.isActive()) return;
|
||||
addTextToEditor(text);
|
||||
|
||||
@ -41,7 +41,6 @@ export default function ReadOnlyText({ note, noteContext, ntxId }: TypeWidgetPro
|
||||
|
||||
// React to included note changes.
|
||||
useTriliumEvent("refreshIncludedNote", ({ noteId }) => {
|
||||
console.log("Refresh ", noteId);
|
||||
if (!contentRef.current) return;
|
||||
refreshIncludedNote(contentRef.current, noteId);
|
||||
});
|
||||
@ -56,7 +55,7 @@ export default function ReadOnlyText({ note, noteContext, ntxId }: TypeWidgetPro
|
||||
<>
|
||||
<RawHtmlBlock
|
||||
containerRef={contentRef}
|
||||
className={clsx("note-detail-readonly-text-content ck-content use-tn-links", codeBlockWordWrap && "word-wrap")}
|
||||
className={clsx("note-detail-readonly-text-content ck-content use-tn-links selectable-text", codeBlockWordWrap && "word-wrap")}
|
||||
tabindex={100}
|
||||
dir={isRtl ? "rtl" : "ltr"}
|
||||
html={blob?.content}
|
||||
|
||||
@ -1,52 +1,54 @@
|
||||
.classic-toolbar-outer-container {
|
||||
contain: none !important;
|
||||
}
|
||||
|
||||
.classic-toolbar-outer-container.visible {
|
||||
height: 38px;
|
||||
background-color: var(--main-background-color);
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#root-widget.virtual-keyboard-opened .classic-toolbar-outer-container.ios {
|
||||
position: absolute;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
height: 38px;
|
||||
overflow: scroll;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
user-select: none;
|
||||
scrollbar-width: 0 !important;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget::-webkit-scrollbar:horizontal {
|
||||
height: 0 !important;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget.dropdown-active {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget .ck.ck-toolbar {
|
||||
--ck-color-toolbar-background: transparent;
|
||||
--ck-color-button-default-background: transparent;
|
||||
--ck-color-button-default-disabled-background: transparent;
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget .ck.ck-button.ck-disabled {
|
||||
opacity: 0.3;
|
||||
body.mobile {
|
||||
.classic-toolbar-outer-container {
|
||||
contain: none !important;
|
||||
}
|
||||
|
||||
.classic-toolbar-outer-container.visible {
|
||||
height: 38px;
|
||||
background-color: var(--main-background-color);
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#root-widget.virtual-keyboard-opened .classic-toolbar-outer-container.ios {
|
||||
position: absolute;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
height: 38px;
|
||||
overflow: scroll;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
user-select: none;
|
||||
scrollbar-width: 0 !important;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget::-webkit-scrollbar:horizontal {
|
||||
height: 0 !important;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget.dropdown-active {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget .ck.ck-toolbar {
|
||||
--ck-color-toolbar-background: transparent;
|
||||
--ck-color-button-default-background: transparent;
|
||||
--ck-color-button-default-disabled-background: transparent;
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.classic-toolbar-widget .ck.ck-button.ck-disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
@ -4,19 +4,23 @@ import "./mobile_editor_toolbar.css";
|
||||
import { isIOS } from "../../../services/utils";
|
||||
import { CKTextEditor, ClassicEditor } from "@triliumnext/ckeditor5";
|
||||
|
||||
interface MobileEditorToolbarProps {
|
||||
inPopupEditor?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the editing toolbar for CKEditor in mobile mode. The toolbar acts as a floating bar, with two different mechanism:
|
||||
*
|
||||
* - On iOS, because it does not respect the viewport meta value `interactive-widget=resizes-content`, we need to listen to window resizes and scroll and reposition the toolbar using absolute positioning.
|
||||
* - On Android, the viewport change makes the keyboard resize the content area, all we have to do is to hide the tab bar and global menu (handled in the global style).
|
||||
*/
|
||||
export default function MobileEditorToolbar() {
|
||||
export default function MobileEditorToolbar({ inPopupEditor }: MobileEditorToolbarProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const { note, noteContext, ntxId } = useNoteContext();
|
||||
const [ shouldDisplay, setShouldDisplay ] = useState(false);
|
||||
const [ dropdownActive, setDropdownActive ] = useState(false);
|
||||
|
||||
usePositioningOniOS(containerRef);
|
||||
usePositioningOniOS(!inPopupEditor, containerRef);
|
||||
|
||||
useEffect(() => {
|
||||
noteContext?.isReadOnly().then(isReadOnly => {
|
||||
@ -29,7 +33,10 @@ export default function MobileEditorToolbar() {
|
||||
if (eventNtxId !== ntxId || !containerRef.current) return;
|
||||
const toolbar = editor.ui.view.toolbar?.element;
|
||||
|
||||
repositionDropdowns(editor);
|
||||
if (!inPopupEditor) {
|
||||
repositionDropdowns(editor);
|
||||
}
|
||||
|
||||
if (toolbar) {
|
||||
containerRef.current.replaceChildren(toolbar);
|
||||
} else {
|
||||
@ -60,7 +67,7 @@ export default function MobileEditorToolbar() {
|
||||
)
|
||||
}
|
||||
|
||||
function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
||||
function usePositioningOniOS(enabled: boolean, wrapperRef: MutableRef<HTMLDivElement | null>) {
|
||||
const adjustPosition = useCallback(() => {
|
||||
if (!wrapperRef.current) return;
|
||||
let bottom = window.innerHeight - (window.visualViewport?.height || 0);
|
||||
@ -68,7 +75,7 @@ function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isIOS()) return;
|
||||
if (!isIOS() || !enabled) return;
|
||||
|
||||
window.visualViewport?.addEventListener("resize", adjustPosition);
|
||||
window.addEventListener("scroll", adjustPosition);
|
||||
@ -77,7 +84,7 @@ function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
||||
window.visualViewport?.removeEventListener("resize", adjustPosition);
|
||||
window.removeEventListener("scroll", adjustPosition);
|
||||
};
|
||||
}, []);
|
||||
}, [ enabled ]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -55,6 +55,7 @@ export function buildClassicToolbar(multilineToolbar: boolean) {
|
||||
...TEXT_FORMATTING_GROUP,
|
||||
items: ["underline", "strikethrough", "|", "superscript", "subscript", "|", "kbd"]
|
||||
},
|
||||
"formatPainter",
|
||||
"|",
|
||||
"fontColor",
|
||||
"fontBackgroundColor",
|
||||
@ -104,6 +105,7 @@ export function buildFloatingToolbar() {
|
||||
...TEXT_FORMATTING_GROUP,
|
||||
items: [ "strikethrough", "|", "superscript", "subscript", "|", "kbd" ]
|
||||
},
|
||||
"formatPainter",
|
||||
"|",
|
||||
"fontColor",
|
||||
"fontBackgroundColor",
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/remote": "2.1.3",
|
||||
"better-sqlite3": "12.4.6",
|
||||
"better-sqlite3": "12.5.0",
|
||||
"electron-debug": "4.1.0",
|
||||
"electron-dl": "4.0.0",
|
||||
"electron-squirrel-startup": "1.0.1",
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"description": "Standalone tool to dump contents of Trilium document.db file into a directory tree of notes",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"better-sqlite3": "12.4.6",
|
||||
"better-sqlite3": "12.5.0",
|
||||
"mime-types": "3.0.2",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"tsx": "4.20.6",
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
"description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.",
|
||||
"dependencies": {
|
||||
"archiver": "7.0.1",
|
||||
"better-sqlite3": "12.4.6"
|
||||
"better-sqlite3": "12.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@triliumnext/client": "workspace:*",
|
||||
|
||||
72
apps/server-e2e/src/layout/split_pane.spec.ts
Normal file
72
apps/server-e2e/src/layout/split_pane.spec.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import App from "../support/app";
|
||||
|
||||
const TEXT_NOTE_TITLE = "Text notes";
|
||||
const CODE_NOTE_TITLE = "Code notes";
|
||||
|
||||
test("Open the note in the correct split pane", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
await app.closeAllTabs();
|
||||
|
||||
// Open the first split.
|
||||
await app.goToNoteInNewTab(TEXT_NOTE_TITLE);
|
||||
const split1 = app.currentNoteSplit;
|
||||
|
||||
// Create a new split.
|
||||
const splitButton = split1.locator("button.bx-dock-right");
|
||||
await expect(splitButton).toBeVisible();
|
||||
await splitButton.click();
|
||||
|
||||
// Search for "Code notes" in the empty area of the second split.
|
||||
const split2 = app.currentNoteSplit.nth(1);;
|
||||
await expect(split2).toBeVisible();
|
||||
const autocomplete = split2.locator(".note-autocomplete");
|
||||
await autocomplete.fill(CODE_NOTE_TITLE);
|
||||
const resultsSelector = split2.locator(".note-detail-empty-results");
|
||||
await expect(resultsSelector).toContainText(CODE_NOTE_TITLE);
|
||||
|
||||
//Focus on the first split.
|
||||
const noteContent = split1.locator(".note-detail-editable-text-editor");
|
||||
await expect(noteContent.locator("p")).toBeVisible();
|
||||
await noteContent.focus();
|
||||
|
||||
// Click the search result in the second split.
|
||||
await resultsSelector.locator(".aa-suggestion", { hasText: CODE_NOTE_TITLE })
|
||||
.nth(1).click();
|
||||
|
||||
await expect(split2).toContainText(CODE_NOTE_TITLE);
|
||||
});
|
||||
|
||||
test("Can directly focus the autocomplete input within the split", async ({ page, context }) => {
|
||||
const app = new App(page, context);
|
||||
await app.goto();
|
||||
await app.closeAllTabs();
|
||||
|
||||
// Open the first split.
|
||||
await app.goToNoteInNewTab(TEXT_NOTE_TITLE);
|
||||
const split1 = app.currentNoteSplit;
|
||||
|
||||
// Create a new split.
|
||||
const splitButton = split1.locator("button.bx-dock-right");
|
||||
await expect(splitButton).toBeVisible();
|
||||
await splitButton.click();
|
||||
|
||||
// Search for "Code notes" in the empty area of the second split.
|
||||
const split2 = app.currentNoteSplit.nth(1);;
|
||||
await expect(split2).toBeVisible();
|
||||
|
||||
// Focus the first split.
|
||||
const noteContent = split1.locator(".note-detail-editable-text-editor");
|
||||
await expect(noteContent.locator("p")).toBeVisible();
|
||||
await noteContent.focus();
|
||||
await noteContent.click();
|
||||
|
||||
// click the autocomplete input box of the second split
|
||||
const autocomplete = split2.locator(".note-autocomplete");
|
||||
await autocomplete.focus();
|
||||
await autocomplete.click();
|
||||
|
||||
await page.waitForTimeout(100);
|
||||
await expect(autocomplete).toBeFocused();
|
||||
});
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"better-sqlite3": "12.4.6"
|
||||
"better-sqlite3": "12.5.0"
|
||||
}
|
||||
}
|
||||
@ -25,7 +25,7 @@
|
||||
"docker-start-rootless-alpine": "pnpm docker-build-rootless-alpine && docker run -p 8081:8080 triliumnext-rootless-alpine"
|
||||
},
|
||||
"dependencies": {
|
||||
"better-sqlite3": "12.4.6",
|
||||
"better-sqlite3": "12.5.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"node-html-parser": "7.0.1"
|
||||
},
|
||||
|
||||
2
apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json
generated
vendored
2
apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json
generated
vendored
File diff suppressed because one or more lines are too long
336
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text.html
generated
vendored
336
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text.html
generated
vendored
@ -4,7 +4,7 @@
|
||||
<p>Most of the interaction with text notes is done via the built-in toolbars.
|
||||
Depending on preference, there are two different layouts:</p>
|
||||
<ul>
|
||||
<li>The <em>Floating toolbar</em> is hidden by default and only appears when
|
||||
<li data-list-item-id="eafcb31c309cb140eedbb41048a0e0db1">The <em>Floating toolbar</em> is hidden by default and only appears when
|
||||
needed. In this mode there are actually two different toolbars:
|
||||
<br>
|
||||
<img src="1_Text_image.png" width="496"
|
||||
@ -12,7 +12,7 @@
|
||||
<img src="2_Text_image.png" width="812"
|
||||
height="114">
|
||||
</li>
|
||||
<li>A toolbar that appears when text is selected. This provides text-level
|
||||
<li data-list-item-id="e59aa3103fa4c5de33075e51f8d482164">A toolbar that appears when text is selected. This provides text-level
|
||||
formatting such as bold, italic, text colors, inline code, etc.
|
||||
<br><em><img src="Text_image.png" width="1109" height="124"></em>
|
||||
</li>
|
||||
@ -20,167 +20,171 @@
|
||||
<p>Fore more information see <a class="reference-link" href="#root/_help_nRhnJkTT8cPs">Formatting toolbar</a>.</p>
|
||||
<h2>Features and formatting</h2>
|
||||
<p>Here's a list of various features supported by text notes:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dedicated article</th>
|
||||
<th>Feature</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_Gr6xFaF6ioJ5">General formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Headings (section titles, paragraph)</li>
|
||||
<li>Font size</li>
|
||||
<li>Bold, italic, underline, strike-through</li>
|
||||
<li>Superscript, subscript</li>
|
||||
<li>Font color & background color</li>
|
||||
<li>Remove formatting</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_S6Xx8QIWTV66">Lists</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Bulleted lists</li>
|
||||
<li>Numbered lists</li>
|
||||
<li>To-do lists</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NwBbFdNZ9h7O">Block quotes & admonitions</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Block quotes</li>
|
||||
<li>Admonitions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NdowYOC1GFKS">Tables</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Basic tables</li>
|
||||
<li>Merging cells</li>
|
||||
<li>Styling tables and cells.</li>
|
||||
<li>Table captions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_UYuUB1ZekNQU">Developer-specific formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Inline code</li>
|
||||
<li>Code blocks</li>
|
||||
<li>Keyboard shortcuts</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_AgjCISero73a">Footnotes</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Footnotes</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_mT0HEkOsz6i1">Images</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Images</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_QEAPj01N5f7w">Links</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>External links</li>
|
||||
<li>Internal Trilium links</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_nBAXQFj20hS1">Include Note</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Include note</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_CohkqWQC1iBv">Insert buttons</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Symbols</li>
|
||||
<li><a class="reference-link" href="#root/_help_YfYAtQBcfo5V">Math Equations</a>
|
||||
</li>
|
||||
<li>Mermaid diagrams</li>
|
||||
<li>Horizontal ruler</li>
|
||||
<li>Page break</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_dEHYtoWWi8ct">Other features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Indentation
|
||||
<ul>
|
||||
<li>Markdown import</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_2x0ZAX9ePtzV">Cut to subnote</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_gLt3vA97tMcp">Premium features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li><a class="reference-link" href="#root/_help_ZlN4nump6EbW">Slash Commands</a>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Read-Only vs. Editing Mode</h2>
|
||||
<p>Text notes are usually opened in edit mode. However, they may open in
|
||||
read-only mode if the note is too big or the note is explicitly marked
|
||||
as read-only. For more information, see <a class="reference-link"
|
||||
href="#root/_help_CoFPLs3dRlXc">Read-Only Notes</a>.</p>
|
||||
<h2>Keyboard shortcuts</h2>
|
||||
<p>There are numerous keyboard shortcuts to format the text without having
|
||||
to use the mouse. For a reference of all the key combinations, see
|
||||
<a
|
||||
class="reference-link" href="#root/_help_A9Oc6YKKc65v">Keyboard Shortcuts</a>. In addition, see <a class="reference-link"
|
||||
href="#root/_help_QrtTYPmdd1qq">Markdown-like formatting</a> as an alternative
|
||||
to the keyboard shortcuts.</p>
|
||||
<h2>Technical details</h2>
|
||||
<p>For the text editing functionality, Trilium uses a commercial product
|
||||
(with an open-source base) called <a class="reference-link" href="#root/_help_MI26XDLSAlCD">CKEditor</a>.
|
||||
This brings the benefit of having a powerful WYSIWYG (What You See Is What
|
||||
You Get) editor.</p>
|
||||
<figure
|
||||
class="table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dedicated article</th>
|
||||
<th>Feature</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_Gr6xFaF6ioJ5">General formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="e04c84d59d44645ee89b2a8541ed99f90">Headings (section titles, paragraph)</li>
|
||||
<li data-list-item-id="e39d25bd3d8bd06185b9d259e5827d451">Font size</li>
|
||||
<li data-list-item-id="e1f7e2a2f4b03449d82bdf5b5c6ea8d44">Bold, italic, underline, strike-through</li>
|
||||
<li data-list-item-id="e3decae72884f65b4d538151b6a297072">Superscript, subscript</li>
|
||||
<li data-list-item-id="e59adf00fef65304c163ae190fac5e92a">Font color & background color</li>
|
||||
<li data-list-item-id="ed3f09156147a2769e91db111c76376e2">Remove formatting</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_S6Xx8QIWTV66">Lists</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="ee87806a913900d85d8f018af81f41df8">Bulleted lists</li>
|
||||
<li data-list-item-id="e3ae314e365fa418ca6e0f061d63834c5">Numbered lists</li>
|
||||
<li data-list-item-id="ee84e08694165f95430046cb34f4cd123">To-do lists</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NwBbFdNZ9h7O">Block quotes & admonitions</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="e2892dc35a0d4b7ad65daffb8f9404daa">Block quotes</li>
|
||||
<li data-list-item-id="e7297e3ad1002f8de15aa0bd66c6f3f22">Admonitions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NdowYOC1GFKS">Tables</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="eb358a4567d93f66004f4195df2dda05a">Basic tables</li>
|
||||
<li data-list-item-id="e6135a555d6c63c30e4b84806a4870830">Merging cells</li>
|
||||
<li data-list-item-id="e29ac76563d0998b28fb1baf94dbdac8c">Styling tables and cells.</li>
|
||||
<li data-list-item-id="e372446e81fdedada64b8bed89ca93d1a">Table captions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_UYuUB1ZekNQU">Developer-specific formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="eb260b76afcbc07bd9d4ceec4e000e8a0">Inline code</li>
|
||||
<li data-list-item-id="e9864352286369ebe7b41c1599f498de8">Code blocks</li>
|
||||
<li data-list-item-id="ee62fb9ed7f349178e8f2a2bd9ec8cd74">Keyboard shortcuts</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_AgjCISero73a">Footnotes</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="edf62ec004eff35cfcb7e361deef19aaf">Footnotes</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_mT0HEkOsz6i1">Images</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="ebe6277e643041403489c3ceb30c36f7f">Images</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_QEAPj01N5f7w">Links</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="e3f988be2f259bb40607cb61541955395">External links</li>
|
||||
<li data-list-item-id="e3f91cc4f0cccd2c077cc306bacd68ef2">Internal Trilium links</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_nBAXQFj20hS1">Include Note</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="eac8015a64bce7b749cc67d1599062007">Include note</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_CohkqWQC1iBv">Insert buttons</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="e5cdf5d3885ec0ea67f924b4b8fe5c483">Symbols</li>
|
||||
<li data-list-item-id="e95082e6642ed5b1eec6e4e116b899a40"><a class="reference-link" href="#root/_help_YfYAtQBcfo5V">Math Equations</a>
|
||||
</li>
|
||||
<li data-list-item-id="ecbef6a358a5b8d27f0d3e08bbc750aa9">Mermaid diagrams</li>
|
||||
<li data-list-item-id="e6e97ee14dd29b7ccf53227107e5dc72d">Horizontal ruler</li>
|
||||
<li data-list-item-id="e6198c7c535c249faec2e8906775f11de">Page break</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_dEHYtoWWi8ct">Other features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="e0c14456cb83d483b07ea432ef9d4728e">Indentation
|
||||
<ul>
|
||||
<li data-list-item-id="e2029812c5e105c595590f70ee227631e">Markdown import</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li data-list-item-id="ea1ee012286e05190c89c9f4e64cf2036"><a class="reference-link" href="#root/_help_2x0ZAX9ePtzV">Cut to subnote</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_gLt3vA97tMcp">Premium features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li data-list-item-id="e1ab173193a533ccf33dccfd0cb916f1f"><a class="reference-link" href="#root/_help_ZlN4nump6EbW">Slash Commands</a>
|
||||
</li>
|
||||
<li data-list-item-id="e564b978c09fe5adf476b331b1e0640e3"><a class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>
|
||||
</li>
|
||||
<li data-list-item-id="e756306c31d9beffbba3820b6d1b9bc61"><a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/iPIMuisry3hd/gLt3vA97tMcp/_help_5wZallV2Qo1t">Format Painter</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
<h2>Read-Only vs. Editing Mode</h2>
|
||||
<p>Text notes are usually opened in edit mode. However, they may open in
|
||||
read-only mode if the note is too big or the note is explicitly marked
|
||||
as read-only. For more information, see <a class="reference-link"
|
||||
href="#root/_help_CoFPLs3dRlXc">Read-Only Notes</a>.</p>
|
||||
<h2>Keyboard shortcuts</h2>
|
||||
<p>There are numerous keyboard shortcuts to format the text without having
|
||||
to use the mouse. For a reference of all the key combinations, see
|
||||
<a
|
||||
class="reference-link" href="#root/_help_A9Oc6YKKc65v">Keyboard Shortcuts</a>. In addition, see <a class="reference-link"
|
||||
href="#root/_help_QrtTYPmdd1qq">Markdown-like formatting</a> as an alternative
|
||||
to the keyboard shortcuts.</p>
|
||||
<h2>Technical details</h2>
|
||||
<p>For the text editing functionality, Trilium uses a commercial product
|
||||
(with an open-source base) called <a class="reference-link" href="#root/_help_MI26XDLSAlCD">CKEditor</a>.
|
||||
This brings the benefit of having a powerful WYSIWYG (What You See Is What
|
||||
You Get) editor.</p>
|
||||
@ -12,11 +12,11 @@
|
||||
<p>Apart from using the UI, it is also possible to quickly insert headings
|
||||
using the Markdown-like shortcuts:</p>
|
||||
<ul>
|
||||
<li><code>##</code> for Heading 2</li>
|
||||
<li><code>###</code> for Heading 3</li>
|
||||
<li><code>####</code> for Heading 4</li>
|
||||
<li><code>#####</code> for Heading 5</li>
|
||||
<li><code>######</code> for Heading 6</li>
|
||||
<li data-list-item-id="e6083df2814e520e138326ef004812a46"><code>##</code> for Heading 2</li>
|
||||
<li data-list-item-id="e8b8acfd06c340271cc4fe84f65e67375"><code>###</code> for Heading 3</li>
|
||||
<li data-list-item-id="e19e95a52ddbcd54428ed5ab40df165a7"><code>####</code> for Heading 4</li>
|
||||
<li data-list-item-id="e69788e0bd8f4459748b8df997a19fa92"><code>#####</code> for Heading 5</li>
|
||||
<li data-list-item-id="eb7205b764231a314c9e9c1590c12ac1c"><code>######</code> for Heading 6</li>
|
||||
</ul>
|
||||
<h2>Font size</h2>
|
||||
<figure class="image image-style-align-right">
|
||||
@ -44,17 +44,17 @@
|
||||
<p>This formatting can be easily removed using the <em>Remove formatting</em> item.</p>
|
||||
<p>The following keyboard shortcuts can be used here:</p>
|
||||
<ul>
|
||||
<li><kbd>Ctrl</kbd>+<kbd>B</kbd> for bold</li>
|
||||
<li><kbd>Ctrl</kbd>+<kbd>I</kbd> for italic</li>
|
||||
<li><kbd>Ctrl</kbd>+<kbd>U</kbd> for underline</li>
|
||||
<li data-list-item-id="ecda6994b8be7fe33daeccbeb8bffe20b"><kbd>Ctrl</kbd>+<kbd>B</kbd> for bold</li>
|
||||
<li data-list-item-id="eaa20ab7965945937bd10a273e5fc323f"><kbd>Ctrl</kbd>+<kbd>I</kbd> for italic</li>
|
||||
<li data-list-item-id="e86881b33671d3bd6930d361e4bb76767"><kbd>Ctrl</kbd>+<kbd>U</kbd> for underline</li>
|
||||
</ul>
|
||||
<p>Alternatively, Markdown-like formatting can be used:</p>
|
||||
<ul>
|
||||
<li><strong>Bold</strong>: Type <code>**text**</code> or <code>__text__</code>
|
||||
<li data-list-item-id="e90b0f040ab78084c41cd8f44045528ec"><strong>Bold</strong>: Type <code>**text**</code> or <code>__text__</code>
|
||||
</li>
|
||||
<li><em>Italic</em>: Type <code>*text*</code> or <code>_text_</code>
|
||||
<li data-list-item-id="eebc210ee7f2b92e0885cd411c6fb8b80"><em>Italic</em>: Type <code>*text*</code> or <code>_text_</code>
|
||||
</li>
|
||||
<li><del>Strikethrough</del>: Type <code>~~text~~</code>
|
||||
<li data-list-item-id="eb7628d2cb441576b3b3edf6c42ab84b4"><del>Strikethrough</del>: Type <code>~~text~~</code>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Superscript, subscript</h2>
|
||||
@ -89,6 +89,11 @@
|
||||
be manually changed back to a paragraph according to the <em>Headings</em> section.</p>
|
||||
<p>When pasting content that comes with undesired formatting, an alternative
|
||||
to pasting and then removing formatting is pasting as plain text via <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd>.</p>
|
||||
<h2>Format painter</h2>
|
||||
<p>The <a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/iPIMuisry3hd/gLt3vA97tMcp/_help_5wZallV2Qo1t">Format Painter</a> allows
|
||||
users to copy the formatting of text (such as bold, italic, Strikethrough,
|
||||
etc.) and apply it to other parts of the document. It helps maintain consistent
|
||||
formatting and accelerates the creation of rich content.</p>
|
||||
<h2>Support for Markdown</h2>
|
||||
<p>When exported to <a class="reference-link" href="#root/_help_Oau6X9rCuegd">Markdown</a>,
|
||||
most of the general formatting is maintained such as headings, bold, italic,
|
||||
|
||||
45
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter.html
generated
vendored
Normal file
45
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter.html
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
<figure class="image image-style-align-right">
|
||||
<img style="aspect-ratio:220/76;" src="Format Painter_image.png"
|
||||
width="220" height="76">
|
||||
</figure>
|
||||
<aside class="admonition note">
|
||||
<p>This is a premium feature of the editor we are using (CKEditor) and we
|
||||
benefit from it thanks to an written agreement with the team. See
|
||||
<a
|
||||
class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/iPIMuisry3hd/_help_gLt3vA97tMcp">Premium features</a> for more information.</p>
|
||||
</aside>
|
||||
<p>The Format Painter is a feature in text notes that allows users to copy
|
||||
the formatting of text (such as <strong>bold</strong>, <em>italic</em>, <del>Strikethrough</del>,
|
||||
etc.) and apply it to other parts of the document. It helps maintain consistent
|
||||
formatting and accelerates the creation of rich content.</p>
|
||||
<h2>Usage Instructions</h2>
|
||||
<p>Click the text that you want to copy the formatting from and use the paint
|
||||
formatting toolbar button (<span><img class="image_resized" style="aspect-ratio:150/150;width:2.7%;" src="Format Painter_746436a2e1.svg" alt="Format painter" width="150" height="150">) </span>to
|
||||
copy the style. Then select the target text with your mouse to apply the
|
||||
formatting.</p>
|
||||
<ul>
|
||||
<li data-list-item-id="e9a728e8f49fb3ecf1202002dfafccabd"><strong>To copy the formatting</strong>: Place the cursor inside a text
|
||||
with some formatting and click the paint formatting toolbar button. Notice
|
||||
that the mouse cursor changes to the <span><img class="image_resized" style="aspect-ratio:30/20;width:3.64%;" src="Format Painter_e144e96df9.svg" alt="Format painter text cursor" width="30" height="20"></span>.</li>
|
||||
<li
|
||||
data-list-item-id="e745c039a3502d4e979d6dcde7876461b"><strong>To paint with the copied formatting</strong>: Click any word in
|
||||
the document and the new formatting will be applied. Alternatively, instead
|
||||
of clicking a single word, you can select a text fragment (like an entire
|
||||
paragraph). Notice that the cursor will go back to the default one after
|
||||
the formatting is applied.</li>
|
||||
<li data-list-item-id="e49e547cfd4e4cbb45712bace9a6e0979"><strong>To keep painting using the same formatting</strong>: Open the
|
||||
toolbar dropdown and enable the continuous painting mode. Once copied,
|
||||
the same formatting can be applied multiple times in different places until
|
||||
the paint formatting button is clicked (the cursor will then revert to
|
||||
the regular one).</li>
|
||||
</ul>
|
||||
<h2>Limitations</h2>
|
||||
<ol>
|
||||
<li data-list-item-id="ea3e6a7c317b51341c7a83cee5387ac1e">Painting with block-level formatting (like headings or image styles) is
|
||||
not supported yet. This is because, in <a class="reference-link" href="#root/pOsGYCXsbNQG/tC7s2alapj8V/1YeN2MzFUluU/_help_MI26XDLSAlCD">CKEditor</a>,
|
||||
they are considered a part of the content rather than text formatting.</li>
|
||||
<li
|
||||
data-list-item-id="edbd74adb8916daaae6024d8b0ae80e32">When applying formatting to words, spaces or other Western punctuation
|
||||
are used as word boundaries, which prevents proper handling of languages
|
||||
that do not use space-based word segmentation.</li>
|
||||
</ol>
|
||||
1
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_746436a2e1.svg
generated
vendored
Normal file
1
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_746436a2e1.svg
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M3 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z"/><path d="M16 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 16 6.449z"/></svg>
|
||||
|
After Width: | Height: | Size: 386 B |
7
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_e144e96df9.svg
generated
vendored
Normal file
7
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_e144e96df9.svg
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31 20" width="30" height="20">
|
||||
<path d="M14 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1V3Z" fill="#000"/>
|
||||
<path d="M27 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H20a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 27 6.449V3.25Z" fill="#000"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.855 2.25H27a2.5 2.5 0 0 1 2.5 2.5v1.7a3.25 3.25 0 0 1-2.79 3.216l-4.21.602a2 2 0 0 1 1 1.732v5a2 2 0 0 1-2 2H20a2 2 0 0 1-2-2v-5a2 2 0 0 1 1-1.732v-.217A3.25 3.25 0 0 1 21.129 7H15a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h10a2 2 0 0 1 1.855 1.25ZM20 10.05V11a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h1.5a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1v-.95c0-.016 0-.033.002-.05a.75.75 0 0 1 .642-.692l4.424-.632A2.25 2.25 0 0 0 28.5 6.45V4.75a1.496 1.496 0 0 0-1.5-1.5v3.2a.75.75 0 0 1-.644.742l-4.424.632A2.25 2.25 0 0 0 20 10.05ZM15 2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H15Z" fill="#fff"/>
|
||||
<path d="M2.5 2.5A.5.5 0 0 1 3 2h2.5a.5.5 0 0 1 .354.146l.646.647.646-.647A.5.5 0 0 1 7.5 2H10a.5.5 0 0 1 0 1H7.707L7 3.707V10h.5a.5.5 0 0 1 0 1H7v4.793l.707.707H10a.5.5 0 0 1 0 1H7.5a.5.5 0 0 1-.354-.146l-.646-.647-.646.647a.5.5 0 0 1-.354.146H3a.5.5 0 0 1 0-1h2.293L6 15.793V11h-.5a.5.5 0 0 1 0-1H6V3.707L5.293 3H3a.5.5 0 0 1-.5-.5Z" fill="#000"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="m5.793 3.5-.5-.5H3a.5.5 0 0 1 0-1h2.5a.5.5 0 0 1 .354.146l.145.146.501.5.646-.646A.5.5 0 0 1 7.5 2H10a.5.5 0 0 1 0 1H7.707L7 3.707V10h.5a.5.5 0 0 1 0 1H7v4.793l.707.707H10a.5.5 0 0 1 0 1H7.5a.5.5 0 0 1-.354-.146l-.646-.647-.5.5-.146.147a.5.5 0 0 1-.354.146H3a.5.5 0 0 1 0-1h2.293L6 15.793V11h-.5a.5.5 0 0 1 0-1H6V3.707L5.793 3.5Zm-.914.5L5 4.121v4.964a1.5 1.5 0 0 0 0 2.83v3.464l-.121.121H3a1.5 1.5 0 0 0 0 3h2.5a1.5 1.5 0 0 0 1-.382 1.5 1.5 0 0 0 1 .382H10a1.5 1.5 0 0 0 0-3H8.121L8 15.379v-3.464a1.5 1.5 0 0 0 0-2.83V4.121L8.121 4H10a1.5 1.5 0 0 0 0-3H7.5a1.5 1.5 0 0 0-1 .382A1.5 1.5 0 0 0 5.5 1H3a1.5 1.5 0 1 0 0 3h1.879Z" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
BIN
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_image.png
generated
vendored
Normal file
BIN
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_image.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@ -39,7 +39,28 @@
|
||||
"activate-previous-tab": "좌측 탭 활성화",
|
||||
"open-new-window": "새 비어있는 창 열기",
|
||||
"toggle-tray": "시스템 트레이에서 애플리케이션 보여주기/숨기기",
|
||||
"tabs-and-windows": "탭 & 창"
|
||||
"tabs-and-windows": "탭 & 창",
|
||||
"first-tab": "목록의 첫 번째 탭 활성화",
|
||||
"second-tab": "목록의 두 번째 탭 활성화",
|
||||
"third-tab": "목록의 세 번째 탭 활성화",
|
||||
"fourth-tab": "목록의 네 번째 탭 활성화",
|
||||
"fifth-tab": "목록의 다섯 번째 탭 활성화",
|
||||
"sixth-tab": "목록의 여섯 번째 탭 활성화",
|
||||
"seventh-tab": "목록의 일곱 번째 탭 활성화",
|
||||
"eight-tab": "목록의 여덟 번째 탭 활성화",
|
||||
"ninth-tab": "목록의 아홉 번째 탭 활성화",
|
||||
"last-tab": "목록의 마지막 탭 활성화",
|
||||
"dialogs": "대화 상자",
|
||||
"show-note-source": "\"노트 소스\" 대화 상자 표시",
|
||||
"show-options": "\"옵션\" 페이지 열기",
|
||||
"show-revisions": "\"노트 리비젼\" 대화 상자 표시",
|
||||
"show-recent-changes": "\"최근 변경 사항\" 대화 상자 표시",
|
||||
"show-sql-console": "\"SQL 콘솔\" 페이지 열기",
|
||||
"show-backend-log": "\"백엔드 로그\" 페이지 열기",
|
||||
"show-help": "내장 사용자 설명서 열기",
|
||||
"show-cheatsheet": "일반적인 키보드 형식의 팝업 표시",
|
||||
"text-note-operations": "텍스트 노트 작업",
|
||||
"add-link-to-text": "텍스트에 링크 추가를 위한 대화 상자 열기"
|
||||
},
|
||||
"hidden-subtree": {
|
||||
"zen-mode": "젠 모드",
|
||||
|
||||
@ -13,10 +13,6 @@ import BBlob from "./entities/bblob.js";
|
||||
import BRecentNote from "./entities/brecent_note.js";
|
||||
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
||||
|
||||
interface AttachmentOpts {
|
||||
includeContentLength?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Becca is a backend cache of all notes, branches, and attributes.
|
||||
* There's a similar frontend cache Froca, and share cache Shaca.
|
||||
@ -167,21 +163,18 @@ export default class Becca {
|
||||
return revision;
|
||||
}
|
||||
|
||||
getAttachment(attachmentId: string, opts: AttachmentOpts = {}): BAttachment | null {
|
||||
opts.includeContentLength = !!opts.includeContentLength;
|
||||
|
||||
const query = opts.includeContentLength
|
||||
? /*sql*/`SELECT attachments.*, LENGTH(blobs.content) AS contentLength
|
||||
FROM attachments
|
||||
JOIN blobs USING (blobId)
|
||||
WHERE attachmentId = ? AND isDeleted = 0`
|
||||
: /*sql*/`SELECT * FROM attachments WHERE attachmentId = ? AND isDeleted = 0`;
|
||||
getAttachment(attachmentId: string): BAttachment | null {
|
||||
const query = /*sql*/`\
|
||||
SELECT attachments.*, LENGTH(blobs.content) AS contentLength
|
||||
FROM attachments
|
||||
JOIN blobs USING (blobId)
|
||||
WHERE attachmentId = ? AND isDeleted = 0`;
|
||||
|
||||
return sql.getRows<AttachmentRow>(query, [attachmentId]).map((row) => new BAttachment(row))[0];
|
||||
}
|
||||
|
||||
getAttachmentOrThrow(attachmentId: string, opts: AttachmentOpts = {}): BAttachment {
|
||||
const attachment = this.getAttachment(attachmentId, opts);
|
||||
getAttachmentOrThrow(attachmentId: string): BAttachment {
|
||||
const attachment = this.getAttachment(attachmentId);
|
||||
if (!attachment) {
|
||||
throw new NotFoundError(`Attachment '${attachmentId}' has not been found.`);
|
||||
}
|
||||
|
||||
@ -61,10 +61,6 @@ interface ContentOpts {
|
||||
forceFrontendReload?: boolean;
|
||||
}
|
||||
|
||||
interface AttachmentOpts {
|
||||
includeContentLength?: boolean;
|
||||
}
|
||||
|
||||
interface Relationship {
|
||||
parentNoteId: string;
|
||||
childNoteId: string;
|
||||
@ -1102,31 +1098,23 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
||||
return sql.getRows<RevisionRow>("SELECT * FROM revisions WHERE noteId = ? ORDER BY revisions.utcDateCreated ASC", [this.noteId]).map((row) => new BRevision(row));
|
||||
}
|
||||
|
||||
getAttachments(opts: AttachmentOpts = {}) {
|
||||
opts.includeContentLength = !!opts.includeContentLength;
|
||||
// from testing, it looks like calculating length does not make a difference in performance even on large-ish DB
|
||||
// given that we're always fetching attachments only for a specific note, we might just do it always
|
||||
|
||||
const query = opts.includeContentLength
|
||||
? /*sql*/`SELECT attachments.*, LENGTH(blobs.content) AS contentLength
|
||||
FROM attachments
|
||||
JOIN blobs USING (blobId)
|
||||
WHERE ownerId = ? AND isDeleted = 0
|
||||
ORDER BY position`
|
||||
: /*sql*/`SELECT * FROM attachments WHERE ownerId = ? AND isDeleted = 0 ORDER BY position`;
|
||||
getAttachments() {
|
||||
const query = /*sql*/`\
|
||||
SELECT attachments.*, LENGTH(blobs.content) AS contentLength
|
||||
FROM attachments
|
||||
JOIN blobs USING (blobId)
|
||||
WHERE ownerId = ? AND isDeleted = 0
|
||||
ORDER BY position`;
|
||||
|
||||
return sql.getRows<AttachmentRow>(query, [this.noteId]).map((row) => new BAttachment(row));
|
||||
}
|
||||
|
||||
getAttachmentById(attachmentId: string, opts: AttachmentOpts = {}) {
|
||||
opts.includeContentLength = !!opts.includeContentLength;
|
||||
|
||||
const query = opts.includeContentLength
|
||||
? /*sql*/`SELECT attachments.*, LENGTH(blobs.content) AS contentLength
|
||||
FROM attachments
|
||||
JOIN blobs USING (blobId)
|
||||
WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`
|
||||
: /*sql*/`SELECT * FROM attachments WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`;
|
||||
getAttachmentById(attachmentId: string) {
|
||||
const query = /*sql*/`\
|
||||
SELECT attachments.*, LENGTH(blobs.content) AS contentLength
|
||||
FROM attachments
|
||||
JOIN blobs USING (blobId)
|
||||
WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`;
|
||||
|
||||
return sql.getRows<AttachmentRow>(query, [this.noteId, attachmentId]).map((row) => new BAttachment(row))[0];
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ function getAndCheckNote(noteId: string) {
|
||||
}
|
||||
|
||||
function getAndCheckAttachment(attachmentId: string) {
|
||||
const attachment = becca.getAttachment(attachmentId, { includeContentLength: true });
|
||||
const attachment = becca.getAttachment(attachmentId);
|
||||
|
||||
if (attachment) {
|
||||
return attachment;
|
||||
|
||||
@ -185,7 +185,7 @@ function register(router: Router) {
|
||||
|
||||
eu.route(router, "get", "/etapi/notes/:noteId/attachments", (req, res, next) => {
|
||||
const note = eu.getAndCheckNote(req.params.noteId);
|
||||
const attachments = note.getAttachments({ includeContentLength: true });
|
||||
const attachments = note.getAttachments();
|
||||
|
||||
res.json(attachments.map((attachment) => mappers.mapAttachmentToPojo(attachment)));
|
||||
});
|
||||
|
||||
@ -14,13 +14,13 @@ function getAttachmentBlob(req: Request) {
|
||||
function getAttachments(req: Request) {
|
||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||
|
||||
return note.getAttachments({ includeContentLength: true });
|
||||
return note.getAttachments();
|
||||
}
|
||||
|
||||
function getAttachment(req: Request) {
|
||||
const { attachmentId } = req.params;
|
||||
|
||||
return becca.getAttachmentOrThrow(attachmentId, { includeContentLength: true });
|
||||
return becca.getAttachmentOrThrow(attachmentId);
|
||||
}
|
||||
|
||||
function getAllAttachments(req: Request) {
|
||||
@ -28,7 +28,7 @@ function getAllAttachments(req: Request) {
|
||||
// one particular attachment is requested, but return all note's attachments
|
||||
|
||||
const attachment = becca.getAttachmentOrThrow(attachmentId);
|
||||
return attachment.getNote()?.getAttachments({ includeContentLength: true }) || [];
|
||||
return attachment.getNote()?.getAttachments() || [];
|
||||
}
|
||||
|
||||
function saveAttachment(req: Request) {
|
||||
|
||||
@ -80,7 +80,6 @@ const ALLOWED_OPTIONS = new Set<OptionNames>([
|
||||
"disableTray",
|
||||
"customSearchEngineName",
|
||||
"customSearchEngineUrl",
|
||||
"promotedAttributesOpenInRibbon",
|
||||
"editedNotesOpenInRibbon",
|
||||
"locale",
|
||||
"formattingLocale",
|
||||
|
||||
@ -27,7 +27,8 @@ async function register(app: express.Application) {
|
||||
appType: "custom",
|
||||
cacheDir: path.join(srcRoot, "../../.cache/vite"),
|
||||
base: `/${assetUrlFragment}/`,
|
||||
root: clientDir
|
||||
root: clientDir,
|
||||
css: { devSourcemap: true }
|
||||
});
|
||||
app.use(`/${assetUrlFragment}/`, (req, res, next) => {
|
||||
req.url = `/${assetUrlFragment}` + req.url;
|
||||
|
||||
@ -764,7 +764,7 @@ function updateNoteData(noteId: string, content: string, attachments: Attachment
|
||||
note.setContent(newContent, { forceFrontendReload });
|
||||
|
||||
if (attachments?.length > 0) {
|
||||
const existingAttachmentsByTitle = toMap(note.getAttachments({ includeContentLength: false }), "title");
|
||||
const existingAttachmentsByTitle = toMap(note.getAttachments(), "title");
|
||||
|
||||
for (const { attachmentId, role, mime, title, position, content } of attachments) {
|
||||
const existingAttachment = existingAttachmentsByTitle.get(title);
|
||||
|
||||
@ -129,7 +129,6 @@ const defaultOptions: DefaultOption[] = [
|
||||
{ name: "logRetentionDays", value: "90", isSynced: false }, // default 90 days
|
||||
{ name: "customSearchEngineName", value: "DuckDuckGo", isSynced: true },
|
||||
{ name: "customSearchEngineUrl", value: "https://duckduckgo.com/?q={keyword}", isSynced: true },
|
||||
{ name: "promotedAttributesOpenInRibbon", value: "true", isSynced: true },
|
||||
{ name: "editedNotesOpenInRibbon", value: "true", isSynced: true },
|
||||
{ name: "mfaEnabled", value: "false", isSynced: false },
|
||||
{ name: "mfaMethod", value: "totp", isSynced: false },
|
||||
|
||||
@ -18,8 +18,8 @@
|
||||
"title": "Organizace",
|
||||
"note_structure_title": "Struktura poznámek",
|
||||
"note_structure_description": "Poznámky lze uspořádat hierarchicky. Není třeba používat složky, protože každá poznámka může obsahovat podpoznámky. Jednu poznámku lze přidat na více míst v hierarchii.",
|
||||
"attributes_title": "Poznámky k štítkům a vztahům",
|
||||
"attributes_description": "Využijte vztahy mezi poznámkami nebo přidejte štítky pro snadnou kategorizaci. Pomocí propagovaných atributů zadejte strukturované informace, které lze použít v tabulkách.",
|
||||
"attributes_title": "Poznámky k štítkům a vazbám",
|
||||
"attributes_description": "Využijte vazby mezi poznámkami nebo přidejte štítky pro snadnou kategorizaci. Pomocí propagovaných atributů zadejte strukturované informace, které lze použít v různých tabulkách.",
|
||||
"hoisting_title": "Pracovní prostředí a hoisting",
|
||||
"hoisting_description": "Snadno oddělte své osobní a pracovní poznámky tím, že je seskupíte do pracovního prostoru, který zaměří strom poznámek tak, aby zobrazoval pouze konkrétní sadu poznámek."
|
||||
},
|
||||
|
||||
@ -19,7 +19,9 @@
|
||||
"note_structure_title": "Notizstruktur",
|
||||
"attributes_title": "Notiz Labels und Beziehungen",
|
||||
"note_structure_description": "Notizen lassen sich hierarchisch anordnen. Ordner sind nicht nötig, da jede Notiz Unternotizen enthalten kann. Eine einzelne Notiz kann an mehreren Stellen in der Hierarchie hinzugefügt werden.",
|
||||
"hoisting_description": "Trennen Sie Ihre persönlichen und beruflichen Notizen ganz einfach, indem Sie sie in einem Arbeitsbereich gruppieren. Dadurch wird Ihre Notizstruktur so fokussiert, dass nur ein bestimmter Satz von Notizen angezeigt wird."
|
||||
"hoisting_description": "Trennen Sie Ihre persönlichen und beruflichen Notizen ganz einfach, indem Sie sie in einem Arbeitsbereich gruppieren. Dadurch wird Ihre Notizstruktur so fokussiert, dass nur ein bestimmter Satz von Notizen angezeigt wird.",
|
||||
"hoisting_title": "Arbeitsbereiche und Fokusansicht",
|
||||
"attributes_description": "Verwenden Sie Beziehungen zwischen Notizen oder fügen Sie Beschriftungen hinzu, um die Kategorisierung zu vereinfachen. Verwenden Sie hervorgehobene Attribute, um strukturierte Informationen einzugeben, die in Tabellen und Boards verwendet werden können."
|
||||
},
|
||||
"productivity_benefits": {
|
||||
"revisions_title": "Notizrevisionen",
|
||||
@ -29,7 +31,12 @@
|
||||
"jump_to_title": "Schnellsuche und Kommandos",
|
||||
"search_title": "Leistungsstarke Suche",
|
||||
"web_clipper_title": "Web clipper",
|
||||
"revisions_content": "Notizen werden regelmäßig im Hintergrund gespeichert und Revisionen können zur Überprüfung oder zum Rückgängigmachen versehentlicher Änderungen verwendet werden. Revisionen können auch bei Bedarf erstellt werden."
|
||||
"revisions_content": "Notizen werden regelmäßig im Hintergrund gespeichert und Revisionen können zur Überprüfung oder zum Rückgängigmachen versehentlicher Änderungen verwendet werden. Revisionen können auch bei Bedarf erstellt werden.",
|
||||
"sync_content": "Verwenden Sie eine selbst gehostete oder Cloud-Instanz, um Ihre Notizen ganz einfach auf mehreren Geräten zu synchronisieren und über eine WebApp von Ihrem mobilen Gerät aus darauf zuzugreifen.",
|
||||
"protected_notes_content": "Halten Sie vertrauliche Informationen sicher, indem Sie Notizen verschlüsseln und mit einem Passwort schützen.",
|
||||
"jump_to_content": "Springen Sie schnell zu Notizen oder UI-Befehlen in der gesamten Hierarchie, indem Sie nach ihrem Titel suchen. Dank Fuzzy-Matching finden Sie auch Treffer bei Tippfehlern oder leicht abweichenden Schreibweisen.",
|
||||
"search_content": "Oder durchsuchen Sie den Inhalt von Notizen und grenzen Sie die Suche ein, indem Sie nach übergeordneten Notizen oder der Hierarchieebene filtern.",
|
||||
"web_clipper_content": "Webseiten oder Screenshots direkt in Trilium speichern – mit der Web Clipper Browser-Erweiterung."
|
||||
},
|
||||
"note_types": {
|
||||
"text_title": "Text Notizen",
|
||||
@ -38,15 +45,38 @@
|
||||
"mermaid_title": "Mermaid Diagramm",
|
||||
"mindmap_title": "Mind Map",
|
||||
"text_description": "Die Notizen werden mit einem visuellen Editor (WYSIWYG) bearbeitet, der Tabellen, Bilder, mathematische Ausdrücke und Code-Blöcke mit Syntaxhervorhebung unterstützt. Formatieren Sie den Text schnell mit einer Markdown-ähnlichen Syntax oder mit Slash-Befehlen.",
|
||||
"code_description": "Große Quellcode- oder Skriptdateien werden mit einem speziellen Editor bearbeitet, der Syntaxhervorhebung für viele Programmiersprachen und diverse Farbschemata bietet."
|
||||
"code_description": "Große Quellcode- oder Skriptdateien werden mit einem speziellen Editor bearbeitet, der Syntaxhervorhebung für viele Programmiersprachen und diverse Farbschemata bietet.",
|
||||
"title": "Verschiedene Darstellungsformen für Ihre Informationen",
|
||||
"file_title": "Datei Notizen",
|
||||
"file_description": "Betten Sie Multimedia-Dateien wie PDFs, Bilder und Videos mit einer Vorschau innerhalb der Anwendung ein.",
|
||||
"canvas_description": "Ordnen Sie Formen, Bilder und Text auf einer unendlichen Leinwand an, indem Sie dieselbe Technologie verwenden, die auch hinter excalidraw.com steckt. Ideal für Diagramme, Skizzen und visuelle Planung.",
|
||||
"mermaid_description": "Erstellen Sie Fluss-, Klassen-, Sequenz- sowie Gantt-Diagramme und vieles mehr mit der Mermaid-Syntax.",
|
||||
"mindmap_description": "Strukturieren Sie Ihre Gedanken visuell oder nutzen Sie eine Brainstorming-Sitzung.",
|
||||
"others_list": "und andere: <0>note map</0>, <1>relation map</1>, <2>saved searches</2>, <3>render note</3>, and <4>web views</4>."
|
||||
},
|
||||
"extensibility_benefits": {
|
||||
"import_export_title": "Import/Export",
|
||||
"scripting_title": "Erweitertes Scripting",
|
||||
"api_title": "REST API"
|
||||
"api_title": "REST API",
|
||||
"title": "Freigabe & Erweiterung",
|
||||
"import_export_description": "Einfache Interaktion mit anderen Anwendungen mithilfe von Markdown, ENEX und OML Formaten.",
|
||||
"share_title": "Notizen im Web teilen",
|
||||
"share_description": "Wenn Sie über einen Server verfügen, können Sie diesen nutzen, um einen Teil Ihrer Notizen mit anderen zu teilen.",
|
||||
"scripting_description": "Erstellen Sie Ihre eigenen Integrationen innerhalb von Trilium mit benutzerdefinierten Widgets oder serverseitiger Logik.",
|
||||
"api_description": "Nutzen Sie die integrierte REST-API, um flexibel und automatisiert mit Trilium zu interagieren."
|
||||
},
|
||||
"collections": {
|
||||
"calendar_title": "Kalender"
|
||||
"calendar_title": "Kalender",
|
||||
"title": "Sammlungen",
|
||||
"calendar_description": "Organisieren Sie Ihre privaten oder beruflichen Termine mithilfe eines Kalenders, der ganztägige und mehrtägige Termine unterstützt. Verschaffen Sie sich mit der Wochen-, Monats- und Jahresansicht einen Überblick über Ihre Termine. Einfaches Hinzufügen oder Verschieben von Terminen.",
|
||||
"table_title": "Tabelle",
|
||||
"table_description": "Zeigen Sie Informationen zu Notizen in einer tabellarischen Ansicht an und bearbeiten Sie diese. Dabei stehen verschiedene Spaltentypen wie Text, Zahlen, Kontrollkästchen, Datum sowie Uhrzeit, Links und Farben zur Verfügung, auch Beziehungen werden unterstützt. Optional können Sie die Notizen innerhalb einer Baumhierarchie in der Tabelle anzeigen.",
|
||||
"board_title": "Kanban-Board",
|
||||
"board_description": "Organisieren Sie Aufgaben und Projektstatus in einem Kanban-Board und ändern Sie den Status ganz einfach per Drag & Drop.",
|
||||
"geomap_title": "Geokarte",
|
||||
"geomap_description": "Planen Sie Ihren Urlaub oder markieren Sie Ihre Sehenswürdigkeiten direkt auf einer geografischen Karte mit individuellen Markierungen. Zeigen Sie aufgezeichnete GPX-Tracks an, um Reiserouten zu verfolgen.",
|
||||
"presentation_title": "Präsentation",
|
||||
"presentation_description": "Organisieren Sie Informationen in Folien und präsentieren Sie diese im Vollbildmodus mit flüssigen Übergängen. Die Folien können als PDF gespeichert und einfach geteilt werden."
|
||||
},
|
||||
"download_helper_desktop_macos": {
|
||||
"quick_start": "Installieren mit Homebrew:",
|
||||
@ -69,7 +99,13 @@
|
||||
"download_nixpkgs": "nixpkgs",
|
||||
"download_zip": "Portable (.zip)",
|
||||
"download_flatpak": ".flatpak",
|
||||
"download_rpm": ".rpm"
|
||||
"download_rpm": ".rpm",
|
||||
"title_x64": "Linux 64-bit",
|
||||
"title_arm64": "Linux on ARM",
|
||||
"description_x64": "Für die meisten Linux-Distributionen, kompatibel mit der x86_64-Architektur.",
|
||||
"description_arm64": "Für ARM-basierte Linux-Distributionen, kompatibel mit der aarch64-Architektur.",
|
||||
"quick_start": "Wählen Sie je nach Ihrer Distribution ein geeignetes Paketformat aus:",
|
||||
"download_deb": ".deb"
|
||||
},
|
||||
"download_helper_server_linux": {
|
||||
"title": "Self-hosted auf Linux",
|
||||
@ -83,5 +119,82 @@
|
||||
"description": "Trilium Notes wird auf PikaPods gehostet, einem kostenpflichtigen Dienst für einfachen Zugriff und Verwaltung. Es besteht keine direkte Verbindung zum Trilium-Team.",
|
||||
"download_pikapod": "Auf PikaPods installieren",
|
||||
"download_triliumcc": "Alternativ siehe trilium.cc"
|
||||
},
|
||||
"faq": {
|
||||
"title": "Häufig gestellte Fragen",
|
||||
"mobile_question": "Gibt es eine mobile Applikation?",
|
||||
"mobile_answer": "Derzeit gibt es keine offizielle mobile Anwendung. Wenn Sie jedoch über eine Serverinstanz verfügen, können Sie über einen Webbrowser darauf zugreifen und sie sogar als PWA installieren. Für Android gibt es eine inoffizielle Anwendung namens TriliumDroid, die sogar offline funktioniert (genau wie ein Desktop-Client).",
|
||||
"database_question": "Wo werden die Daten gespeichert?",
|
||||
"database_answer": "Alle Ihre Notizen werden in einer SQLite-Datenbank in einem Anwendungsordner gespeichert. Der Grund, warum Trilium eine Datenbank anstelle von einfachen Textdateien verwendet, liegt sowohl in der Leistung als auch darin, dass einige Funktionen, wie z. B. Klone (gleiche Notiz an mehreren Stellen im Baum), viel schwieriger zu implementieren wären. Um den Anwendungsordner zu finden, gehen Sie einfach zum Fenster „Über“.",
|
||||
"server_question": "Benötige ich einen Server um Trilium zu nutzen?",
|
||||
"server_answer": "Nein, der Server ermöglicht den Zugriff über einen Webbrowser und verwaltet die Synchronisierung, wenn Sie mehrere Geräte haben. Um loszulegen, reicht es aus, die Desktop-Anwendung herunterzuladen und zu verwenden.",
|
||||
"scaling_question": "Wie gut skaliert die Anwendung bei einer großen Anzahl von Notizen?",
|
||||
"scaling_answer": "Je nach Nutzung sollte die Anwendung min. 100.000 Notizen problemlos verarbeiten können. Beachten Sie, dass der Synchronisierungsvorgang manchmal fehlschlagen kann, wenn viele große Dateien (1 GB pro Datei) hochgeladen werden, da Trilium eher als Wissensdatenbank-Anwendung und nicht als Dateispeicher (wie beispielsweise NextCloud) konzipiert ist.",
|
||||
"network_share_question": "Kann ich meine Datenbank über ein Netzlaufwerk freigeben?",
|
||||
"network_share_answer": "Nein, es ist im Allgemeinen keine gute Idee, eine SQLite-Datenbank über ein Netzlaufwerk freizugeben. Auch wenn dies manchmal funktionieren mag, besteht die Gefahr, dass die Datenbank aufgrund unvollständiger Dateisperren über ein Netzwerk beschädigt wird.",
|
||||
"security_question": "Wie werden meine Daten geschützt?",
|
||||
"security_answer": "Standardmäßig sind Notizen nicht verschlüsselt und können direkt aus der Datenbank gelesen werden. Sobald eine Notiz als verschlüsselt markiert ist, wird diese mit AES-128-CBC verschlüsselt."
|
||||
},
|
||||
"final_cta": {
|
||||
"title": "Sind Sie bereit, um mit Trilium Notes zu starten?",
|
||||
"description": "Baue dein persönliches Wissensarchiv mit leistungsstarken Funktionen und vollständigem Datenschutz auf.",
|
||||
"get_started": "Loslegen"
|
||||
},
|
||||
"components": {
|
||||
"link_learn_more": "Mehr erfahren..."
|
||||
},
|
||||
"download_now": {
|
||||
"text": "Herunterladen ",
|
||||
"platform_big": "v{{version}} für {{platform}}",
|
||||
"platform_small": "für {{platform}}",
|
||||
"linux_big": "v{{version}} für Linux",
|
||||
"linux_small": "für Linux",
|
||||
"more_platforms": "Weitere Plattformen & Server-Einrichtung"
|
||||
},
|
||||
"header": {
|
||||
"get-started": "Loslegen",
|
||||
"documentation": "Dokumentation",
|
||||
"support-us": "Unterstützt uns"
|
||||
},
|
||||
"footer": {
|
||||
"copyright_and_the": " und die ",
|
||||
"copyright_community": "Community"
|
||||
},
|
||||
"social_buttons": {
|
||||
"github": "GitHub",
|
||||
"github_discussions": "GitHub Discussions",
|
||||
"matrix": "Matrix",
|
||||
"reddit": "Reddit"
|
||||
},
|
||||
"support_us": {
|
||||
"title": "Unterstütze uns",
|
||||
"financial_donations_title": "Geldspenden",
|
||||
"financial_donations_description": "Trilium wurde mit <Link>Hunderten von Arbeitsstunden</Link> entwickelt und wird mit diesem Aufwand auch gewartet. Ihre Unterstützung sorgt dafür, dass es Open Source bleibt, verbessert die Funktionen und deckt Kosten wie das Hosting.",
|
||||
"financial_donations_cta": "Bitte unterstützen Sie den Hauptentwickler (<Link>eliandoran</Link>) der Anwendung über:",
|
||||
"github_sponsors": "GitHub Sponsoren",
|
||||
"paypal": "PayPal",
|
||||
"buy_me_a_coffee": "Buy Me A Coffee"
|
||||
},
|
||||
"contribute": {
|
||||
"title": "Weitere Möglichkeiten zum Mitwirken",
|
||||
"way_translate": "Übersetzen Sie die Anwendung über <Link>Weblate</Link> in Ihre Muttersprache.",
|
||||
"way_community": "Interagieren Sie mit der Community auf <Discussions>GitHub Discussions</Discussions> oder auf <Matrix>Matrix</Matrix>.",
|
||||
"way_reports": "Fehlfunktionen über <Link>GitHub-Issues</Link> melden.",
|
||||
"way_document": "Verbessern Sie die Dokumentation, indem Sie uns auf Lücken hinweisen oder durch eigene Beiträge wie Anleitungen, FAQs oder Tutorials unterstützen.",
|
||||
"way_market": "Weitersagen: Teilen Sie Trilium Notes mit Freunden, in Blogs und sozialen Medien."
|
||||
},
|
||||
"404": {
|
||||
"title": "404: Not Found",
|
||||
"description": "Die gesuchte Seite konnte nicht gefunden werden. Möglicherweise wurde sie gelöscht oder die URL ist falsch."
|
||||
},
|
||||
"download_helper_desktop_windows": {
|
||||
"title_x64": "Windows 64-bit",
|
||||
"title_arm64": "Windows on ARM",
|
||||
"description_x64": "Kompatibel mit Intel- oder AMD-Geräten unter Windows 10 und 11.",
|
||||
"description_arm64": "Kompatibel mit ARM-Geräten (z. B. mit Qualcomm Snapdragon).",
|
||||
"quick_start": "Installation über Winget:",
|
||||
"download_exe": "Download Installer (.exe)",
|
||||
"download_zip": "Portable (.zip)",
|
||||
"download_scoop": "Scoop"
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,13 @@
|
||||
"sync_title": "동기화",
|
||||
"sync_content": "자체 호스팅 또는 클라우드 인스턴스를 이용하여 여러 기기 사이에서 노트를 쉽게 동기화하고 PWA를 통해 모바일 폰에서 접근할 수 있습니다.",
|
||||
"protected_notes_title": "보호된 노트",
|
||||
"protected_notes_content": "노트를 암호화하고 비밀번호로 보호되는 세션 뒤에 잠궈 민감한 개인 정보를 보호하세요."
|
||||
"protected_notes_content": "노트를 암호화하고 비밀번호로 보호되는 세션 뒤에 잠궈 민감한 개인 정보를 보호하세요.",
|
||||
"jump_to_title": "빠른 검색 및 명령어",
|
||||
"jump_to_content": "제목을 검색하고 오타나 약간의 차이를 설명하기 위해 퍼지 매칭을 통해 계층 전반에 걸쳐 노트나 UI 명령으로 빠르게 이동하세요.",
|
||||
"search_title": "상세 검색",
|
||||
"search_content": "또는 노트 내부에서 문자를 검색하거나 부모 노트 또는 단계별로 필터링 하는 등 검색 범위를 조정하세요.",
|
||||
"web_clipper_title": "웹 클리퍼",
|
||||
"web_clipper_content": "웹 클리퍼 확장 프로그램을 사용하여 웹 페이지(또는 스크린샷)를 Trilium으로 가져와 문서에 사용하세요."
|
||||
},
|
||||
"header": {
|
||||
"get-started": "시작하기",
|
||||
@ -79,5 +85,10 @@
|
||||
"title_arm64": "ARM 기반 리눅스",
|
||||
"description_x64": "대부분의 리눅스 배포판에서 x86_64 아키텍처와 호환됩니다.",
|
||||
"description_arm64": "ARM 기반 리눅스 배포판에서 aarch64 아키텍처와 호환됩니다."
|
||||
},
|
||||
"note_types": {
|
||||
"text_title": "텍스트 노트",
|
||||
"text_description": "노트는 WYSIWYG 편집기를 사용하며 표, 이미지, 수학 표현식, 구문 강조 기능의 코드 블록을 지원합니다. 특수문자를 사용한 마크다운 유사 구문이나 슬래시(/) 명령으로 텍스트 서식을 빠르게 지정할 수 있습니다.",
|
||||
"code_title": "코드 노트"
|
||||
}
|
||||
}
|
||||
|
||||
157
docs/User Guide/!!!meta.json
vendored
157
docs/User Guide/!!!meta.json
vendored
@ -2380,6 +2380,20 @@
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "IakOLONlIfGI",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "yTjUdsOi4CIE",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "iconClass",
|
||||
@ -2393,20 +2407,6 @@
|
||||
"value": "keyboard-shortcuts",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "IakOLONlIfGI",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "yTjUdsOi4CIE",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -5207,45 +5207,59 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "MMiBEQljMQh2",
|
||||
"value": "DvdZhoQZY9Yd",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "zEY4DaJG4YT5",
|
||||
"value": "MMiBEQljMQh2",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "iPIMuisry3hd",
|
||||
"value": "zEY4DaJG4YT5",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "TBwsyfadTA18",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "oiVPnW8QfnvS",
|
||||
"value": "iPIMuisry3hd",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "QrtTYPmdd1qq",
|
||||
"value": "oiVPnW8QfnvS",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "eIg8jdvaoNNd",
|
||||
"value": "QrtTYPmdd1qq",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "eIg8jdvaoNNd",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
@ -5259,20 +5273,6 @@
|
||||
"value": "bx bxs-keyboard",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "DvdZhoQZY9Yd",
|
||||
"isInheritable": false,
|
||||
"position": 90
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "TBwsyfadTA18",
|
||||
"isInheritable": false,
|
||||
"position": 100
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -6244,6 +6244,13 @@
|
||||
"value": "",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "5wZallV2Qo1t",
|
||||
"isInheritable": false,
|
||||
"position": 220
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -6914,6 +6921,13 @@
|
||||
"value": "general-formatting",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "5wZallV2Qo1t",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@ -8423,6 +8437,81 @@
|
||||
"dataFileName": "1_Text Snippets_image.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"isClone": false,
|
||||
"noteId": "5wZallV2Qo1t",
|
||||
"notePath": [
|
||||
"pOsGYCXsbNQG",
|
||||
"KSZ04uQ2D1St",
|
||||
"iPIMuisry3hd",
|
||||
"gLt3vA97tMcp",
|
||||
"5wZallV2Qo1t"
|
||||
],
|
||||
"title": "Format Painter",
|
||||
"notePosition": 30,
|
||||
"prefix": null,
|
||||
"isExpanded": false,
|
||||
"type": "text",
|
||||
"mime": "text/html",
|
||||
"attributes": [
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "gLt3vA97tMcp",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "MI26XDLSAlCD",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
"value": "format-painter",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "iconClass",
|
||||
"value": "bx bxs-paint-roll",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
"dataFileName": "Format Painter.md",
|
||||
"attachments": [
|
||||
{
|
||||
"attachmentId": "OY9JmG8zdGm5",
|
||||
"title": "image.png",
|
||||
"role": "image",
|
||||
"mime": "image/png",
|
||||
"position": 10,
|
||||
"dataFileName": "Format Painter_image.png"
|
||||
},
|
||||
{
|
||||
"attachmentId": "qEJy5SJMsPUh",
|
||||
"title": "e144e96df9.svg",
|
||||
"role": "image",
|
||||
"mime": "image/svg+xml",
|
||||
"position": 10,
|
||||
"dataFileName": "Format Painter_e144e96df9.svg"
|
||||
},
|
||||
{
|
||||
"attachmentId": "vZqf8QJ80XRF",
|
||||
"title": "746436a2e1.svg",
|
||||
"role": "image",
|
||||
"mime": "image/svg+xml",
|
||||
"position": 10,
|
||||
"dataFileName": "Format Painter_746436a2e1.svg"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@ -16,7 +16,7 @@ Fore more information see <a class="reference-link" href="Text/Formatting%20too
|
||||
|
||||
Here's a list of various features supported by text notes:
|
||||
|
||||
<table><thead><tr><th>Dedicated article</th><th>Feature</th></tr></thead><tbody><tr><td><a class="reference-link" href="Text/General%20formatting.md">General formatting</a></td><td><ul><li>Headings (section titles, paragraph)</li><li>Font size</li><li>Bold, italic, underline, strike-through</li><li>Superscript, subscript</li><li>Font color & background color</li><li>Remove formatting</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Lists.md">Lists</a></td><td><ul><li>Bulleted lists</li><li>Numbered lists</li><li>To-do lists</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Block%20quotes%20%26%20admonitions.md">Block quotes & admonitions</a></td><td><ul><li>Block quotes</li><li>Admonitions</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Tables.md">Tables</a></td><td><ul><li>Basic tables</li><li>Merging cells</li><li>Styling tables and cells.</li><li>Table captions</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Developer-specific%20formatting.md">Developer-specific formatting</a></td><td><ul><li>Inline code</li><li>Code blocks</li><li>Keyboard shortcuts</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Footnotes.md">Footnotes</a></td><td><ul><li>Footnotes</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Images.md">Images</a></td><td><ul><li>Images</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Links.md">Links</a></td><td><ul><li>External links</li><li>Internal Trilium links</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Include%20Note.md">Include Note</a></td><td><ul><li>Include note</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Insert%20buttons.md">Insert buttons</a></td><td><ul><li>Symbols</li><li><a class="reference-link" href="Text/Math%20Equations.md">Math Equations</a></li><li>Mermaid diagrams</li><li>Horizontal ruler</li><li>Page break</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Other%20features.md">Other features</a></td><td><ul><li>Indentation<ul><li>Markdown import</li></ul></li><li><a class="reference-link" href="Text/Cut%20to%20subnote.md">Cut to subnote</a></li></ul></td></tr><tr><td><a class="reference-link" href="Text/Premium%20features.md">Premium features</a></td><td><ul><li><a class="reference-link" href="Text/Premium%20features/Slash%20Commands.md">Slash Commands</a></li><li><a class="reference-link" href="../Advanced%20Usage/Templates.md">Templates</a></li></ul></td></tr></tbody></table>
|
||||
<table><thead><tr><th>Dedicated article</th><th>Feature</th></tr></thead><tbody><tr><td><a class="reference-link" href="Text/General%20formatting.md">General formatting</a></td><td><ul><li data-list-item-id="e04c84d59d44645ee89b2a8541ed99f90">Headings (section titles, paragraph)</li><li data-list-item-id="e39d25bd3d8bd06185b9d259e5827d451">Font size</li><li data-list-item-id="e1f7e2a2f4b03449d82bdf5b5c6ea8d44">Bold, italic, underline, strike-through</li><li data-list-item-id="e3decae72884f65b4d538151b6a297072">Superscript, subscript</li><li data-list-item-id="e59adf00fef65304c163ae190fac5e92a">Font color & background color</li><li data-list-item-id="ed3f09156147a2769e91db111c76376e2">Remove formatting</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Lists.md">Lists</a></td><td><ul><li data-list-item-id="ee87806a913900d85d8f018af81f41df8">Bulleted lists</li><li data-list-item-id="e3ae314e365fa418ca6e0f061d63834c5">Numbered lists</li><li data-list-item-id="ee84e08694165f95430046cb34f4cd123">To-do lists</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Block%20quotes%20%26%20admonitions.md">Block quotes & admonitions</a></td><td><ul><li data-list-item-id="e2892dc35a0d4b7ad65daffb8f9404daa">Block quotes</li><li data-list-item-id="e7297e3ad1002f8de15aa0bd66c6f3f22">Admonitions</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Tables.md">Tables</a></td><td><ul><li data-list-item-id="eb358a4567d93f66004f4195df2dda05a">Basic tables</li><li data-list-item-id="e6135a555d6c63c30e4b84806a4870830">Merging cells</li><li data-list-item-id="e29ac76563d0998b28fb1baf94dbdac8c">Styling tables and cells.</li><li data-list-item-id="e372446e81fdedada64b8bed89ca93d1a">Table captions</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Developer-specific%20formatting.md">Developer-specific formatting</a></td><td><ul><li data-list-item-id="eb260b76afcbc07bd9d4ceec4e000e8a0">Inline code</li><li data-list-item-id="e9864352286369ebe7b41c1599f498de8">Code blocks</li><li data-list-item-id="ee62fb9ed7f349178e8f2a2bd9ec8cd74">Keyboard shortcuts</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Footnotes.md">Footnotes</a></td><td><ul><li data-list-item-id="edf62ec004eff35cfcb7e361deef19aaf">Footnotes</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Images.md">Images</a></td><td><ul><li data-list-item-id="ebe6277e643041403489c3ceb30c36f7f">Images</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Links.md">Links</a></td><td><ul><li data-list-item-id="e3f988be2f259bb40607cb61541955395">External links</li><li data-list-item-id="e3f91cc4f0cccd2c077cc306bacd68ef2">Internal Trilium links</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Include%20Note.md">Include Note</a></td><td><ul><li data-list-item-id="eac8015a64bce7b749cc67d1599062007">Include note</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Insert%20buttons.md">Insert buttons</a></td><td><ul><li data-list-item-id="e5cdf5d3885ec0ea67f924b4b8fe5c483">Symbols</li><li data-list-item-id="e95082e6642ed5b1eec6e4e116b899a40"><a class="reference-link" href="Text/Math%20Equations.md">Math Equations</a></li><li data-list-item-id="ecbef6a358a5b8d27f0d3e08bbc750aa9">Mermaid diagrams</li><li data-list-item-id="e6e97ee14dd29b7ccf53227107e5dc72d">Horizontal ruler</li><li data-list-item-id="e6198c7c535c249faec2e8906775f11de">Page break</li></ul></td></tr><tr><td><a class="reference-link" href="Text/Other%20features.md">Other features</a></td><td><ul><li data-list-item-id="e0c14456cb83d483b07ea432ef9d4728e">Indentation<ul><li data-list-item-id="e2029812c5e105c595590f70ee227631e">Markdown import</li></ul></li><li data-list-item-id="ea1ee012286e05190c89c9f4e64cf2036"><a class="reference-link" href="Text/Cut%20to%20subnote.md">Cut to subnote</a></li></ul></td></tr><tr><td><a class="reference-link" href="Text/Premium%20features.md">Premium features</a></td><td><ul><li data-list-item-id="e1ab173193a533ccf33dccfd0cb916f1f"><a class="reference-link" href="Text/Premium%20features/Slash%20Commands.md">Slash Commands</a></li><li data-list-item-id="e564b978c09fe5adf476b331b1e0640e3"><a class="reference-link" href="../Advanced%20Usage/Templates.md">Templates</a></li><li data-list-item-id="e756306c31d9beffbba3820b6d1b9bc61"><a class="reference-link" href="Text/Premium%20features/Format%20Painter.md">Format Painter</a></li></ul></td></tr></tbody></table>
|
||||
|
||||
## Read-Only vs. Editing Mode
|
||||
|
||||
|
||||
@ -79,6 +79,10 @@ Note that heading styles are not taken into consideration, these must be manuall
|
||||
|
||||
When pasting content that comes with undesired formatting, an alternative to pasting and then removing formatting is pasting as plain text via <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd>.
|
||||
|
||||
## Format painter
|
||||
|
||||
The <a class="reference-link" href="Premium%20features/Format%20Painter.md">Format Painter</a> allows users to copy the formatting of text (such as bold, italic, Strikethrough, etc.) and apply it to other parts of the document. It helps maintain consistent formatting and accelerates the creation of rich content.
|
||||
|
||||
## Support for Markdown
|
||||
|
||||
When exported to <a class="reference-link" href="../../Basic%20Concepts%20and%20Features/Import%20%26%20Export/Markdown.md">Markdown</a>, most of the general formatting is maintained such as headings, bold, italic, underline, etc.
|
||||
20
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter.md
vendored
Normal file
20
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Format Painter
|
||||
<figure class="image image-style-align-right"><img style="aspect-ratio:220/76;" src="Format Painter_image.png" width="220" height="76"></figure>
|
||||
|
||||
> [!NOTE]
|
||||
> This is a premium feature of the editor we are using (CKEditor) and we benefit from it thanks to an written agreement with the team. See <a class="reference-link" href="../Premium%20features.md">Premium features</a> for more information.
|
||||
|
||||
The Format Painter is a feature in text notes that allows users to copy the formatting of text (such as **bold**, _italic_, ~~Strikethrough~~, etc.) and apply it to other parts of the document. It helps maintain consistent formatting and accelerates the creation of rich content.
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
Click the text that you want to copy the formatting from and use the paint formatting toolbar button (<img class="image_resized" style="aspect-ratio:150/150;width:2.7%;" src="Format Painter_746436a2e1.svg" alt="Format painter" width="150" height="150">) to copy the style. Then select the target text with your mouse to apply the formatting.
|
||||
|
||||
* **To copy the formatting**: Place the cursor inside a text with some formatting and click the paint formatting toolbar button. Notice that the mouse cursor changes to the <img class="image_resized" style="aspect-ratio:30/20;width:3.64%;" src="Format Painter_e144e96df9.svg" alt="Format painter text cursor" width="30" height="20">.
|
||||
* **To paint with the copied formatting**: Click any word in the document and the new formatting will be applied. Alternatively, instead of clicking a single word, you can select a text fragment (like an entire paragraph). Notice that the cursor will go back to the default one after the formatting is applied.
|
||||
* **To keep painting using the same formatting**: Open the toolbar dropdown and enable the continuous painting mode. Once copied, the same formatting can be applied multiple times in different places until the paint formatting button is clicked (the cursor will then revert to the regular one).
|
||||
|
||||
## Limitations
|
||||
|
||||
1. Painting with block-level formatting (like headings or image styles) is not supported yet. This is because, in <a class="reference-link" href="../../../Advanced%20Usage/Technologies%20used/CKEditor.md">CKEditor</a>, they are considered a part of the content rather than text formatting.
|
||||
2. When applying formatting to words, spaces or other Western punctuation are used as word boundaries, which prevents proper handling of languages that do not use space-based word segmentation.
|
||||
1
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_746436a2e1.svg
vendored
Normal file
1
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_746436a2e1.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M3 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1z"/><path d="M16 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 16 6.449z"/></svg>
|
||||
|
After Width: | Height: | Size: 386 B |
7
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_e144e96df9.svg
vendored
Normal file
7
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_e144e96df9.svg
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31 20" width="30" height="20">
|
||||
<path d="M14 3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1V3Z" fill="#000"/>
|
||||
<path d="M27 3.25a1.5 1.5 0 0 1 1.5 1.5v1.7a2.25 2.25 0 0 1-1.932 2.226l-4.424.632a.75.75 0 0 0-.644.743V11a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H20a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1v-.95a2.25 2.25 0 0 1 1.932-2.226l4.424-.632A.75.75 0 0 0 27 6.449V3.25Z" fill="#000"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.855 2.25H27a2.5 2.5 0 0 1 2.5 2.5v1.7a3.25 3.25 0 0 1-2.79 3.216l-4.21.602a2 2 0 0 1 1 1.732v5a2 2 0 0 1-2 2H20a2 2 0 0 1-2-2v-5a2 2 0 0 1 1-1.732v-.217A3.25 3.25 0 0 1 21.129 7H15a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h10a2 2 0 0 1 1.855 1.25ZM20 10.05V11a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h1.5a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1v-.95c0-.016 0-.033.002-.05a.75.75 0 0 1 .642-.692l4.424-.632A2.25 2.25 0 0 0 28.5 6.45V4.75a1.496 1.496 0 0 0-1.5-1.5v3.2a.75.75 0 0 1-.644.742l-4.424.632A2.25 2.25 0 0 0 20 10.05ZM15 2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H15Z" fill="#fff"/>
|
||||
<path d="M2.5 2.5A.5.5 0 0 1 3 2h2.5a.5.5 0 0 1 .354.146l.646.647.646-.647A.5.5 0 0 1 7.5 2H10a.5.5 0 0 1 0 1H7.707L7 3.707V10h.5a.5.5 0 0 1 0 1H7v4.793l.707.707H10a.5.5 0 0 1 0 1H7.5a.5.5 0 0 1-.354-.146l-.646-.647-.646.647a.5.5 0 0 1-.354.146H3a.5.5 0 0 1 0-1h2.293L6 15.793V11h-.5a.5.5 0 0 1 0-1H6V3.707L5.293 3H3a.5.5 0 0 1-.5-.5Z" fill="#000"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="m5.793 3.5-.5-.5H3a.5.5 0 0 1 0-1h2.5a.5.5 0 0 1 .354.146l.145.146.501.5.646-.646A.5.5 0 0 1 7.5 2H10a.5.5 0 0 1 0 1H7.707L7 3.707V10h.5a.5.5 0 0 1 0 1H7v4.793l.707.707H10a.5.5 0 0 1 0 1H7.5a.5.5 0 0 1-.354-.146l-.646-.647-.5.5-.146.147a.5.5 0 0 1-.354.146H3a.5.5 0 0 1 0-1h2.293L6 15.793V11h-.5a.5.5 0 0 1 0-1H6V3.707L5.793 3.5Zm-.914.5L5 4.121v4.964a1.5 1.5 0 0 0 0 2.83v3.464l-.121.121H3a1.5 1.5 0 0 0 0 3h2.5a1.5 1.5 0 0 0 1-.382 1.5 1.5 0 0 0 1 .382H10a1.5 1.5 0 0 0 0-3H8.121L8 15.379v-3.464a1.5 1.5 0 0 0 0-2.83V4.121L8.121 4H10a1.5 1.5 0 0 0 0-3H7.5a1.5 1.5 0 0 0-1 .382A1.5 1.5 0 0 0 5.5 1H3a1.5 1.5 0 1 0 0 3h1.879Z" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
BIN
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_image.png
vendored
Normal file
BIN
docs/User Guide/User Guide/Note Types/Text/Premium features/Format Painter_image.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@ -33,13 +33,13 @@
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"http-server": "14.1.1",
|
||||
"lint-staged": "16.2.7",
|
||||
"stylelint": "16.26.0",
|
||||
"stylelint": "16.26.1",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.14",
|
||||
"webdriverio": "9.20.1"
|
||||
"webdriverio": "9.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.2.0"
|
||||
|
||||
@ -34,13 +34,13 @@
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"http-server": "14.1.1",
|
||||
"lint-staged": "16.2.7",
|
||||
"stylelint": "16.26.0",
|
||||
"stylelint": "16.26.1",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.14",
|
||||
"webdriverio": "9.20.1"
|
||||
"webdriverio": "9.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.2.0"
|
||||
|
||||
@ -36,13 +36,13 @@
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"http-server": "14.1.1",
|
||||
"lint-staged": "16.2.7",
|
||||
"stylelint": "16.26.0",
|
||||
"stylelint": "16.26.1",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.14",
|
||||
"webdriverio": "9.20.1"
|
||||
"webdriverio": "9.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.2.0"
|
||||
|
||||
@ -37,13 +37,13 @@
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"http-server": "14.1.1",
|
||||
"lint-staged": "16.2.7",
|
||||
"stylelint": "16.26.0",
|
||||
"stylelint": "16.26.1",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.14",
|
||||
"webdriverio": "9.20.1"
|
||||
"webdriverio": "9.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.2.0"
|
||||
|
||||
@ -36,13 +36,13 @@
|
||||
"eslint-config-ckeditor5": ">=9.1.0",
|
||||
"http-server": "14.1.1",
|
||||
"lint-staged": "16.2.7",
|
||||
"stylelint": "16.26.0",
|
||||
"stylelint": "16.26.1",
|
||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vite-plugin-svgo": "~2.0.0",
|
||||
"vitest": "4.0.14",
|
||||
"webdriverio": "9.20.1"
|
||||
"webdriverio": "9.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ckeditor5": "47.2.0"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import "ckeditor5/ckeditor5.css";
|
||||
import 'ckeditor5-premium-features/ckeditor5-premium-features.css';
|
||||
import "./theme/code_block_toolbar.css";
|
||||
import { COMMON_PLUGINS, CORE_PLUGINS, POPUP_EDITOR_PLUGINS } from "./plugins.js";
|
||||
import { BalloonEditor, DecoupledEditor, FindAndReplaceEditing, FindCommand } from "ckeditor5";
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Autoformat, AutoLink, BlockQuote, BlockToolbar, Bold, CKFinderUploadAdapter, Clipboard, Code, CodeBlock, Enter, FindAndReplace, Font, FontBackgroundColor, FontColor, GeneralHtmlSupport, Heading, HeadingButtonsUI, HorizontalLine, Image, ImageCaption, ImageInline, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Alignment, Indent, IndentBlock, Italic, Link, List, ListProperties, Mention, PageBreak, Paragraph, ParagraphButtonUI, PasteFromOffice, PictureEditing, RemoveFormat, SelectAll, ShiftEnter, SpecialCharacters, SpecialCharactersEssentials, Strikethrough, Style, Subscript, Superscript, Table, TableCaption, TableCellProperties, TableColumnResize, TableProperties, TableSelection, TableToolbar, TextPartLanguage, TextTransformation, TodoList, Typing, Underline, Undo, Bookmark, Emoji, Notification, EmojiMention, EmojiPicker } from "ckeditor5";
|
||||
import { SlashCommand, Template } from "ckeditor5-premium-features";
|
||||
import { SlashCommand, Template, FormatPainter } from "ckeditor5-premium-features";
|
||||
import type { Plugin } from "ckeditor5";
|
||||
import CutToNotePlugin from "./plugins/cuttonote.js";
|
||||
import UploadimagePlugin from "./plugins/uploadimage.js";
|
||||
@ -83,7 +83,8 @@ export const CORE_PLUGINS: typeof Plugin[] = [
|
||||
*/
|
||||
export const PREMIUM_PLUGINS: typeof Plugin[] = [
|
||||
SlashCommand,
|
||||
Template
|
||||
Template,
|
||||
FormatPainter
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user