Initial import of LogDarioSeq baseline
Establishes version control for the personal Logseq DB fork before starting the server-client architecture migration and domain features described in docs/agent-guide and the approved implementation plan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
41
resources/404.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Not Found</title>
|
||||
<script type="text/javascript">
|
||||
// Single Page Apps for GitHub Pages
|
||||
// https://github.com/rafgraph/spa-github-pages
|
||||
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
|
||||
// ----------------------------------------------------------------------
|
||||
// This script takes the current url and converts the path and query
|
||||
// string into just a query string, and then redirects the browser
|
||||
// to the new url with only a query string and hash fragment,
|
||||
// e.g. https://www.foo.tld/one/two?a=b&c=d#qwe, becomes
|
||||
// https://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe
|
||||
// Note: this 404.html file must be at least 512 bytes for it to work
|
||||
// with Internet Explorer (it is currently > 512 bytes)
|
||||
|
||||
// If you're creating a Project Pages site and NOT using a custom domain,
|
||||
// then set segmentCount to 1 (enterprise users may need to set it to > 1).
|
||||
// This way the code will only replace the route part of the path, and not
|
||||
// the real directory in which the app resides, for example:
|
||||
// https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
|
||||
// https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe
|
||||
// Otherwise, leave segmentCount as 0.
|
||||
var segmentCount = 0;
|
||||
|
||||
var l = window.location;
|
||||
l.replace(
|
||||
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
|
||||
l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +
|
||||
l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +
|
||||
(l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
|
||||
l.hash
|
||||
);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
166
resources/css/codemirror.lsradix.css
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
lsradix theme for code-mirror
|
||||
http://ethanschoonover.com/lsradix
|
||||
*/
|
||||
|
||||
/*
|
||||
lsradix color palette
|
||||
http://ethanschoonover.com/lsradix/img/lsradix-palette.png
|
||||
*/
|
||||
|
||||
.lsradix.base03 { color: var(--lx-gray-01, #002b36); }
|
||||
.dark .lsradix.base03 { color: var(--lx-gray-02, #002b36); }
|
||||
.lsradix.base02 { color: var(--lx-gray-02, #073642); }
|
||||
.dark .lsradix.base02 { color: var(--lx-gray-01, #073642); }
|
||||
.lsradix.base01 { color: var(--lx-gray-03, #586e75); }
|
||||
.lsradix.base00 { color: var(--lx-gray-04, #657b83); }
|
||||
.lsradix.base0 { color: var(--lx-gray-09, #839496); }
|
||||
.lsradix.base1 { color: var(--lx-gray-10, #93a1a1); }
|
||||
.lsradix.base2 { color: var(--lx-gray-11, #eee8d5); }
|
||||
.lsradix.base3 { color: var(--lx-gray-11, #fdf6e3); }
|
||||
.lsradix.solar-yellow { color: var(--rx-yellow-11, #b58900); }
|
||||
.lsradix.solar-orange { color: var(--rx-orange-11, #cb4b16); }
|
||||
.lsradix.solar-red { color: var(--rx-red-11, #dc322f); }
|
||||
.lsradix.solar-magenta { color: var(--rx-pink-11, #d33682); }
|
||||
.lsradix.solar-violet { color: var(--rx-purple-11, #6c71c4); }
|
||||
.lsradix.solar-blue { color: var(--rx-blue-11, #268bd2); }
|
||||
.lsradix.solar-cyan { color: var(--rx-sky-11, #2aa198); }
|
||||
.lsradix.solar-green { color: var(--rx-grass-11, #859900); }
|
||||
|
||||
/* Color scheme for code-mirror */
|
||||
|
||||
.cm-s-lsradix {
|
||||
line-height: 1.45em;
|
||||
color-profile: sRGB;
|
||||
rendering-intent: auto;
|
||||
}
|
||||
.cm-s-lsradix.cm-s-dark {
|
||||
background-color: var(--lx-gray-01, hsl(var(--secondary)/.7));
|
||||
color: var(--ls-primary-text-color, var(--lx-gray-10, hsl(var(--secondary-foreground))));
|
||||
}
|
||||
|
||||
.dark .cm-s-lsradix.cm-s-dark {
|
||||
background-color: var(--lx-gray-02, hsl(var(--secondary)/.7));
|
||||
}
|
||||
|
||||
.cm-s-lsradix.cm-s-light {
|
||||
background-color: var(--lx-gray-02, hsl(var(--secondary)/.7));
|
||||
color: var(--lx-gray-10, hsl(var(--secondary-foreground)));
|
||||
}
|
||||
|
||||
.cm-s-lsradix .CodeMirror-widget {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.cm-s-lsradix .cm-header { color: var(--lx-gray-03, #586e75); }
|
||||
.cm-s-lsradix .cm-quote { color: var(--lx-gray-10, #93a1a1); }
|
||||
|
||||
.cm-s-lsradix .cm-keyword { color: var(--rx-orange-11, #cb4b16); }
|
||||
.cm-s-lsradix .cm-atom { color: var(--rx-pink-11, #d33682); }
|
||||
.cm-s-lsradix .cm-number { color: var(--rx-pink-11, #d33682); }
|
||||
.cm-s-lsradix .cm-def { color: var(--rx-sky-11, #2aa198); }
|
||||
|
||||
/* .cm-s-lsradix .cm-variable { color: var(--lx-gray-09, #839496); } */
|
||||
.cm-s-lsradix .cm-variable { color: var(--lx-gray-12, #839496); }
|
||||
.cm-s-lsradix .cm-variable-2 { color: var(--rx-yellow-11, #b58900); }
|
||||
.cm-s-lsradix .cm-variable-3, .cm-s-lsradix .cm-type { color: var(--rx-purple-11, #6c71c4); }
|
||||
|
||||
.cm-s-lsradix .cm-property { color: var(--rx-sky-11, #2aa198); }
|
||||
.cm-s-lsradix .cm-operator { color: var(--rx-purple-11, #6c71c4); }
|
||||
|
||||
.cm-s-lsradix .cm-comment { color: var(--lx-gray-10, #586e75); font-style:italic; }
|
||||
|
||||
.cm-s-lsradix .cm-string { color: var(--rx-grass-11, #859900); }
|
||||
.cm-s-lsradix .cm-string-2 { color: var(--rx-yellow-11, #b58900); }
|
||||
|
||||
.cm-s-lsradix .cm-meta { color: var(--rx-grass-11, #859900); }
|
||||
.cm-s-lsradix .cm-qualifier { color: var(--rx-yellow-11, #b58900); }
|
||||
.cm-s-lsradix .cm-builtin { color: var(--rx-pink-11, #d33682); }
|
||||
.cm-s-lsradix .cm-bracket { color: var(--rx-orange-11, #cb4b16); }
|
||||
.cm-s-lsradix .CodeMirror-matchingbracket { color: var(--rx-grass-11, #859900); }
|
||||
.cm-s-lsradix .CodeMirror-nonmatchingbracket { color: var(--rx-red-11, #dc322f); }
|
||||
.cm-s-lsradix .cm-tag { color: var(--lx-gray-10, #93a1a1); }
|
||||
.cm-s-lsradix .cm-attribute { color: var(--rx-sky-11, #2aa198); }
|
||||
.cm-s-lsradix .cm-hr {
|
||||
color: transparent;
|
||||
border-top: 1px solid var(--lx-gray-03, #586e75);
|
||||
display: block;
|
||||
}
|
||||
.cm-s-lsradix .cm-link { color: var(--lx-gray-10, #93a1a1); cursor: pointer; }
|
||||
.cm-s-lsradix .cm-special { color: var(--rx-purple-11, #6c71c4); }
|
||||
.cm-s-lsradix .cm-em {
|
||||
color: #999;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
.cm-s-lsradix .cm-error,
|
||||
.cm-s-lsradix .cm-invalidchar {
|
||||
/* color: var(--lx-gray-03, #586e75); */
|
||||
color: var(--lx-gray-10, #586e75);
|
||||
border-bottom: 1px dotted var(--rx-red-11, #dc322f);
|
||||
}
|
||||
|
||||
.cm-s-lsradix.cm-s-dark div.CodeMirror-selected { background: var(--lx-gray-06, rgb(4 38 47 / 99%)); }
|
||||
.cm-s-lsradix.cm-s-dark.CodeMirror ::selection { background: var(--lx-gray-06, rgb(4 38 47 / 99%)); }
|
||||
.cm-s-lsradix.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: var(--lx-gray-06, rgb(4 38 47 / 99%)); }
|
||||
|
||||
.cm-s-lsradix.cm-s-light div.CodeMirror-selected { background: var(--lx-gray-06, #eee8d5); }
|
||||
.cm-s-lsradix.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: var(--lx-gray-06, #eee8d5); }
|
||||
.cm-s-lsradix.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-light .CodeMirror-line > span::-moz-selection, .cm-s-light .CodeMirror-line > span > span::-moz-selection { background: var(--lx-gray-06, #eee8d5); }
|
||||
|
||||
/* Editor styling */
|
||||
|
||||
|
||||
/* Remove gutter border */
|
||||
.cm-s-lsradix .CodeMirror-gutters {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
/* Gutter colors and line number styling based of color scheme (dark / light) */
|
||||
|
||||
/* Dark */
|
||||
.cm-s-lsradix.cm-s-dark .CodeMirror-gutters {
|
||||
background-color: var(--lx-gray-03, hsl(var(--secondary)));
|
||||
}
|
||||
|
||||
.cm-s-lsradix.cm-s-dark .CodeMirror-linenumber {
|
||||
color: var(--lx-gray-09, #586e75);
|
||||
}
|
||||
|
||||
/* Light */
|
||||
.cm-s-lsradix.cm-s-light .CodeMirror-gutters {
|
||||
background-color: var(--lx-gray-03, hsl(var(--secondary)));
|
||||
}
|
||||
|
||||
.cm-s-lsradix.cm-s-light .CodeMirror-linenumber {
|
||||
color: var(--lx-gray-09, #839496);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
.cm-s-lsradix .CodeMirror-linenumber {
|
||||
padding: 0 5px;
|
||||
}
|
||||
.cm-s-lsradix .CodeMirror-guttermarker-subtle { color: var(--lx-gray-03, #586e75); }
|
||||
.cm-s-lsradix.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }
|
||||
.cm-s-lsradix.cm-s-light .CodeMirror-guttermarker { color: var(--rx-orange-11, #cb4b16); }
|
||||
|
||||
.cm-s-lsradix .CodeMirror-gutter .CodeMirror-gutter-text {
|
||||
color: var(--lx-gray-03, #586e75);
|
||||
}
|
||||
|
||||
/* Cursor */
|
||||
.cm-s-lsradix .CodeMirror-cursor { border-left: 1px solid #819090; }
|
||||
|
||||
/* Fat cursor */
|
||||
.cm-s-lsradix.cm-s-light.cm-fat-cursor .CodeMirror-cursor { background: #77ee77; }
|
||||
.cm-s-lsradix.cm-s-light .cm-animate-fat-cursor { background-color: #77ee77; }
|
||||
.cm-s-lsradix.cm-s-dark.cm-fat-cursor .CodeMirror-cursor { background: var(--lx-gray-03, #586e75); }
|
||||
.cm-s-lsradix.cm-s-dark .cm-animate-fat-cursor { background-color: var(--lx-gray-03, #586e75); }
|
||||
|
||||
/* Active line */
|
||||
.cm-s-lsradix.cm-s-dark .CodeMirror-activeline-background {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
.cm-s-lsradix.cm-s-light .CodeMirror-activeline-background {
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
BIN
resources/css/fonts/tabler-icons-extension.woff2
Normal file
BIN
resources/css/fonts/tabler-icons.eot
Normal file
BIN
resources/css/fonts/tabler-icons.ttf
Normal file
BIN
resources/css/fonts/tabler-icons.woff
Normal file
BIN
resources/css/fonts/tabler-icons.woff2
Normal file
561
resources/css/shui.css
Normal file
@@ -0,0 +1,561 @@
|
||||
html * {
|
||||
border-color: hsl(var(--border));
|
||||
}
|
||||
|
||||
html[data-theme=light] {
|
||||
--accent: var(--rx-gray-12-hsl);
|
||||
--accent-foreground: var(--rx-gray-02-hsl);
|
||||
--input: var(--rx-gray-05-hsl);
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--kbd-glow-top: transparent;
|
||||
--kbd-glow-bottom: rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
|
||||
html[data-theme=dark] {
|
||||
--accent: var(--rx-gray-12-hsl);
|
||||
--accent-foreground: var(--rx-gray-02-hsl);
|
||||
--primary-foreground: 0 0% 22%;
|
||||
--background: 0 0% 11%;
|
||||
--foreground: 0 0% 95%;
|
||||
--card: 0 0% 11%;
|
||||
--card-foreground: 0 0% 95%;
|
||||
--secondary: 0 0% 20%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--border: 0 0% 16%;
|
||||
--muted: 0 0% 15%;
|
||||
--popover: 0 0% 7%;
|
||||
--popover-foreground: 0 0 95%;
|
||||
--input: 0 0% 16%;
|
||||
--kbd-glow-top: rgba(255, 255, 255, 0.15);
|
||||
--kbd-glow-bottom: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
html {
|
||||
div[data-radix-menu-content],
|
||||
.ui__select-content {
|
||||
--accent: var(--rx-gray-04-hsl);
|
||||
--accent-foreground: var(--rx-gray-12-hsl);
|
||||
|
||||
--muted: var(--rx-gray-05-hsl);
|
||||
}
|
||||
|
||||
.ui__calendar {
|
||||
--accent: var(--rx-gray-04-hsl);
|
||||
--accent-foreground: var(--rx-gray-12-hsl);
|
||||
}
|
||||
|
||||
&:not([data-color=logseq]) {
|
||||
.ui__dropdown-menu-item,
|
||||
div[data-radix-popper-content-wrapper] div[data-radix-collection-item] {
|
||||
&:focus, &.is-active {
|
||||
background-color: var(--lx-gray-04, hsl(var(--accent)));
|
||||
}
|
||||
}
|
||||
|
||||
.ui__dropdown-menu-content.has-search-key {
|
||||
> .head:focus-within + div[data-radix-collection-item] {
|
||||
background-color: var(--lx-gray-04, hsl(var(--accent)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
div[data-radix-popper-content-wrapper] div[role=menu],
|
||||
.menu-links-wrapper,
|
||||
.menu-links-outer,
|
||||
.absolute-modal[data-modal-name] {
|
||||
background-color: var(--lx-popover-bg, var(--lx-gray-01, hsl(var(--popover))));
|
||||
}
|
||||
}
|
||||
|
||||
&[data-color=logseq] {
|
||||
.references-blocks-item {
|
||||
--lx-bg-override: var(--rx-gray-03-alpha);
|
||||
}
|
||||
|
||||
.block-children-left-border:hover {
|
||||
--ls-block-left-color: var(--rx-logseq-11);
|
||||
}
|
||||
}
|
||||
|
||||
&[data-color=none] {
|
||||
--ls-block-bullet-color: var(--rx-gray-08);
|
||||
--ls-block-bullet-active-color: var(--rx-gray-12);
|
||||
|
||||
::selection {
|
||||
@apply bg-primary/20;
|
||||
}
|
||||
|
||||
#ui__ac-inner {
|
||||
}
|
||||
|
||||
.cp__cmdk {
|
||||
--lx-gray-07: var(--rx-gray-07);
|
||||
}
|
||||
|
||||
.ui__toggle {
|
||||
&-background-off {
|
||||
@apply bg-gray-08;
|
||||
|
||||
.switcher {
|
||||
@apply bg-gray-10;
|
||||
}
|
||||
}
|
||||
|
||||
&-background-on {
|
||||
.switcher {
|
||||
@apply bg-gray-03;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tl-container {
|
||||
--ls-primary-background-color: hsl(var(--background));
|
||||
--ls-secondary-background-color: var(--rx-gray-01);
|
||||
--ls-tertiary-background-color: var(--rx-gray-03);
|
||||
--ls-quaternary-background-color: var(--rx-gray-05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme=light] {
|
||||
&[data-color=logseq] {
|
||||
.references-blocks-item {
|
||||
--lx-bg-override: var(--rx-gray-03-alpha);
|
||||
}
|
||||
}
|
||||
|
||||
.extensions__pdf-container {
|
||||
--lx-pdf-container-dark-bg: var(--lx-gray-11, #042f3c);
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme=dark] {
|
||||
background-color: #161616;
|
||||
|
||||
&[data-color=logseq] {
|
||||
@apply bg-[#002b36];
|
||||
|
||||
.ui__modal-panel {
|
||||
@apply border-accent-01;
|
||||
}
|
||||
|
||||
.tippy-tooltip {
|
||||
@apply border-accent-02;
|
||||
}
|
||||
|
||||
.references-blocks-item {
|
||||
background-color: var(--lx-gray-03, var(--ls-secondary-background-color));
|
||||
}
|
||||
|
||||
.cp__right-sidebar-inner {
|
||||
.references-blocks-item {
|
||||
background-color: var(--lx-gray-04, var(--ls-tertiary-background-color));
|
||||
}
|
||||
}
|
||||
|
||||
.cp__themes-installed {
|
||||
.it.is-active, .it:hover {
|
||||
@apply bg-accent-01;
|
||||
}
|
||||
}
|
||||
|
||||
.ui__button {
|
||||
&.as-outline {
|
||||
--accent: 192 100% 12%;
|
||||
}
|
||||
}
|
||||
|
||||
div[data-radix-menu-content],
|
||||
.ui__select-content {
|
||||
--accent: 190 100% 15%;
|
||||
--muted: 192 100% 13%;
|
||||
--secondary-foreground: 0 0% 82%;
|
||||
}
|
||||
|
||||
.ui__button {
|
||||
&.as-ghost {
|
||||
@apply hover:bg-accent-01;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-separator {
|
||||
@apply opacity-20;
|
||||
}
|
||||
|
||||
.ui__calendar {
|
||||
--accent: 196 100% 15%;
|
||||
}
|
||||
|
||||
.rc-datepicker {
|
||||
--accent: 200 97% 37%;
|
||||
}
|
||||
|
||||
.cp__cmdk {
|
||||
.border-gray-06,
|
||||
.border-gray-07 {
|
||||
border-color: var(--ls-border-color, var(--lx-gray-06));
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
> .hints {
|
||||
@apply border-accent-01 bg-gray-02;
|
||||
}
|
||||
}
|
||||
|
||||
.tl-button {
|
||||
&:hover {
|
||||
@apply bg-accent-02;
|
||||
}
|
||||
}
|
||||
|
||||
.cp__header {
|
||||
> .r > div:not(.ui__dropdown-trigger) a.button, button.button,
|
||||
.ui__button.as-ghost {
|
||||
@apply opacity-60 hover:opacity-90;
|
||||
}
|
||||
}
|
||||
|
||||
.form-input {
|
||||
@apply border-accent-01;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui__dialog-overlay, .ui__alert-dialog-overlay,
|
||||
.ui__dialog-content, .ui__alert-dialog-content,
|
||||
.ui__dropdown-menu-content, .ui__select-content {
|
||||
|
||||
&.z-50 {
|
||||
@apply z-[999];
|
||||
}
|
||||
}
|
||||
|
||||
div[data-radix-popper-content-wrapper] {
|
||||
@apply !z-[999];
|
||||
|
||||
&:has(> .repos-list) {
|
||||
@apply !z-[var(--ls-z-index-level-5)];
|
||||
}
|
||||
}
|
||||
|
||||
.ui__dialog-overlay {
|
||||
&[data-align=start],
|
||||
&[data-align=top] {
|
||||
@apply !items-start;
|
||||
|
||||
.ui__dialog-content {
|
||||
@apply top-20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui__dialog-content {
|
||||
@apply outline-none m-0;
|
||||
|
||||
&:not([data-auto-width]) {
|
||||
width: calc(100% - 2rem);
|
||||
}
|
||||
|
||||
&[data-auto-width] {
|
||||
@apply max-w-[90vw] w-max sm:max-w-[960px];
|
||||
}
|
||||
|
||||
&[data-close-btn=false] {
|
||||
.ui__dialog-close {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui__alert-dialog-content {
|
||||
&[data-mode=confirm] {
|
||||
.ui__alert-dialog-footer {
|
||||
@apply flex justify-between font-normal items-center select-none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Deprecated: .ui__button-shortcut-key - replaced by shui-shortcut-key */
|
||||
|
||||
/* Unified Keyboard Shortcut Component Styles */
|
||||
|
||||
/* Combo Keys - simultaneous key combinations with separator */
|
||||
.shui-shortcut-combo {
|
||||
@apply flex items-start relative rounded;
|
||||
background-color: var(--lx-gray-06-alpha, var(--rx-gray-06-alpha));
|
||||
border: 1px solid var(--lx-gray-06-alpha, var(--rx-gray-06-alpha));
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
transition: transform 140ms ease-out, box-shadow 140ms ease-out, filter 140ms ease-out;
|
||||
filter: brightness(1);
|
||||
}
|
||||
|
||||
/* Glow effect for combo and separate keys */
|
||||
/* Top highlight and bottom shadow use theme-aware variables for light/dark visibility */
|
||||
/* Combo keys: glow on container (wraps all keys together) */
|
||||
.shui-shortcut-combo.shui-shortcut-glow {
|
||||
box-shadow: var(--kbd-glow-top) 0px 1px 0px 0px inset, var(--kbd-glow-bottom) 0px -1px 0px 0px inset;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Separate keys: glow on individual keys (not container) */
|
||||
.shui-shortcut-separate.shui-shortcut-glow kbd.shui-shortcut-key {
|
||||
box-shadow: var(--kbd-glow-top) 0px 1px 0px 0px inset, var(--kbd-glow-bottom) 0px -1px 0px 0px inset;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.shui-shortcut-combo kbd.shui-shortcut-key {
|
||||
@apply flex flex-col items-center justify-center px-1 py-0.5 relative shrink-0;
|
||||
min-width: 20px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.shui-shortcut-separator {
|
||||
background-color: var(--lx-gray-07-alpha, var(--rx-gray-07-alpha));
|
||||
align-self: stretch;
|
||||
flex-shrink: 0;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
/* Separate Keys - sequential key presses with 4px gap */
|
||||
.shui-shortcut-separate {
|
||||
@apply flex items-start relative;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.shui-shortcut-separate kbd.shui-shortcut-key {
|
||||
@apply flex flex-col items-center justify-center px-1 py-0.5 relative rounded shrink-0;
|
||||
background-color: var(--lx-gray-06-alpha, var(--rx-gray-06-alpha));
|
||||
border: 1px solid var(--lx-gray-06-alpha, var(--rx-gray-06-alpha));
|
||||
box-sizing: border-box;
|
||||
min-width: 20px;
|
||||
}
|
||||
|
||||
/* Compact Keys - minimal text-only style */
|
||||
.shui-shortcut-compact {
|
||||
@apply flex items-start relative;
|
||||
font-family: 'Inter', sans-serif;
|
||||
font-weight: normal;
|
||||
line-height: 16px;
|
||||
font-style: normal;
|
||||
color: var(--lx-gray-12, var(--rx-gray-12));
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
letter-spacing: -0.5px;
|
||||
white-space: nowrap;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
/* Individual key styling with inner glow */
|
||||
kbd.shui-shortcut-key,
|
||||
.shui-shortcut-key {
|
||||
@apply text-xs font-normal h-5 flex items-center justify-center;
|
||||
font-family: 'Inter', sans-serif;
|
||||
color: var(--lx-gray-12, var(--rx-gray-12));
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
letter-spacing: -0.5px;
|
||||
padding: 2px 4px;
|
||||
line-height: 16px;
|
||||
min-width: fit-content;
|
||||
transition: transform 140ms ease-out, box-shadow 140ms ease-out, filter 140ms ease-out;
|
||||
box-shadow: 0 0 0 transparent;
|
||||
filter: brightness(1);
|
||||
}
|
||||
|
||||
/* Keys in separate containers get their own styling */
|
||||
.shui-shortcut-separate kbd.shui-shortcut-key {
|
||||
@apply rounded;
|
||||
background-color: var(--lx-gray-06-alpha, var(--rx-gray-06-alpha));
|
||||
border: 1px solid var(--lx-gray-06-alpha, var(--rx-gray-06-alpha));
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Override shortcut text color inside primary buttons for better contrast */
|
||||
.bg-primary kbd.shui-shortcut-key,
|
||||
.bg-primary .shui-shortcut-key,
|
||||
.bg-primary .shui-shortcut-compact,
|
||||
.bg-primary\/90 kbd.shui-shortcut-key,
|
||||
.bg-primary\/90 .shui-shortcut-key,
|
||||
.bg-primary\/90 .shui-shortcut-compact,
|
||||
.bg-primary\/100 kbd.shui-shortcut-key,
|
||||
.bg-primary\/100 .shui-shortcut-key,
|
||||
.bg-primary\/100 .shui-shortcut-compact {
|
||||
color: hsl(var(--primary-foreground));
|
||||
}
|
||||
|
||||
/* Key press animation — separate keys: animate individual kbd elements */
|
||||
kbd.shui-shortcut-key-pressed,
|
||||
.shui-shortcut-key-pressed {
|
||||
transform: translateY(1px);
|
||||
filter: brightness(0.92);
|
||||
}
|
||||
|
||||
.shui-shortcut-separate.shui-shortcut-glow kbd.shui-shortcut-key-pressed {
|
||||
box-shadow: var(--kbd-glow-top) 0px 2px 0px 0px inset, var(--kbd-glow-bottom) 0px -0.5px 0px 0px inset;
|
||||
}
|
||||
|
||||
/* Key press animation — combo keys: animate the container (the whole keycap) */
|
||||
.shui-shortcut-combo.shui-shortcut-key-pressed {
|
||||
transform: translateY(1px);
|
||||
filter: brightness(0.92);
|
||||
}
|
||||
|
||||
.shui-shortcut-combo.shui-shortcut-glow.shui-shortcut-key-pressed {
|
||||
box-shadow: var(--kbd-glow-top) 0px 2px 0px 0px inset, var(--kbd-glow-bottom) 0px -0.5px 0px 0px inset;
|
||||
}
|
||||
|
||||
/* Row highlight animation — accent band sweep (only on actual row elements) */
|
||||
.shui-shortcut-row.shui-shortcut-row--pressed,
|
||||
.shortcut-row.shui-shortcut-row--pressed {
|
||||
background-image: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
transparent 35%,
|
||||
rgba(223, 239, 254, 0.08) 50%,
|
||||
transparent 65%,
|
||||
transparent 100%
|
||||
);
|
||||
background-size: 300% 100%;
|
||||
background-repeat: no-repeat;
|
||||
animation: shortcut-row-sweep 700ms ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes shortcut-row-sweep {
|
||||
from { background-position: -50% 0; }
|
||||
to { background-position: 150% 0; }
|
||||
}
|
||||
|
||||
/* Ensure consistent height for shortcut containers */
|
||||
.shui-shortcut-row {
|
||||
min-height: 20px;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
/* Respect reduced motion preference */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
kbd.shui-shortcut-key,
|
||||
.shui-shortcut-key,
|
||||
.shui-shortcut-combo {
|
||||
transition: none;
|
||||
transform: none;
|
||||
filter: none;
|
||||
box-shadow: 0 0 0 transparent;
|
||||
}
|
||||
|
||||
.shui-shortcut-row.shui-shortcut-row--pressed,
|
||||
.shortcut-row.shui-shortcut-row--pressed {
|
||||
animation: none !important;
|
||||
background-image: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ui__list-item-highlighted-span {
|
||||
background-color: var(--lx-accent-06, var(--color-level-4));
|
||||
}
|
||||
|
||||
.dark .ui__list-item-highlighted-span {
|
||||
background-color: var(--lx-accent-08-alpha, var(--color-level-4));
|
||||
}
|
||||
|
||||
.ui__dropdown-menu-content, div[data-radix-menu-content],
|
||||
.ui__select-content {
|
||||
@apply overflow-y-auto;
|
||||
|
||||
&[data-side=top] {
|
||||
max-height: calc(var(--radix-dropdown-menu-content-available-height) - 20px);
|
||||
}
|
||||
|
||||
&[data-side=bottom] {
|
||||
max-height: calc(var(--radix-dropdown-menu-content-available-height) - 10px);
|
||||
}
|
||||
|
||||
&.text-popover-foreground {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.ui__popover-content {
|
||||
@apply overflow-y-auto;
|
||||
|
||||
&[data-side=top] {
|
||||
max-height: calc(var(--radix-popover-content-available-height) - 40px);
|
||||
}
|
||||
|
||||
&[data-side=bottom] {
|
||||
max-height: calc(var(--radix-popover-content-available-height) - 20px);
|
||||
}
|
||||
}
|
||||
|
||||
.ui__popover-content {
|
||||
@apply !pointer-events-auto;
|
||||
}
|
||||
|
||||
.ui__multi-select-content {
|
||||
@apply relative;
|
||||
|
||||
> .head {
|
||||
@apply sticky top-0 z-10;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
> .ui__input {
|
||||
@apply rounded-[1px] h-8;
|
||||
}
|
||||
}
|
||||
|
||||
&:has([data-radix-collection-item]) {
|
||||
> .head {
|
||||
@apply mb-1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui__calendar {
|
||||
.del-date-btn {
|
||||
@apply absolute right-[4px] top-[17px] px-1 opacity-70 hover:opacity-100
|
||||
active:opacity-80 hover:text-red-rx-09 rounded-md !h-6 !w-6;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
appearance: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.popper-arrow {
|
||||
fill: white;
|
||||
filter: drop-shadow(0 0 3px var(--lx-gray-12));
|
||||
clip-path: inset(0 -10px -10px -10px);
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
.popper-arrow {
|
||||
/* FIXME: set the best color for different themes */
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui__toast-content {
|
||||
&.untitled {
|
||||
.ui__toast-header {
|
||||
@apply absolute top-1 right-1 w-fit z-1;
|
||||
}
|
||||
|
||||
.ui__toast-body {
|
||||
@apply flex-initial py-2;
|
||||
}
|
||||
|
||||
.ui__toast-text {
|
||||
@apply flex flex-row items-center gap-2 overflow-auto;
|
||||
}
|
||||
|
||||
.ui__toast-description {
|
||||
@apply max-w-full overflow-auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
153
resources/css/tabler-extension.css
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* This file is managed manually by Webfont app.
|
||||
* Steps:
|
||||
* - download the zip from Webfont app
|
||||
* - get the tabler-icons-extension.woff2 and replace the one in fonts/tabler-icons-extension.woff2
|
||||
* - update the tie-xxx css rules
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'tabler-icons-extension';
|
||||
src: url('./fonts/tabler-icons-extension.woff2?mxgthk') format('woff2');
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.tie {
|
||||
display: inline-block;
|
||||
font-family: "tabler-icons-extension" !important;
|
||||
font-style: normal !important;
|
||||
font-weight: normal !important;
|
||||
font-variant: normal !important;
|
||||
text-transform: none !important;
|
||||
speak: none;
|
||||
line-height: 1;
|
||||
vertical-align: -.125em;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.tie-add-link::before {
|
||||
content: "\ea01";
|
||||
}
|
||||
|
||||
.tie-app-feature::before {
|
||||
content: "\ea02";
|
||||
}
|
||||
|
||||
.tie-block::before {
|
||||
content: "\ea03";
|
||||
}
|
||||
|
||||
.tie-block-search::before {
|
||||
content: "\ea04";
|
||||
}
|
||||
|
||||
.tie-cloud-exclamation::before {
|
||||
content: "\ea05";
|
||||
}
|
||||
|
||||
.tie-connector::before {
|
||||
content: "\ea06";
|
||||
}
|
||||
|
||||
.tie-group::before {
|
||||
content: "\ea07";
|
||||
}
|
||||
|
||||
.tie-h-auto::before {
|
||||
content: "\ea08";
|
||||
}
|
||||
|
||||
.tie-heading-off::before {
|
||||
content: "\ea09";
|
||||
}
|
||||
|
||||
.tie-internal-link::before {
|
||||
content: "\ea0a";
|
||||
}
|
||||
|
||||
.tie-link-to-block::before {
|
||||
content: "\ea0b";
|
||||
}
|
||||
|
||||
.tie-link-to-page::before {
|
||||
content: "\ea0c";
|
||||
}
|
||||
|
||||
.tie-link-to-whiteboard::before {
|
||||
content: "\ea0d";
|
||||
}
|
||||
|
||||
.tie-move-to-sidebar-right::before {
|
||||
content: "\ea0e";
|
||||
}
|
||||
|
||||
.tie-new-block::before {
|
||||
content: "\ea0f";
|
||||
}
|
||||
|
||||
.tie-new-page::before {
|
||||
content: "\ea10";
|
||||
}
|
||||
|
||||
.tie-new-whiteboard::before {
|
||||
content: "\ea11";
|
||||
}
|
||||
|
||||
.tie-new-whiteboard-element::before {
|
||||
content: "\ea12";
|
||||
}
|
||||
|
||||
.tie-object-compact::before {
|
||||
content: "\ea13";
|
||||
}
|
||||
|
||||
.tie-object-expanded::before {
|
||||
content: "\ea14";
|
||||
}
|
||||
|
||||
.tie-open-as-page::before {
|
||||
content: "\ea15";
|
||||
}
|
||||
|
||||
.tie-page::before {
|
||||
content: "\ea16";
|
||||
}
|
||||
|
||||
.tie-page-search::before {
|
||||
content: "\ea17";
|
||||
}
|
||||
|
||||
.tie-references-hide::before {
|
||||
content: "\ea18";
|
||||
}
|
||||
|
||||
.tie-references-show::before {
|
||||
content: "\ea19";
|
||||
}
|
||||
|
||||
.tie-select-cursor::before {
|
||||
content: "\ea1a";
|
||||
}
|
||||
|
||||
.tie-text::before {
|
||||
content: "\ea1b";
|
||||
}
|
||||
|
||||
.tie-ungroup::before {
|
||||
content: "\ea1c";
|
||||
}
|
||||
|
||||
.tie-whiteboard::before {
|
||||
content: "\ea1d";
|
||||
}
|
||||
|
||||
.tie-whiteboard-element::before {
|
||||
content: "\ea1e";
|
||||
}
|
||||
|
||||
.tie-whiteboard-search::before {
|
||||
content: "\ea1f";
|
||||
}
|
||||
4
resources/css/tabler-icons.min.css
vendored
Normal file
2339
resources/css/ui.css
Normal file
1121
resources/docs/api_server.html
Normal file
89
resources/electron-builder.yml
Normal file
@@ -0,0 +1,89 @@
|
||||
appId: com.logseq.logseq
|
||||
electronUpdaterCompatibility: ">=2.16"
|
||||
|
||||
directories:
|
||||
buildResources: .
|
||||
output: dist
|
||||
|
||||
files:
|
||||
- "**/*"
|
||||
- "!dist/**"
|
||||
- "!mobile/**"
|
||||
- "!android/**"
|
||||
- "!ios/**"
|
||||
- "!js/publishing/*.map"
|
||||
- "!js/publishing/manifest.edn"
|
||||
- "!js/publishing/module-loader.*"
|
||||
- "!js/sqlite3.wasm"
|
||||
- "!css/fonts/tabler-icons.eot"
|
||||
- "!css/fonts/tabler-icons.ttf"
|
||||
- "!css/fonts/tabler-icons.woff"
|
||||
- "!**/node_modules/**/*.map"
|
||||
- "!**/node_modules/**/*.d.ts"
|
||||
- "!**/node_modules/**/*.d.cts"
|
||||
- "!**/node_modules/**/*.d.mts"
|
||||
- "!**/node_modules/**/*.{ts,cts,mts}"
|
||||
- "!**/node_modules/**/*.{c,cc,cpp,h,hpp,gyp}"
|
||||
- "!**/node_modules/**/*.test-d.ts"
|
||||
- "!**/node_modules/**/*.test-d.cts"
|
||||
- "!**/node_modules/**/*.test-d.mts"
|
||||
- "!**/node_modules/**/*.{test,spec}.{js,cjs,mjs,ts,cts,mts}"
|
||||
- "!**/node_modules/**/*{example,benchmark,bench,tests,runkit}*.{js,cjs,mjs,ts,cts,mts}"
|
||||
- "!**/node_modules/**/*.{md,markdown}"
|
||||
- "!**/node_modules/**/{test,tests,__tests__,powered-test,example,examples,benchmark,benchmarks}/**"
|
||||
- "!**/node_modules/**/{tsconfig.json,eslint.config.js,.editorconfig}"
|
||||
|
||||
toolsets:
|
||||
appimage: "1.0.2"
|
||||
|
||||
protocols:
|
||||
- name: logseq
|
||||
schemes:
|
||||
- logseq
|
||||
|
||||
publish:
|
||||
- provider: github
|
||||
owner: logseq
|
||||
repo: logseq
|
||||
|
||||
extraResources:
|
||||
- from: .agents/skills/logseq-cli/SKILL.md
|
||||
to: .agents/skills/logseq-cli/SKILL.md
|
||||
- from: ../sidecar
|
||||
to: sidecar
|
||||
|
||||
mac:
|
||||
artifactName: ${productName}-darwin-${arch}-${version}.${ext}
|
||||
icon: icons/logseq_big_sur.icns
|
||||
target:
|
||||
- dmg
|
||||
- zip
|
||||
hardenedRuntime: true
|
||||
entitlements: entitlements.plist
|
||||
entitlementsInherit: entitlements.plist
|
||||
|
||||
dmg:
|
||||
format: ULFO
|
||||
|
||||
win:
|
||||
icon: icons/logseq.ico
|
||||
target:
|
||||
- nsis
|
||||
- zip
|
||||
|
||||
nsis:
|
||||
artifactName: ${productName}-win-${arch}-${version}-nsis.${ext}
|
||||
oneClick: false
|
||||
allowToChangeInstallationDirectory: true
|
||||
installerIcon: icons/logseq.ico
|
||||
uninstallerIcon: icons/logseq.ico
|
||||
|
||||
linux:
|
||||
artifactName: ${productName}-linux-${arch}-${version}.${ext}
|
||||
icon: icons/logseq.png
|
||||
category: Office
|
||||
target:
|
||||
- AppImage
|
||||
- zip
|
||||
mimeTypes:
|
||||
- x-scheme-handler/logseq
|
||||
12
resources/entitlements.plist
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
61
resources/forge.config.test.js
Normal file
@@ -0,0 +1,61 @@
|
||||
const test = require('node:test')
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const config = require('./forge.config')
|
||||
|
||||
const repoRoot = path.resolve(__dirname, '..')
|
||||
|
||||
function normalizeResourcePath(resourcePath) {
|
||||
return path.resolve(resourcePath)
|
||||
}
|
||||
|
||||
function collectExtraResources() {
|
||||
return (config.packagerConfig?.extraResource || []).map(normalizeResourcePath)
|
||||
}
|
||||
|
||||
function isCoveredByExtraResources(targetPath, extraResources) {
|
||||
const normalizedTarget = path.resolve(targetPath)
|
||||
return extraResources.some((resource) =>
|
||||
normalizedTarget === resource || normalizedTarget.startsWith(resource + path.sep)
|
||||
)
|
||||
}
|
||||
|
||||
test('packager includes all JavaScript files under dist/', () => {
|
||||
const distDir = path.resolve(repoRoot, 'dist')
|
||||
const distJsFiles = fs
|
||||
.readdirSync(distDir)
|
||||
.filter((name) => name.endsWith('.js'))
|
||||
.map((name) => path.join(distDir, name))
|
||||
|
||||
assert.ok(
|
||||
distJsFiles.length > 0,
|
||||
'Expected dist/ to contain at least one JavaScript file for packaging checks'
|
||||
)
|
||||
|
||||
const extraResources = collectExtraResources()
|
||||
|
||||
for (const jsFile of distJsFiles) {
|
||||
assert.ok(
|
||||
isCoveredByExtraResources(jsFile, extraResources),
|
||||
`Expected extraResource to include or cover ${jsFile}`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
test('packager includes dist/build directory', () => {
|
||||
const distBuildDir = path.resolve(repoRoot, 'dist/build')
|
||||
|
||||
assert.ok(
|
||||
fs.existsSync(distBuildDir),
|
||||
'Expected dist/build directory to exist for packaging checks'
|
||||
)
|
||||
|
||||
const extraResources = collectExtraResources()
|
||||
|
||||
assert.ok(
|
||||
isCoveredByExtraResources(distBuildDir, extraResources),
|
||||
`Expected extraResource to include or cover ${distBuildDir}`
|
||||
)
|
||||
})
|
||||
BIN
resources/icon.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
resources/icon_monochrome.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
1297
resources/icons.edn
Normal file
BIN
resources/icons/canary/logseq.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/icons/canary/logseq.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
resources/icons/canary/logseq_big_sur.icns
Normal file
BIN
resources/icons/canary/logseq_big_sur.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
resources/icons/canary/logseq_big_sur.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
resources/icons/logseq.icns
Normal file
BIN
resources/icons/logseq.ico
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
resources/icons/logseq.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
resources/icons/logseq_big_sur.icns
Normal file
BIN
resources/icons/logseq_big_sur.ico
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
resources/icons/logseq_big_sur.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
resources/img/broken-avatar.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
resources/img/checker.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
resources/img/credits.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
resources/img/dark-theme.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
resources/img/dmg-bg.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
resources/img/file-edn.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
resources/img/file-sync-unavailale-nonbacker-dark.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
resources/img/file-sync-unavailale-nonbacker-light.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
resources/img/file-sync-welcome-backer-dark.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
resources/img/file-sync-welcome-backer-light.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
resources/img/folder-logo.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
resources/img/folder.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
resources/img/light-theme.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
resources/img/logo.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
resources/img/screenshot.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
resources/img/system-theme.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/img/theme-modes.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
resources/img/tutorial-thumb.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
resources/img/whiteboard-welcome-dark.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
resources/img/whiteboard-welcome-light.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
52
resources/index.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="minimum-scale=1, initial-scale=1, maximum-scale=1, width=device-width, shrink-to-fit=no" name="viewport">
|
||||
<link href="./css/tabler-icons.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="./css/inter.css" rel="stylesheet" type="text/css">
|
||||
<link href="./css/style.css" rel="stylesheet" type="text/css">
|
||||
<link href="./img/logo.png" rel="shortcut icon" type="image/png">
|
||||
<link href="./img/logo.png" rel="shortcut icon" sizes="192x192">
|
||||
<link href="./img/logo.png" rel="apple-touch-icon">
|
||||
<meta content="Logseq" name="apple-mobile-web-app-title">
|
||||
<meta content="yes" name="apple-mobile-web-app-capable">
|
||||
<meta content="yes" name="apple-touch-fullscreen">
|
||||
<meta content="black-translucent" name="apple-mobile-web-app-status-bar-style">
|
||||
<meta content="yes" name="mobile-web-app-capable">
|
||||
<meta content="summary" name="twitter:card">
|
||||
<meta content="A privacy-first, open-source platform for knowledge management and collaboration." name="twitter:description">
|
||||
<meta content="@logseq" name="twitter:site">
|
||||
<meta content="A privacy-first, open-source platform for knowledge management and collaboration." name="twitter:title">
|
||||
<meta content="https://asset.logseq.com/static/img/logo.png" name="twitter:image:src">
|
||||
<meta content="A privacy-first, open-source platform for knowledge management and collaboration." name="twitter:image:alt">
|
||||
<meta content="A privacy-first, open-source platform for knowledge management and collaboration." property="og:title">
|
||||
<meta content="site" property="og:type">
|
||||
<meta content="https://logseq.com" property="og:url">
|
||||
<meta content="https://asset.logseq.com/static/img/logo.png" property="og:image">
|
||||
<meta content="A privacy-first, open-source platform for knowledge management and collaboration." property="og:description">
|
||||
<title>Logseq: A privacy-first platform for knowledge management and collaboration</title>
|
||||
<meta content="logseq" property="og:site_name">
|
||||
<meta content="A privacy-first, open-source platform for knowledge management and collaboration." name="description">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>window.__LSP__HOST__ = true</script>
|
||||
<script>window.user = null</script>
|
||||
<script src="./js/magic_portal.js"></script>
|
||||
<script defer src="./js/highlight.min.js"></script>
|
||||
<script defer src="./js/interact.min.js"></script>
|
||||
<script defer src="./js/marked.umd.js"></script>
|
||||
<script defer type="module" src="./js/pdfjs/pdf.mjs"></script>
|
||||
<script defer type="module" src="./js/pdf_viewer3.mjs"></script>
|
||||
<script defer src="./js/eventemitter3.umd.min.js"></script>
|
||||
<script defer src="./js/photoswipe.umd.min.js"></script>
|
||||
<script defer src="./js/photoswipe-lightbox.umd.min.js"></script>
|
||||
<script defer src="./js/html2canvas.min.js"></script>
|
||||
<script defer src="./js/lsplugin.core.js"></script>
|
||||
<script defer src="./js/main.js"></script>
|
||||
<script defer src="./js/prop-types.min.js"></script>
|
||||
<script defer src="./js/tabler.ext.js"></script>
|
||||
<script defer src="./js/code-editor.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1
resources/js/eventemitter3.umd.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).EventEmitter3=t()}(this,(function(){"use strict";var e={};return function(e){var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function s(e,t,r,s,i){if("function"!=typeof r)throw new TypeError("The listener must be a function");var c=new o(r,s||e,i),f=n?n+t:t;return e._events[f]?e._events[f].fn?e._events[f]=[e._events[f],c]:e._events[f].push(c):(e._events[f]=c,e._eventsCount++),e}function i(e,t){0==--e._eventsCount?e._events=new r:delete e._events[t]}function c(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(n=!1)),c.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},c.prototype.listeners=function(e){var t=n?n+e:e,r=this._events[t];if(!r)return[];if(r.fn)return[r.fn];for(var o=0,s=r.length,i=new Array(s);o<s;o++)i[o]=r[o].fn;return i},c.prototype.listenerCount=function(e){var t=n?n+e:e,r=this._events[t];return r?r.fn?1:r.length:0},c.prototype.emit=function(e,t,r,o,s,i){var c=n?n+e:e;if(!this._events[c])return!1;var f,u,a=this._events[c],l=arguments.length;if(a.fn){switch(a.once&&this.removeListener(e,a.fn,void 0,!0),l){case 1:return a.fn.call(a.context),!0;case 2:return a.fn.call(a.context,t),!0;case 3:return a.fn.call(a.context,t,r),!0;case 4:return a.fn.call(a.context,t,r,o),!0;case 5:return a.fn.call(a.context,t,r,o,s),!0;case 6:return a.fn.call(a.context,t,r,o,s,i),!0}for(u=1,f=new Array(l-1);u<l;u++)f[u-1]=arguments[u];a.fn.apply(a.context,f)}else{var p,v=a.length;for(u=0;u<v;u++)switch(a[u].once&&this.removeListener(e,a[u].fn,void 0,!0),l){case 1:a[u].fn.call(a[u].context);break;case 2:a[u].fn.call(a[u].context,t);break;case 3:a[u].fn.call(a[u].context,t,r);break;case 4:a[u].fn.call(a[u].context,t,r,o);break;default:if(!f)for(p=1,f=new Array(l-1);p<l;p++)f[p-1]=arguments[p];a[u].fn.apply(a[u].context,f)}}return!0},c.prototype.on=function(e,t,n){return s(this,e,t,n,!1)},c.prototype.once=function(e,t,n){return s(this,e,t,n,!0)},c.prototype.removeListener=function(e,t,r,o){var s=n?n+e:e;if(!this._events[s])return this;if(!t)return i(this,s),this;var c=this._events[s];if(c.fn)c.fn!==t||o&&!c.once||r&&c.context!==r||i(this,s);else{for(var f=0,u=[],a=c.length;f<a;f++)(c[f].fn!==t||o&&!c[f].once||r&&c[f].context!==r)&&u.push(c[f]);u.length?this._events[s]=1===u.length?u[0]:u:i(this,s)}return this},c.prototype.removeAllListeners=function(e){var t;return e?(t=n?n+e:e,this._events[t]&&i(this,t)):(this._events=new r,this._eventsCount=0),this},c.prototype.off=c.prototype.removeListener,c.prototype.addListener=c.prototype.on,c.prefixed=n,c.EventEmitter=c,e.exports=c}({get exports(){return e},set exports(t){e=t}}),e}));//# sourceMappingURL=eventemitter3.umd.min.js.map
|
||||
2
resources/js/lsplugin.core.js
Normal file
1
resources/js/lsplugin.core.js.LICENSE.txt
Normal file
@@ -0,0 +1 @@
|
||||
/*! @license DOMPurify 3.3.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.3/LICENSE */
|
||||
2
resources/js/lsplugin.user.js
Normal file
1
resources/js/lsplugin.user.js.LICENSE.txt
Normal file
@@ -0,0 +1 @@
|
||||
/*! @license DOMPurify 3.3.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.3/LICENSE */
|
||||
1
resources/js/magic_portal.js
Normal file
@@ -0,0 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.MagicPortal=t()}(this,function(){var e=function(e){var t=this;this.rpc_counter=0,this.channel=e,this.foreign=new Map,this.local=new Map,this.calls=new Map,this.queue=[],this.connectionEstablished=!1,this.channel.addEventListener("message",function(e){var n=e.data;if(n&&"object"==typeof n)switch(n.type){case"MP_INIT":return t.onInit(n);case"MP_SET":return t.onSet(n);case"MP_CALL":return t.onCall(n);case"MP_RETURN":return t.onReturn(n)}}),this.channel.postMessage({type:"MP_INIT",id:1,reply:!0})};e.prototype.onInit=function(e){this.connectionEstablished=!0;var t=this.queue;this.queue=[];for(var n=0,o=t;n<o.length;n+=1){this.channel.postMessage(o[n])}e.reply&&this.channel.postMessage({type:"MP_INIT",reply:!1})},e.prototype.onSet=function(e){for(var t=this,n={},o=e.object,i=function(){var i=r[s],c=!e.void.includes(i);n[i]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];return t.rpc_counter=(t.rpc_counter+1)%Number.MAX_SAFE_INTEGER,new Promise(function(n,s){t.postMessage({type:"MP_CALL",object:o,method:i,id:t.rpc_counter,args:e,reply:c}),c?t.calls.set(t.rpc_counter,{resolve:n,reject:s}):n()})}},s=0,r=e.methods;s<r.length;s+=1)i();var c=this.foreign.get(e.object);this.foreign.set(e.object,n),"function"==typeof c&&c(n)},e.prototype.onCall=function(e){var t=this,n=this.local.get(e.object);n&&n[e.method].apply(n,e.args).then(function(n){return e.reply&&t.channel.postMessage({type:"MP_RETURN",id:e.id,result:n})}).catch(function(n){return t.channel.postMessage({type:"MP_RETURN",id:e.id,error:n.message})})},e.prototype.onReturn=function(e){if(this.calls.has(e.id)){var t=this.calls.get(e.id),n=t.resolve,o=t.reject;this.calls.delete(e.id),e.error?o(e.error):n(e.result)}},e.prototype.postMessage=function(e){this.connectionEstablished?this.channel.postMessage(e):this.queue.push(e)},e.prototype.set=function(e,t,n){void 0===n&&(n={}),this.local.set(e,t);var o=Object.entries(t).filter(function(e){return"function"==typeof e[1]}).map(function(e){return e[0]});this.postMessage({type:"MP_SET",object:e,methods:o,void:n.void||[]})},e.prototype.get=function(e){return new Promise(function(t,n){var o=this;return this.foreign.has(e)?t(this.foreign.get(e)):t(new Promise(function(t,n){return o.foreign.set(e,t)}))}.bind(this))};return function(t){var n=new e(t);Object.defineProperties(this,{get:{writable:!1,configurable:!1,value:n.get.bind(n)},set:{writable:!1,configurable:!1,value:n.set.bind(n)}})}});
|
||||
12391
resources/js/pdf_viewer3.mjs
Normal file
163
resources/js/preload.js
Normal file
@@ -0,0 +1,163 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const { ipcRenderer, contextBridge, shell, clipboard, webFrame, webUtils } = require('electron')
|
||||
|
||||
const IS_MAC = process.platform === 'darwin'
|
||||
const IS_WIN32 = process.platform === 'win32'
|
||||
|
||||
const ALLOWED_EXTERNAL_PROTOCOLS = ['https:', 'http:', 'mailto:', 'zotero:', 'file:']
|
||||
|
||||
function getFilePathFromClipboard () {
|
||||
if (IS_WIN32) {
|
||||
const rawFilePath = clipboard.read('FileNameW')
|
||||
return rawFilePath.replace(new RegExp(String.fromCharCode(0), 'g'), '')
|
||||
} else if (IS_MAC) {
|
||||
return clipboard.read('public.file-url').replace('file://', '')
|
||||
} else {
|
||||
return clipboard.readText()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the contents of the clipboard for a custom format.
|
||||
* @param {string} format The custom format to read.
|
||||
* @returns Buffer containing the contents of the clipboard for the specified format, or null if not available.
|
||||
*/
|
||||
function getClipboardData (format) {
|
||||
if (clipboard.has(format, "clipboard")) {
|
||||
return clipboard.readBuffer(format)
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
contextBridge.exposeInMainWorld('apis', {
|
||||
getFilePath: (file) => webUtils.getPathForFile(file),
|
||||
|
||||
doAction: async (arg) => {
|
||||
return await ipcRenderer.invoke('main', arg)
|
||||
},
|
||||
|
||||
invoke: async (channel, args) => {
|
||||
return await ipcRenderer.invoke(channel, ...args)
|
||||
},
|
||||
|
||||
addListener: ipcRenderer.on.bind(ipcRenderer),
|
||||
removeListener: ipcRenderer.removeListener.bind(ipcRenderer),
|
||||
removeAllListeners: ipcRenderer.removeAllListeners.bind(ipcRenderer),
|
||||
|
||||
on: (channel, callback) => {
|
||||
const newCallback = (_, data) => callback(data)
|
||||
ipcRenderer.on(channel, newCallback)
|
||||
},
|
||||
|
||||
off: (channel, callback) => {
|
||||
if (!callback) {
|
||||
ipcRenderer.removeAllListeners(channel)
|
||||
} else {
|
||||
ipcRenderer.removeListener(channel, callback)
|
||||
}
|
||||
},
|
||||
|
||||
once: (channel, callback) => {
|
||||
ipcRenderer.on(channel, callback)
|
||||
},
|
||||
|
||||
checkForUpdates: async (...args) => {
|
||||
await ipcRenderer.invoke('check-for-updates', ...args)
|
||||
},
|
||||
|
||||
setUpdatesCallback (cb) {
|
||||
if (typeof cb !== 'function') return
|
||||
|
||||
const channel = 'updates-callback'
|
||||
ipcRenderer.removeAllListeners(channel)
|
||||
ipcRenderer.on(channel, cb)
|
||||
},
|
||||
|
||||
installUpdatesAndQuitApp () {
|
||||
ipcRenderer.invoke('install-updates', true)
|
||||
},
|
||||
|
||||
async openExternal (url, options) {
|
||||
const protocol = new URL(url).protocol
|
||||
if (!ALLOWED_EXTERNAL_PROTOCOLS.includes(protocol)) {
|
||||
throw new Error('illegal protocol')
|
||||
}
|
||||
await shell.openExternal(url, options)
|
||||
},
|
||||
|
||||
async openPath (relativePath) {
|
||||
const absolutePath = path.resolve(
|
||||
relativePath.startsWith('~') ? path.join(os.homedir(), relativePath.slice(1)) : relativePath
|
||||
);
|
||||
await shell.openPath(absolutePath)
|
||||
},
|
||||
|
||||
/**
|
||||
* save all publish assets to disk
|
||||
*
|
||||
* @param {string} html html file with embedded state
|
||||
*/
|
||||
exportPublishAssets (html, customCSSPath, exportCSSPath, repoPath, assetFilenames, outputDir) {
|
||||
ipcRenderer.invoke(
|
||||
'export-publish-assets',
|
||||
html,
|
||||
customCSSPath,
|
||||
exportCSSPath,
|
||||
repoPath,
|
||||
assetFilenames,
|
||||
outputDir
|
||||
)
|
||||
},
|
||||
|
||||
toggleMaxOrMinActiveWindow (isToggleMin = false) {
|
||||
ipcRenderer.invoke('toggle-max-or-min-active-win', isToggleMin)
|
||||
},
|
||||
|
||||
/**
|
||||
* internal
|
||||
* @param type
|
||||
* @param args
|
||||
* @private
|
||||
*/
|
||||
async _callApplication (type, ...args) {
|
||||
return await ipcRenderer.invoke('call-application', type, ...args)
|
||||
},
|
||||
|
||||
/**
|
||||
* internal
|
||||
* @param type
|
||||
* @param args
|
||||
* @private
|
||||
*/
|
||||
async _callMainWin (type, ...args) {
|
||||
return await ipcRenderer.invoke('call-main-win', type, ...args)
|
||||
},
|
||||
|
||||
/**
|
||||
* Write binary data to a file, creating parent dirs as needed.
|
||||
* Used for asset files that can't be transit-serialized through doAction.
|
||||
*/
|
||||
writeFileBytes (filePath, data) {
|
||||
const dir = path.dirname(filePath)
|
||||
fs.mkdirSync(dir, { recursive: true })
|
||||
fs.writeFileSync(filePath, Buffer.from(data))
|
||||
},
|
||||
|
||||
getFilePathFromClipboard,
|
||||
|
||||
getClipboardData,
|
||||
|
||||
setZoomFactor (factor) {
|
||||
webFrame.setZoomFactor(factor)
|
||||
},
|
||||
|
||||
setZoomLevel (level) {
|
||||
webFrame.setZoomLevel(level)
|
||||
},
|
||||
|
||||
isAbsolutePath: path.isAbsolute.bind(path)
|
||||
})
|
||||
1
resources/js/tabler.ext.js
Normal file
56
resources/js/worker.js
Normal file
@@ -0,0 +1,56 @@
|
||||
importScripts(
|
||||
// Batched optimization
|
||||
"./lightning-fs.min.js",
|
||||
// Fixed a bug
|
||||
"./magic_portal.js"
|
||||
);
|
||||
|
||||
const detect = () => {
|
||||
if (typeof window !== 'undefined' && !self.skipWaiting) {
|
||||
return 'window'
|
||||
} else if (typeof self !== 'undefined' && !self.skipWaiting) {
|
||||
return 'Worker'
|
||||
} else if (typeof self !== 'undefined' && self.skipWaiting) {
|
||||
return 'ServiceWorker'
|
||||
}
|
||||
};
|
||||
|
||||
const fsName = 'logseq';
|
||||
const createFS = () => new LightningFS(fsName);
|
||||
let fs = createFS();
|
||||
let pfs = fs.promises;
|
||||
|
||||
if (typeof self !== 'undefined') {
|
||||
self.fs = fs;
|
||||
self.pfs = pfs;
|
||||
}
|
||||
|
||||
if (detect() === 'Worker') {
|
||||
const portal = new MagicPortal(self);
|
||||
portal.set('fs', fs);
|
||||
portal.set('pfs', pfs);
|
||||
|
||||
portal.set('workerThread', {
|
||||
rimraf: async function (path) {
|
||||
// Knowing path is a directory,
|
||||
// first, assume everything inside path is a file.
|
||||
let files = await pfs.readdir(path);
|
||||
for (let file of files) {
|
||||
let child = path + '/' + file
|
||||
try {
|
||||
await pfs.unlink(child)
|
||||
} catch (err) {
|
||||
if (err.code !== 'EISDIR') throw err
|
||||
}
|
||||
}
|
||||
// Assume what's left are directories and recurse.
|
||||
let dirs = await pfs.readdir(path)
|
||||
for (let dir of dirs) {
|
||||
let child = path + '/' + dir
|
||||
await rimraf(child, pfs)
|
||||
}
|
||||
// Finally, delete the empty directory
|
||||
await pfs.rmdir(path)
|
||||
}
|
||||
});
|
||||
}
|
||||
168
resources/marketplace.html
Normal file
@@ -0,0 +1,168 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Logseq Marketplace</title>
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/4.0.0/github-markdown.min.css"
|
||||
integrity="sha512-Oy18vBnbSJkXTndr2n6lDMO5NN31UljR8e/ICzVPrGpSud4Gkckb8yUpqhKuUNoE+o9gAb4O/rAxxw1ojyUVzg=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"/>
|
||||
<style>
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: sans-serif;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar-thumb:active {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
width: 900px;
|
||||
min-height: 100%;
|
||||
padding: 30px;
|
||||
margin: 0 auto;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#app > strong {
|
||||
padding-top: 30vh;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
pre {
|
||||
max-width: 800px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="./js/marked.umd.js"></script>
|
||||
<script src="./js/purify.js"></script>
|
||||
<script>
|
||||
;(async function () {
|
||||
const app = document.getElementById('app')
|
||||
const url = new URL(location.href)
|
||||
const setMsg = (msg) => app.innerHTML = `<strong>${msg}</strong>`
|
||||
const repo = url.searchParams.get('repo')
|
||||
if (!repo) {
|
||||
return setMsg('Repo parameter not found!')
|
||||
}
|
||||
|
||||
const setContent = (content) => app.innerHTML = `<main class="markdown-body">${content}</main>`
|
||||
const endpoint = (repo, branch, file) => `https://raw.githubusercontent.com/${repo}/${branch}/${file}`
|
||||
|
||||
let defaultPoints = [
|
||||
endpoint(repo, 'master', 'README.md'), endpoint(repo, 'main', 'README.md'),
|
||||
endpoint(repo, 'master', 'readme.md'), endpoint(repo, 'main', 'readme.md')]
|
||||
|
||||
let content = ''
|
||||
let readme
|
||||
|
||||
const fixLink = (link) => readme.replace(/[^\/]+\.md$/i, link)
|
||||
const isRelative = (href) => href && !href.startsWith('http') && !!href.match(/^([.\/]+|[^\/]+)/) &&
|
||||
href.replace(/^[.\/]+/, '')
|
||||
|
||||
marked.use({
|
||||
renderer: {
|
||||
link({ href, title, text }) {
|
||||
return `<a href="${href}" target="_blank" title="${title}">${text}</a>`
|
||||
},
|
||||
|
||||
image({ href, title, text }) {
|
||||
let link = isRelative(href)
|
||||
|
||||
if (link) {
|
||||
link = fixLink(link)
|
||||
return `<img style="max-width: 100%;" src="${link}" alt="${title}" />`
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// force fix Markdown content
|
||||
function fixAllImageTagHref (content) {
|
||||
const isRelativeImageSrc = (src) => src && !src.match(/^(?:[a-z][a-z\d+.-]*:|\/\/|#)/i) && isRelative(src)
|
||||
|
||||
return content.replace(/<img\b[^>]*>/gi, (img) => {
|
||||
return img.replace(/\bsrc\s*=\s*(['"]?)([^'"\s>]+)\1/i, (attr, quote, src) => {
|
||||
const link = isRelativeImageSrc(src)
|
||||
return link ? attr.replace(src, fixLink(link)) : attr
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// load exist points content
|
||||
async function loadPage(points) {
|
||||
setMsg('Loading ...')
|
||||
|
||||
for (let url of points) {
|
||||
try {
|
||||
const res = await fetch(url)
|
||||
if (res.status !== 200) {
|
||||
throw new Error(res.statusText)
|
||||
}
|
||||
content = await res.text()
|
||||
readme = url
|
||||
break
|
||||
} catch (e) {
|
||||
console.debug('Error:', url, e.message)
|
||||
}
|
||||
}
|
||||
|
||||
content = marked.parse(fixAllImageTagHref(content))
|
||||
setContent(DOMPurify.sanitize(content))
|
||||
}
|
||||
|
||||
// load default
|
||||
await loadPage(defaultPoints)
|
||||
|
||||
// handle link
|
||||
document.querySelector('#app').addEventListener('click', (e) => {
|
||||
const target = e.target
|
||||
const href = target.getAttribute('href')
|
||||
if (!!href && href.endsWith('.md') && !href.startsWith('http')) {
|
||||
loadPage([
|
||||
endpoint(repo, 'master', href),
|
||||
endpoint(repo, 'main', href)
|
||||
])
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
}())
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
resources/mobile/android/icon-background.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
resources/mobile/android/icon-foreground.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
resources/mobile/android/icon/drawable-hdpi-icon.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/mobile/android/icon/drawable-ldpi-icon.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/mobile/android/icon/drawable-mdpi-icon.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
resources/mobile/android/icon/drawable-xhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
resources/mobile/android/icon/drawable-xxhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
resources/mobile/android/icon/drawable-xxxhdpi-icon.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
resources/mobile/android/icon/hdpi-background.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
resources/mobile/android/icon/hdpi-foreground.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
resources/mobile/android/icon/ldpi-background.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/mobile/android/icon/ldpi-foreground.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/mobile/android/icon/mdpi-background.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
resources/mobile/android/icon/mdpi-foreground.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
resources/mobile/android/icon/xhdpi-background.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
resources/mobile/android/icon/xhdpi-foreground.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
resources/mobile/android/icon/xxhdpi-background.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
resources/mobile/android/icon/xxhdpi-foreground.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
resources/mobile/android/icon/xxxhdpi-background.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
resources/mobile/android/icon/xxxhdpi-foreground.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
resources/mobile/android/splash/drawable-land-hdpi-screen.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
resources/mobile/android/splash/drawable-land-ldpi-screen.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
resources/mobile/android/splash/drawable-land-mdpi-screen.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/mobile/android/splash/drawable-land-xhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/mobile/android/splash/drawable-land-xxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
resources/mobile/android/splash/drawable-land-xxxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
resources/mobile/android/splash/drawable-port-hdpi-screen.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
resources/mobile/android/splash/drawable-port-ldpi-screen.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
resources/mobile/android/splash/drawable-port-mdpi-screen.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/mobile/android/splash/drawable-port-xhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
resources/mobile/android/splash/drawable-port-xxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
resources/mobile/android/splash/drawable-port-xxxhdpi-screen.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
29
resources/mobile/index.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-color="logseq">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, viewport-fit=cover, user-scalable=no">
|
||||
<link href="./css/style.css" rel="stylesheet" type="text/css">
|
||||
<title>Logseq: A privacy-first platform for knowledge management and collaboration</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>var isCapacitorNew=true</script>
|
||||
<script src="./js/magic_portal.js"></script>
|
||||
<script defer src="./js/highlight.min.js"></script>
|
||||
<script defer src="./js/interact.min.js"></script>
|
||||
<script defer src="./js/marked.umd.js"></script>
|
||||
<script defer src="./js/eventemitter3.umd.min.js"></script>
|
||||
<script defer src="./js/photoswipe.umd.min.js"></script>
|
||||
<script defer src="./js/photoswipe-lightbox.umd.min.js"></script>
|
||||
<script defer src="./js/prop-types.min.js"></script>
|
||||
<script defer src="./js/main.js"></script>
|
||||
<script defer src="./js/tabler.ext.js"></script>
|
||||
<script defer src="./js/code-editor.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.Capacitor?.Plugins?.SplashScreen?.hide()
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
resources/mobile/ios/icon/icon-1024.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
resources/mobile/ios/icon/icon-108@2x.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
resources/mobile/ios/icon/icon-20.png
Normal file
|
After Width: | Height: | Size: 575 B |
BIN
resources/mobile/ios/icon/icon-20@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/mobile/ios/icon/icon-20@3x.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
resources/mobile/ios/icon/icon-24@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |