Compare commits
2 Commits
v0.2025.11
...
tasiaiso-n
| Author | SHA1 | Date | |
|---|---|---|---|
|
d67e47ae4b
|
|||
|
b43b8da9ab
|
@@ -48,7 +48,7 @@ jobs:
|
|||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
run: |
|
run: |
|
||||||
mkdir -p out/html/ ~/.ssh/
|
mkdir -p out/html/ ~/.ssh/
|
||||||
make -j`nproc` docs
|
make docs
|
||||||
echo 'pildefriends ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKD3Kde5vDO0TrMBDK0IGGeNGe/XinWAZkSQ/rXxwUjt' >> ~/.ssh/known_hosts
|
echo 'pildefriends ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKD3Kde5vDO0TrMBDK0IGGeNGe/XinWAZkSQ/rXxwUjt' >> ~/.ssh/known_hosts
|
||||||
rsync -avP --delete -e "ssh -i /opt/keys/ssh.ed25519" out/html/ tfdocs@pildefriends:docs/html/
|
rsync -avP --delete -e "ssh -i /opt/keys/ssh.ed25519" out/html/ tfdocs@pildefriends:docs/html/
|
||||||
- name: Setup JDK
|
- name: Setup JDK
|
||||||
@@ -59,11 +59,11 @@ jobs:
|
|||||||
- name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
uses: android-actions/setup-android@v3
|
uses: android-actions/setup-android@v3
|
||||||
with:
|
with:
|
||||||
packages: 'tools platform-tools build-tools;35.0.0 platforms;android-35 ndk;27.2.12479018'
|
packages: 'tools platform-tools build-tools;34.0.0 platforms;android-34 ndk;26.3.11579264'
|
||||||
- name: Docker build
|
- name: Docker build
|
||||||
run: DOCKER_BUILDKIT=1 docker build .
|
run: DOCKER_BUILDKIT=1 docker build .
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all dist
|
run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all dist docs
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
4
.gitmodules
vendored
@@ -19,6 +19,10 @@
|
|||||||
[submodule "deps/picohttpparser"]
|
[submodule "deps/picohttpparser"]
|
||||||
path = deps/picohttpparser
|
path = deps/picohttpparser
|
||||||
url = https://github.com/h2o/picohttpparser.git
|
url = https://github.com/h2o/picohttpparser.git
|
||||||
|
[submodule "deps/openssl_src"]
|
||||||
|
path = deps/openssl_src
|
||||||
|
url = https://github.com/openssl/openssl.git
|
||||||
|
shallow = true
|
||||||
[submodule "deps/c-ares"]
|
[submodule "deps/c-ares"]
|
||||||
path = deps/c-ares
|
path = deps/c-ares
|
||||||
url = https://github.com/c-ares/c-ares.git
|
url = https://github.com/c-ares/c-ares.git
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ src
|
|||||||
deps
|
deps
|
||||||
.clang-format
|
.clang-format
|
||||||
flake.lock
|
flake.lock
|
||||||
apps/trace/speedscope/**
|
|
||||||
|
|
||||||
# Minified files
|
# Minified files
|
||||||
**/*.min.css
|
**/*.min.css
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ RUN apt-get update && \
|
|||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
gcc \
|
gcc \
|
||||||
libc6-dev \
|
libc6-dev \
|
||||||
|
perl \
|
||||||
make
|
make
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|||||||
370
Doxyfile
@@ -1,4 +1,4 @@
|
|||||||
# Doxyfile 1.9.4
|
# Doxyfile 1.9.8
|
||||||
|
|
||||||
# This file describes the settings to be used by the documentation system
|
# This file describes the settings to be used by the documentation system
|
||||||
# doxygen (www.doxygen.org) for a project.
|
# doxygen (www.doxygen.org) for a project.
|
||||||
@@ -19,7 +19,8 @@
|
|||||||
# configuration file:
|
# configuration file:
|
||||||
# doxygen -x [configFile]
|
# doxygen -x [configFile]
|
||||||
# Use doxygen to compare the used configuration file with the template
|
# Use doxygen to compare the used configuration file with the template
|
||||||
# configuration file without replacing the environment variables:
|
# configuration file without replacing the environment variables or CMake type
|
||||||
|
# replacement variables:
|
||||||
# doxygen -x_noenv [configFile]
|
# doxygen -x_noenv [configFile]
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -85,7 +86,7 @@ CREATE_SUBDIRS = NO
|
|||||||
# level increment doubles the number of directories, resulting in 4096
|
# level increment doubles the number of directories, resulting in 4096
|
||||||
# directories at level 8 which is the default and also the maximum value. The
|
# directories at level 8 which is the default and also the maximum value. The
|
||||||
# sub-directories are organized in 2 levels, the first level always has a fixed
|
# sub-directories are organized in 2 levels, the first level always has a fixed
|
||||||
# numer of 16 directories.
|
# number of 16 directories.
|
||||||
# Minimum value: 0, maximum value: 8, default value: 8.
|
# Minimum value: 0, maximum value: 8, default value: 8.
|
||||||
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
|
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
|
||||||
|
|
||||||
@@ -341,7 +342,7 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
|||||||
#
|
#
|
||||||
# Note see also the list of default file extension mappings.
|
# Note see also the list of default file extension mappings.
|
||||||
|
|
||||||
EXTENSION_MAPPING = js=javascript
|
EXTENSION_MAPPING =
|
||||||
|
|
||||||
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
||||||
# according to the Markdown format, which allows for more readable
|
# according to the Markdown format, which allows for more readable
|
||||||
@@ -362,6 +363,17 @@ MARKDOWN_SUPPORT = YES
|
|||||||
|
|
||||||
TOC_INCLUDE_HEADINGS = 5
|
TOC_INCLUDE_HEADINGS = 5
|
||||||
|
|
||||||
|
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
|
||||||
|
# generate identifiers for the Markdown headings. Note: Every identifier is
|
||||||
|
# unique.
|
||||||
|
# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
|
||||||
|
# sequence number starting at 0 and GITHUB use the lower case version of title
|
||||||
|
# with any whitespace replaced by '-' and punctuation characters removed.
|
||||||
|
# The default value is: DOXYGEN.
|
||||||
|
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
||||||
|
|
||||||
|
MARKDOWN_ID_STYLE = DOXYGEN
|
||||||
|
|
||||||
# When enabled doxygen tries to link words that correspond to documented
|
# When enabled doxygen tries to link words that correspond to documented
|
||||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||||
# be prevented in individual cases by putting a % sign in front of the word or
|
# be prevented in individual cases by putting a % sign in front of the word or
|
||||||
@@ -486,6 +498,14 @@ LOOKUP_CACHE_SIZE = 0
|
|||||||
|
|
||||||
NUM_PROC_THREADS = 1
|
NUM_PROC_THREADS = 1
|
||||||
|
|
||||||
|
# If the TIMESTAMP tag is set different from NO then each generated page will
|
||||||
|
# contain the date or date and time when the page was generated. Setting this to
|
||||||
|
# NO can help when comparing the output of multiple runs.
|
||||||
|
# Possible values are: YES, NO, DATETIME and DATE.
|
||||||
|
# The default value is: NO.
|
||||||
|
|
||||||
|
TIMESTAMP = NO
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Build related configuration options
|
# Build related configuration options
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -567,7 +587,8 @@ HIDE_UNDOC_MEMBERS = NO
|
|||||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
||||||
# undocumented classes that are normally visible in the class hierarchy. If set
|
# undocumented classes that are normally visible in the class hierarchy. If set
|
||||||
# to NO, these classes will be included in the various overviews. This option
|
# to NO, these classes will be included in the various overviews. This option
|
||||||
# has no effect if EXTRACT_ALL is enabled.
|
# will also hide undocumented C++ concepts if enabled. This option has no effect
|
||||||
|
# if EXTRACT_ALL is enabled.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
HIDE_UNDOC_CLASSES = NO
|
HIDE_UNDOC_CLASSES = NO
|
||||||
@@ -605,7 +626,8 @@ INTERNAL_DOCS = NO
|
|||||||
# Windows (including Cygwin) and MacOS, users should typically set this option
|
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||||
# YES.
|
# YES.
|
||||||
# The default value is: system dependent.
|
# Possible values are: SYSTEM, NO and YES.
|
||||||
|
# The default value is: SYSTEM.
|
||||||
|
|
||||||
CASE_SENSE_NAMES = YES
|
CASE_SENSE_NAMES = YES
|
||||||
|
|
||||||
@@ -857,11 +879,26 @@ WARN_IF_INCOMPLETE_DOC = YES
|
|||||||
|
|
||||||
WARN_NO_PARAMDOC = NO
|
WARN_NO_PARAMDOC = NO
|
||||||
|
|
||||||
|
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
|
||||||
|
# undocumented enumeration values. If set to NO, doxygen will accept
|
||||||
|
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
|
||||||
|
# will automatically be disabled.
|
||||||
|
# The default value is: NO.
|
||||||
|
|
||||||
|
WARN_IF_UNDOC_ENUM_VAL = NO
|
||||||
|
|
||||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||||
# at the end of the doxygen process doxygen will return with a non-zero status.
|
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
|
||||||
|
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
|
||||||
|
# write the warning messages in between other messages but write them at the end
|
||||||
|
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
|
||||||
|
# besides being in the defined file also be shown at the end of a run, unless
|
||||||
|
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
|
||||||
|
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
|
||||||
|
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
WARN_AS_ERROR = NO
|
WARN_AS_ERROR = NO
|
||||||
@@ -906,23 +943,28 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = README.md \
|
INPUT = README.md docs/ src/
|
||||||
core/app.js \
|
|
||||||
core/client.js \
|
|
||||||
core/core.js \
|
|
||||||
core/tfrpc.js \
|
|
||||||
docs/ \
|
|
||||||
src/
|
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||||
# documentation (see:
|
# documentation (see:
|
||||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||||
|
# See also: INPUT_FILE_ENCODING
|
||||||
# The default value is: UTF-8.
|
# The default value is: UTF-8.
|
||||||
|
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
|
|
||||||
|
# This tag can be used to specify the character encoding of the source files
|
||||||
|
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
|
||||||
|
# character encoding on a per file pattern basis. Doxygen will compare the file
|
||||||
|
# name with each pattern and apply the encoding instead of the default
|
||||||
|
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
|
||||||
|
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
|
||||||
|
# "INPUT_ENCODING" for further information on supported encodings.
|
||||||
|
|
||||||
|
INPUT_FILE_ENCODING =
|
||||||
|
|
||||||
# If the value of the INPUT tag contains directories, you can use the
|
# If the value of the INPUT tag contains directories, you can use the
|
||||||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
||||||
# *.h) to filter out the source-files in the directories.
|
# *.h) to filter out the source-files in the directories.
|
||||||
@@ -934,15 +976,14 @@ INPUT_ENCODING = UTF-8
|
|||||||
# Note the list of default checked file patterns might differ from the list of
|
# Note the list of default checked file patterns might differ from the list of
|
||||||
# default file extension mappings.
|
# default file extension mappings.
|
||||||
#
|
#
|
||||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
|
||||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl,
|
||||||
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
|
# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php,
|
||||||
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
|
# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be
|
||||||
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
|
# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||||
# *.vhdl, *.ucf, *.qsf and *.ice.
|
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
||||||
|
|
||||||
FILE_PATTERNS = *.h \
|
FILE_PATTERNS = *.h \
|
||||||
*.js \
|
|
||||||
*.md
|
*.md
|
||||||
|
|
||||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||||
@@ -981,9 +1022,6 @@ EXCLUDE_PATTERNS =
|
|||||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||||
# ANamespace::AClass, ANamespace::*Test
|
# ANamespace::AClass, ANamespace::*Test
|
||||||
#
|
|
||||||
# Note that the wildcards are matched against the file with absolute path, so to
|
|
||||||
# exclude all test directories use the pattern */test/*
|
|
||||||
|
|
||||||
EXCLUDE_SYMBOLS =
|
EXCLUDE_SYMBOLS =
|
||||||
|
|
||||||
@@ -1011,7 +1049,7 @@ EXAMPLE_RECURSIVE = NO
|
|||||||
# that contain images that are to be included in the documentation (see the
|
# that contain images that are to be included in the documentation (see the
|
||||||
# \image command).
|
# \image command).
|
||||||
|
|
||||||
IMAGE_PATH = docs/images/
|
IMAGE_PATH =
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
@@ -1028,6 +1066,11 @@ IMAGE_PATH = docs/images/
|
|||||||
# code is scanned, but not when the output code is generated. If lines are added
|
# code is scanned, but not when the output code is generated. If lines are added
|
||||||
# or removed, the anchors will not be placed correctly.
|
# or removed, the anchors will not be placed correctly.
|
||||||
#
|
#
|
||||||
|
# Note that doxygen will use the data processed and written to standard output
|
||||||
|
# for further processing, therefore nothing else, like debug statements or used
|
||||||
|
# commands (so in case of a Windows batch file always use @echo OFF), should be
|
||||||
|
# written to standard output.
|
||||||
|
#
|
||||||
# Note that for custom extensions or not directly supported extensions you also
|
# Note that for custom extensions or not directly supported extensions you also
|
||||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||||
# properly processed by doxygen.
|
# properly processed by doxygen.
|
||||||
@@ -1069,6 +1112,15 @@ FILTER_SOURCE_PATTERNS =
|
|||||||
|
|
||||||
USE_MDFILE_AS_MAINPAGE = README.md
|
USE_MDFILE_AS_MAINPAGE = README.md
|
||||||
|
|
||||||
|
# The Fortran standard specifies that for fixed formatted Fortran code all
|
||||||
|
# characters from position 72 are to be considered as comment. A common
|
||||||
|
# extension is to allow longer lines before the automatic comment starts. The
|
||||||
|
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
|
||||||
|
# be processed before the automatic comment starts.
|
||||||
|
# Minimum value: 7, maximum value: 10000, default value: 72.
|
||||||
|
|
||||||
|
FORTRAN_COMMENT_AFTER = 72
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to source browsing
|
# Configuration options related to source browsing
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -1206,10 +1258,11 @@ CLANG_DATABASE_PATH =
|
|||||||
|
|
||||||
ALPHABETICAL_INDEX = YES
|
ALPHABETICAL_INDEX = YES
|
||||||
|
|
||||||
# In case all classes in a project start with a common prefix, all classes will
|
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
||||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
||||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
# tag works for classes, function and member names. The entity will be placed in
|
||||||
# while generating the index headers.
|
# the alphabetical list under the first letter of the entity name that remains
|
||||||
|
# after removing the prefix.
|
||||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
||||||
|
|
||||||
IGNORE_PREFIX =
|
IGNORE_PREFIX =
|
||||||
@@ -1288,7 +1341,12 @@ HTML_STYLESHEET =
|
|||||||
# Doxygen will copy the style sheet files to the output directory.
|
# Doxygen will copy the style sheet files to the output directory.
|
||||||
# Note: The order of the extra style sheet files is of importance (e.g. the last
|
# Note: The order of the extra style sheet files is of importance (e.g. the last
|
||||||
# style sheet in the list overrules the setting of the previous ones in the
|
# style sheet in the list overrules the setting of the previous ones in the
|
||||||
# list). For an example see the documentation.
|
# list).
|
||||||
|
# Note: Since the styling of scrollbars can currently not be overruled in
|
||||||
|
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
|
||||||
|
# one or more extra stylesheets have been specified. So if scrollbar
|
||||||
|
# customization is desired it has to be added explicitly. For an example see the
|
||||||
|
# documentation.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_EXTRA_STYLESHEET =
|
HTML_EXTRA_STYLESHEET =
|
||||||
@@ -1303,6 +1361,19 @@ HTML_EXTRA_STYLESHEET =
|
|||||||
|
|
||||||
HTML_EXTRA_FILES =
|
HTML_EXTRA_FILES =
|
||||||
|
|
||||||
|
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
|
||||||
|
# should be rendered with a dark or light theme.
|
||||||
|
# Possible values are: LIGHT always generate light mode output, DARK always
|
||||||
|
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
|
||||||
|
# the user preference, use light mode if no preference is set (the default),
|
||||||
|
# AUTO_DARK automatically set the mode according to the user preference, use
|
||||||
|
# dark mode if no preference is set and TOGGLE allow to user to switch between
|
||||||
|
# light and dark mode via a button.
|
||||||
|
# The default value is: AUTO_LIGHT.
|
||||||
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
|
HTML_COLORSTYLE = AUTO_LIGHT
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||||
# will adjust the colors in the style sheet and background images according to
|
# will adjust the colors in the style sheet and background images according to
|
||||||
# this color. Hue is specified as an angle on a color-wheel, see
|
# this color. Hue is specified as an angle on a color-wheel, see
|
||||||
@@ -1333,15 +1404,6 @@ HTML_COLORSTYLE_SAT = 100
|
|||||||
|
|
||||||
HTML_COLORSTYLE_GAMMA = 80
|
HTML_COLORSTYLE_GAMMA = 80
|
||||||
|
|
||||||
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
|
|
||||||
# page will contain the date and time when the page was generated. Setting this
|
|
||||||
# to YES can help to show when doxygen was last run and thus if the
|
|
||||||
# documentation is up to date.
|
|
||||||
# The default value is: NO.
|
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
|
||||||
|
|
||||||
#HTML_TIMESTAMP = NO
|
|
||||||
|
|
||||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||||
# documentation will contain a main index with vertical navigation menus that
|
# documentation will contain a main index with vertical navigation menus that
|
||||||
# are dynamically created via JavaScript. If disabled, the navigation index will
|
# are dynamically created via JavaScript. If disabled, the navigation index will
|
||||||
@@ -1361,6 +1423,13 @@ HTML_DYNAMIC_MENUS = YES
|
|||||||
|
|
||||||
HTML_DYNAMIC_SECTIONS = NO
|
HTML_DYNAMIC_SECTIONS = NO
|
||||||
|
|
||||||
|
# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
|
||||||
|
# dynamically folded and expanded in the generated HTML source code.
|
||||||
|
# The default value is: YES.
|
||||||
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
|
HTML_CODE_FOLDING = YES
|
||||||
|
|
||||||
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
|
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
|
||||||
# shown in the various tree structured indices initially; the user can expand
|
# shown in the various tree structured indices initially; the user can expand
|
||||||
# and collapse entries dynamically later on. Doxygen will expand the tree to
|
# and collapse entries dynamically later on. Doxygen will expand the tree to
|
||||||
@@ -1491,6 +1560,16 @@ BINARY_TOC = NO
|
|||||||
|
|
||||||
TOC_EXPAND = NO
|
TOC_EXPAND = NO
|
||||||
|
|
||||||
|
# The SITEMAP_URL tag is used to specify the full URL of the place where the
|
||||||
|
# generated documentation will be placed on the server by the user during the
|
||||||
|
# deployment of the documentation. The generated sitemap is called sitemap.xml
|
||||||
|
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
|
||||||
|
# is specified no sitemap is generated. For information about the sitemap
|
||||||
|
# protocol see https://www.sitemaps.org
|
||||||
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
|
SITEMAP_URL =
|
||||||
|
|
||||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
||||||
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
|
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
|
||||||
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
|
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
|
||||||
@@ -1666,17 +1745,6 @@ HTML_FORMULA_FORMAT = png
|
|||||||
|
|
||||||
FORMULA_FONTSIZE = 10
|
FORMULA_FONTSIZE = 10
|
||||||
|
|
||||||
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
|
|
||||||
# generated for formulas are transparent PNGs. Transparent PNGs are not
|
|
||||||
# supported properly for IE 6.0, but are supported on all modern browsers.
|
|
||||||
#
|
|
||||||
# Note that when changing this option you need to delete any form_*.png files in
|
|
||||||
# the HTML output directory before the changes have effect.
|
|
||||||
# The default value is: YES.
|
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
|
||||||
|
|
||||||
#FORMULA_TRANSPARENT = YES
|
|
||||||
|
|
||||||
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
||||||
# to create new LaTeX commands to be used in formulas as building blocks. See
|
# to create new LaTeX commands to be used in formulas as building blocks. See
|
||||||
# the section "Including formulas" for details.
|
# the section "Including formulas" for details.
|
||||||
@@ -1738,8 +1806,8 @@ MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2
|
|||||||
|
|
||||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||||
# extension names that should be enabled during MathJax rendering. For example
|
# extension names that should be enabled during MathJax rendering. For example
|
||||||
# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html
|
# for MathJax version 2 (see
|
||||||
# #tex-and-latex-extensions):
|
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
|
||||||
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
||||||
# For example for MathJax version 3 (see
|
# For example for MathJax version 3 (see
|
||||||
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
|
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
|
||||||
@@ -1990,9 +2058,16 @@ PDF_HYPERLINKS = YES
|
|||||||
|
|
||||||
USE_PDFLATEX = YES
|
USE_PDFLATEX = YES
|
||||||
|
|
||||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
|
# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
|
||||||
# command to the generated LaTeX files. This will instruct LaTeX to keep running
|
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
|
||||||
# if errors occur, instead of asking the user for help.
|
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
|
||||||
|
# hit at every error; missing files that TeX tries to input or request from
|
||||||
|
# keyboard input (\read on a not open input stream) cause the job to abort,
|
||||||
|
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
|
||||||
|
# but there is no possibility of user interaction just like in batch mode,
|
||||||
|
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
|
||||||
|
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
|
||||||
|
# each error, asking for user intervention.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
@@ -2013,14 +2088,6 @@ LATEX_HIDE_INDICES = NO
|
|||||||
|
|
||||||
LATEX_BIB_STYLE = plain
|
LATEX_BIB_STYLE = plain
|
||||||
|
|
||||||
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
|
|
||||||
# page will contain the date and time when the page was generated. Setting this
|
|
||||||
# to NO can help when comparing the output of multiple runs.
|
|
||||||
# The default value is: NO.
|
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
|
||||||
|
|
||||||
#LATEX_TIMESTAMP = NO
|
|
||||||
|
|
||||||
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
|
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
|
||||||
# path from which the emoji images will be read. If a relative path is entered,
|
# path from which the emoji images will be read. If a relative path is entered,
|
||||||
# it will be relative to the LATEX_OUTPUT directory. If left blank the
|
# it will be relative to the LATEX_OUTPUT directory. If left blank the
|
||||||
@@ -2186,13 +2253,39 @@ DOCBOOK_OUTPUT = docbook
|
|||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
|
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
|
||||||
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
|
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
|
||||||
# the structure of the code including all documentation. Note that this feature
|
# the structure of the code including all documentation. Note that this feature
|
||||||
# is still experimental and incomplete at the moment.
|
# is still experimental and incomplete at the moment.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
GENERATE_AUTOGEN_DEF = NO
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to Sqlite3 output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
|
||||||
|
# database with symbols found by doxygen stored in tables.
|
||||||
|
# The default value is: NO.
|
||||||
|
|
||||||
|
GENERATE_SQLITE3 = NO
|
||||||
|
|
||||||
|
# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
|
||||||
|
# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
|
||||||
|
# in front of it.
|
||||||
|
# The default directory is: sqlite3.
|
||||||
|
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
|
||||||
|
|
||||||
|
SQLITE3_OUTPUT = sqlite3
|
||||||
|
|
||||||
|
# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db
|
||||||
|
# database file will be recreated with each doxygen run. If set to NO, doxygen
|
||||||
|
# will warn if an a database file is already found and not modify it.
|
||||||
|
# The default value is: YES.
|
||||||
|
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
|
||||||
|
|
||||||
|
SQLITE3_RECREATE_DB = YES
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to the Perl module output
|
# Configuration options related to the Perl module output
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -2335,15 +2428,15 @@ TAGFILES =
|
|||||||
|
|
||||||
GENERATE_TAGFILE =
|
GENERATE_TAGFILE =
|
||||||
|
|
||||||
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
|
# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
|
||||||
# the class index. If set to NO, only the inherited external classes will be
|
# will be listed in the class and namespace index. If set to NO, only the
|
||||||
# listed.
|
# inherited external classes will be listed.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
ALLEXTERNALS = NO
|
ALLEXTERNALS = NO
|
||||||
|
|
||||||
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
|
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
|
||||||
# in the modules index. If set to NO, only the current project's groups will be
|
# in the topic index. If set to NO, only the current project's groups will be
|
||||||
# listed.
|
# listed.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
@@ -2357,16 +2450,9 @@ EXTERNAL_GROUPS = YES
|
|||||||
EXTERNAL_PAGES = YES
|
EXTERNAL_PAGES = YES
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to the dot tool
|
# Configuration options related to diagram generator tools
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
|
||||||
# then run dia to produce the diagram and insert it in the documentation. The
|
|
||||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
|
||||||
# If left empty dia is assumed to be found in the default search path.
|
|
||||||
|
|
||||||
DIA_PATH =
|
|
||||||
|
|
||||||
# If set to YES the inheritance and collaboration graphs will hide inheritance
|
# If set to YES the inheritance and collaboration graphs will hide inheritance
|
||||||
# and usage relations if the target is undocumented or is not a class.
|
# and usage relations if the target is undocumented or is not a class.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
@@ -2375,10 +2461,10 @@ HIDE_UNDOC_RELATIONS = YES
|
|||||||
|
|
||||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||||
# available from the path. This tool is part of Graphviz (see:
|
# available from the path. This tool is part of Graphviz (see:
|
||||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||||
# Bell Labs. The other options in this section have no effect if this option is
|
# Bell Labs. The other options in this section have no effect if this option is
|
||||||
# set to NO
|
# set to NO
|
||||||
# The default value is: NO.
|
# The default value is: YES.
|
||||||
|
|
||||||
HAVE_DOT = YES
|
HAVE_DOT = YES
|
||||||
|
|
||||||
@@ -2392,37 +2478,51 @@ HAVE_DOT = YES
|
|||||||
|
|
||||||
DOT_NUM_THREADS = 0
|
DOT_NUM_THREADS = 0
|
||||||
|
|
||||||
# When you want a differently looking font in the dot files that doxygen
|
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
|
||||||
# generates you can specify the font name using DOT_FONTNAME. You need to make
|
# subgraphs. When you want a differently looking font in the dot files that
|
||||||
# sure dot is able to find the font, which can be done by putting it in a
|
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
|
||||||
# standard location or by setting the DOTFONTPATH environment variable or by
|
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
|
||||||
# setting DOT_FONTPATH to the directory containing the font.
|
# Edge and Graph Attributes specification</a> You need to make sure dot is able
|
||||||
# The default value is: Helvetica.
|
# to find the font, which can be done by putting it in a standard location or by
|
||||||
|
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
|
||||||
|
# directory containing the font. Default graphviz fontsize is 14.
|
||||||
|
# The default value is: fontname=Helvetica,fontsize=10.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
#DOT_FONTNAME = Helvetica
|
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
|
||||||
|
|
||||||
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
|
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
|
||||||
# dot graphs.
|
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
|
||||||
# Minimum value: 4, maximum value: 24, default value: 10.
|
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
|
||||||
|
# arrows shapes.</a>
|
||||||
|
# The default value is: labelfontname=Helvetica,labelfontsize=10.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
#DOT_FONTSIZE = 10
|
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
|
||||||
|
|
||||||
# By default doxygen will tell dot to use the default font as specified with
|
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
|
||||||
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
|
# around nodes set 'shape=plain' or 'shape=plaintext' <a
|
||||||
# the path where dot can find it using this tag.
|
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
|
||||||
|
# The default value is: shape=box,height=0.2,width=0.4.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
#DOT_FONTPATH =
|
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
|
||||||
|
|
||||||
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
|
# You can set the path where dot can find font specified with fontname in
|
||||||
# graph for each documented class showing the direct and indirect inheritance
|
# DOT_COMMON_ATTR and others dot attributes.
|
||||||
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
|
|
||||||
# to TEXT the direct and indirect inheritance relations will be shown as texts /
|
DOT_FONTPATH =
|
||||||
# links.
|
|
||||||
# Possible values are: NO, YES, TEXT and GRAPH.
|
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
|
||||||
|
# generate a graph for each documented class showing the direct and indirect
|
||||||
|
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
|
||||||
|
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
|
||||||
|
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
|
||||||
|
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
|
||||||
|
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
|
||||||
|
# relations will be shown as texts / links.
|
||||||
|
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
CLASS_GRAPH = YES
|
CLASS_GRAPH = YES
|
||||||
@@ -2430,15 +2530,21 @@ CLASS_GRAPH = YES
|
|||||||
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
|
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
|
||||||
# graph for each documented class showing the direct and indirect implementation
|
# graph for each documented class showing the direct and indirect implementation
|
||||||
# dependencies (inheritance, containment, and class references variables) of the
|
# dependencies (inheritance, containment, and class references variables) of the
|
||||||
# class with other documented classes.
|
# class with other documented classes. Explicit enabling a collaboration graph,
|
||||||
|
# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
|
||||||
|
# command \collaborationgraph. Disabling a collaboration graph can be
|
||||||
|
# accomplished by means of the command \hidecollaborationgraph.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
COLLABORATION_GRAPH = YES
|
COLLABORATION_GRAPH = YES
|
||||||
|
|
||||||
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
|
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
|
||||||
# groups, showing the direct groups dependencies. See also the chapter Grouping
|
# groups, showing the direct groups dependencies. Explicit enabling a group
|
||||||
# in the manual.
|
# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
|
||||||
|
# of the command \groupgraph. Disabling a directory graph can be accomplished by
|
||||||
|
# means of the command \hidegroupgraph. See also the chapter Grouping in the
|
||||||
|
# manual.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2498,7 +2604,9 @@ TEMPLATE_RELATIONS = NO
|
|||||||
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
|
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
|
||||||
# YES then doxygen will generate a graph for each documented file showing the
|
# YES then doxygen will generate a graph for each documented file showing the
|
||||||
# direct and indirect include dependencies of the file with other documented
|
# direct and indirect include dependencies of the file with other documented
|
||||||
# files.
|
# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
|
||||||
|
# can be accomplished by means of the command \includegraph. Disabling an
|
||||||
|
# include graph can be accomplished by means of the command \hideincludegraph.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2507,7 +2615,10 @@ INCLUDE_GRAPH = YES
|
|||||||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
||||||
# set to YES then doxygen will generate a graph for each documented file showing
|
# set to YES then doxygen will generate a graph for each documented file showing
|
||||||
# the direct and indirect include dependencies of the file with other documented
|
# the direct and indirect include dependencies of the file with other documented
|
||||||
# files.
|
# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
|
||||||
|
# to NO, can be accomplished by means of the command \includedbygraph. Disabling
|
||||||
|
# an included by graph can be accomplished by means of the command
|
||||||
|
# \hideincludedbygraph.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2547,7 +2658,10 @@ GRAPHICAL_HIERARCHY = YES
|
|||||||
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
|
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
|
||||||
# dependencies a directory has on other directories in a graphical way. The
|
# dependencies a directory has on other directories in a graphical way. The
|
||||||
# dependency relations are determined by the #include relations between the
|
# dependency relations are determined by the #include relations between the
|
||||||
# files in the directories.
|
# files in the directories. Explicit enabling a directory graph, when
|
||||||
|
# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
|
||||||
|
# \directorygraph. Disabling a directory graph can be accomplished by means of
|
||||||
|
# the command \hidedirectorygraph.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2563,12 +2677,13 @@ DIR_GRAPH_MAX_DEPTH = 1
|
|||||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||||
# generated by dot. For an explanation of the image formats see the section
|
# generated by dot. For an explanation of the image formats see the section
|
||||||
# output formats in the documentation of the dot tool (Graphviz (see:
|
# output formats in the documentation of the dot tool (Graphviz (see:
|
||||||
# http://www.graphviz.org/)).
|
# https://www.graphviz.org/)).
|
||||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||||
# requirement).
|
# requirement).
|
||||||
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
|
# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,
|
||||||
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,
|
||||||
|
# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
||||||
# png:gdiplus:gdiplus.
|
# png:gdiplus:gdiplus.
|
||||||
# The default value is: png.
|
# The default value is: png.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
@@ -2600,11 +2715,12 @@ DOT_PATH =
|
|||||||
|
|
||||||
DOTFILE_DIRS =
|
DOTFILE_DIRS =
|
||||||
|
|
||||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||||
# contain msc files that are included in the documentation (see the \mscfile
|
# then run dia to produce the diagram and insert it in the documentation. The
|
||||||
# command).
|
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||||
|
# If left empty dia is assumed to be found in the default search path.
|
||||||
|
|
||||||
MSCFILE_DIRS =
|
DIA_PATH =
|
||||||
|
|
||||||
# The DIAFILE_DIRS tag can be used to specify one or more directories that
|
# The DIAFILE_DIRS tag can be used to specify one or more directories that
|
||||||
# contain dia files that are included in the documentation (see the \diafile
|
# contain dia files that are included in the documentation (see the \diafile
|
||||||
@@ -2654,18 +2770,6 @@ DOT_GRAPH_MAX_NODES = 50
|
|||||||
|
|
||||||
MAX_DOT_GRAPH_DEPTH = 0
|
MAX_DOT_GRAPH_DEPTH = 0
|
||||||
|
|
||||||
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
|
||||||
# background. This is disabled by default, because dot on Windows does not seem
|
|
||||||
# to support this out of the box.
|
|
||||||
#
|
|
||||||
# Warning: Depending on the platform used, enabling this option may lead to
|
|
||||||
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
|
|
||||||
# read).
|
|
||||||
# The default value is: NO.
|
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
|
||||||
|
|
||||||
#DOT_TRANSPARENT = NO
|
|
||||||
|
|
||||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
||||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
# files in one run (i.e. multiple -o and -T options on the command line). This
|
||||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
||||||
@@ -2693,3 +2797,19 @@ GENERATE_LEGEND = YES
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
DOT_CLEANUP = YES
|
DOT_CLEANUP = YES
|
||||||
|
|
||||||
|
# You can define message sequence charts within doxygen comments using the \msc
|
||||||
|
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
|
||||||
|
# use a built-in version of mscgen tool to produce the charts. Alternatively,
|
||||||
|
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
|
||||||
|
# specifying prog as the value, doxygen will call the tool as prog -T
|
||||||
|
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
|
||||||
|
# output file formats "png", "eps", "svg", and "ismap".
|
||||||
|
|
||||||
|
MSCGEN_TOOL =
|
||||||
|
|
||||||
|
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
||||||
|
# contain msc files that are included in the documentation (see the \mscfile
|
||||||
|
# command).
|
||||||
|
|
||||||
|
MSCFILE_DIRS =
|
||||||
|
|||||||
240
GNUmakefile
@@ -16,15 +16,15 @@ MAKEFLAGS += --no-builtin-rules
|
|||||||
## LD := Linker.
|
## LD := Linker.
|
||||||
## ANDROID_SDK := Path to the Android SDK.
|
## ANDROID_SDK := Path to the Android SDK.
|
||||||
|
|
||||||
VERSION_CODE := 48
|
VERSION_CODE := 33
|
||||||
VERSION_CODE_IOS := 26
|
VERSION_CODE_IOS := 8
|
||||||
VERSION_NUMBER := 0.2025.11
|
VERSION_NUMBER := 0.0.28-wip
|
||||||
VERSION_NAME := This program kills fascists.
|
VERSION_NAME := This program kills fascists.
|
||||||
|
|
||||||
IPHONEOS_VERSION_MIN=14.5
|
IPHONEOS_VERSION_MIN=14.0
|
||||||
|
|
||||||
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3510000.zip
|
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip
|
||||||
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.18.2/bundletool-all-1.18.2.jar
|
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
|
||||||
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||||
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
|
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
|
||||||
|
|
||||||
@@ -38,16 +38,13 @@ BUNDLETOOL = out/bundletool.jar
|
|||||||
|
|
||||||
HAVE_WIN :=
|
HAVE_WIN :=
|
||||||
HAVE_CROSS_AARCH64 :=
|
HAVE_CROSS_AARCH64 :=
|
||||||
|
USE_SYSTEM_SSL :=
|
||||||
|
|
||||||
export SOURCE_DATE_EPOCH=1
|
export SOURCE_DATE_EPOCH=1
|
||||||
export TZ=UTC
|
export TZ=UTC
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
BUILD_TYPES := debug release iosdebug iosrelease iossimdebug iossimrelease
|
BUILD_TYPES := debug release iosdebug iosrelease iossimdebug iossimrelease
|
||||||
HAVE_ANDROID = 0
|
|
||||||
HAVE_LINUX_IOS = 0
|
|
||||||
HAVE_LINUX_MACOS = 0
|
|
||||||
HAVE_WIN = 0
|
|
||||||
else ifeq ($(UNAME_S),Linux)
|
else ifeq ($(UNAME_S),Linux)
|
||||||
BUILD_TYPES := debug release
|
BUILD_TYPES := debug release
|
||||||
HAVE_ANDROID = $(if $(shell which $(ANDROID_SDK)/platform-tools/adb),1)
|
HAVE_ANDROID = $(if $(shell which $(ANDROID_SDK)/platform-tools/adb),1)
|
||||||
@@ -64,10 +61,7 @@ LDFLAGS += \
|
|||||||
-lbsd \
|
-lbsd \
|
||||||
-lnetwork \
|
-lnetwork \
|
||||||
-Wno-stringop-overflow
|
-Wno-stringop-overflow
|
||||||
HAVE_ANDROID = 0
|
USE_SYSTEM_SSL := 1
|
||||||
HAVE_LINUX_IOS = 0
|
|
||||||
HAVE_LINUX_MACOS = 0
|
|
||||||
HAVE_WIN = 0
|
|
||||||
else ifeq ($(UNAME_S),OpenBSD)
|
else ifeq ($(UNAME_S),OpenBSD)
|
||||||
BUILD_TYPES := debug release
|
BUILD_TYPES := debug release
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
@@ -78,12 +72,13 @@ LDFLAGS += \
|
|||||||
HAVE_ANDROID :=
|
HAVE_ANDROID :=
|
||||||
HAVE_LINUX_IOS :=
|
HAVE_LINUX_IOS :=
|
||||||
HAVE_LINUX_MACOS :=
|
HAVE_LINUX_MACOS :=
|
||||||
|
USE_SYSTEM_SSL := 1
|
||||||
else
|
else
|
||||||
$(error Unexpected host platform $(UNAME_S).)
|
$(error Unexpected host platform $(UNAME_S).)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Everything is set above.
|
# Everything is set above.
|
||||||
$(info Building Tilde Friends $(VERSION_NUMBER) android=$(if $(HAVE_ANDROID),1,0) win=$(if $(HAVE_WIN),1,0) cross_aarch64=$(if $(HAVE_CROSS_AARCH64),1,0) cross_ios=$(if $(HAVE_LINUX_IOS),1,0) cross_macos=$(if $(HAVE_LINUX_MACOS),1,0))
|
$(info Building Tilde Friends $(VERSION_NUMBER) android=$(if $(HAVE_ANDROID),1,0) win=$(if $(HAVE_WIN),1,0) cross_aarch64=$(if $(HAVE_CROSS_AARCH64),1,0) cross_ios=$(if $(HAVE_LINUX_IOS),1,0) cross_macos=$(if $(HAVE_LINUX_MACOS),1,0) system_ssl=$(if $(USE_SYSTEM_SSL),1,0))
|
||||||
|
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-std=gnu11 \
|
-std=gnu11 \
|
||||||
@@ -103,10 +98,10 @@ LDFLAGS += \
|
|||||||
-Wno-aggressive-loop-optimizations
|
-Wno-aggressive-loop-optimizations
|
||||||
|
|
||||||
ANDROID_MIN_SDK_VERSION := 24
|
ANDROID_MIN_SDK_VERSION := 24
|
||||||
ANDROID_TARGET_SDK_VERSION := 35
|
ANDROID_TARGET_SDK_VERSION := 34
|
||||||
ANDROID_BUILD_TOOLS := $(ANDROID_SDK)/build-tools/35.0.0
|
ANDROID_BUILD_TOOLS := $(ANDROID_SDK)/build-tools/34.0.0
|
||||||
ANDROID_PLATFORM := $(ANDROID_SDK)/platforms/android-$(ANDROID_TARGET_SDK_VERSION)
|
ANDROID_PLATFORM := $(ANDROID_SDK)/platforms/android-$(ANDROID_TARGET_SDK_VERSION)
|
||||||
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/27.2.12479018
|
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/26.3.11579264
|
||||||
|
|
||||||
ANDROID_ARMV7A_TARGETS := \
|
ANDROID_ARMV7A_TARGETS := \
|
||||||
out/androiddebug-armv7a/tildefriends \
|
out/androiddebug-armv7a/tildefriends \
|
||||||
@@ -250,10 +245,7 @@ $(ANDROID_TARGETS): CFLAGS += \
|
|||||||
-fno-asynchronous-unwind-tables \
|
-fno-asynchronous-unwind-tables \
|
||||||
-funwind-tables \
|
-funwind-tables \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
$(ANDROID_TARGETS): LDFLAGS += \
|
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
|
||||||
--sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
|
|
||||||
-Wl,-z,max-page-size=16384 \
|
|
||||||
-fPIC
|
|
||||||
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
||||||
$(DEBUG_TARGETS): LDFLAGS += -Og
|
$(DEBUG_TARGETS): LDFLAGS += -Og
|
||||||
$(RELEASE_TARGETS): CFLAGS += \
|
$(RELEASE_TARGETS): CFLAGS += \
|
||||||
@@ -267,12 +259,16 @@ $(WINDOWS_TARGETS): AS = $(CC)
|
|||||||
$(WINDOWS_TARGETS): CFLAGS += \
|
$(WINDOWS_TARGETS): CFLAGS += \
|
||||||
-D_WIN32_WINNT=0x0A00 \
|
-D_WIN32_WINNT=0x0A00 \
|
||||||
-DWINVER=0x0A00 \
|
-DWINVER=0x0A00 \
|
||||||
-DNTDDI_VERSION=NTDDI_WIN10
|
-DNTDDI_VERSION=NTDDI_WIN10 \
|
||||||
|
-Iout/openssl/$(UNAME_S)/mingw64/usr/local/include
|
||||||
$(WINDOWS_TARGETS): LDFLAGS += \
|
$(WINDOWS_TARGETS): LDFLAGS += \
|
||||||
-static \
|
-static \
|
||||||
-lm
|
-lm \
|
||||||
|
-Lout/openssl/$(UNAME_S)/mingw64/usr/local/lib
|
||||||
$(AARCH64_TARGETS): CC = aarch64-linux-gnu-gcc
|
$(AARCH64_TARGETS): CC = aarch64-linux-gnu-gcc
|
||||||
$(AARCH64_TARGETS): AS = $(CC)
|
$(AARCH64_TARGETS): AS = $(CC)
|
||||||
|
$(AARCH64_TARGETS): CFLAGS += -Iout/openssl/Linux/aarch64/usr/local/include
|
||||||
|
$(AARCH64_TARGETS): LDFLAGS += -Lout/openssl/Linux/aarch64/usr/local/lib
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
$(HOST_TARGETS): CC = xcrun clang
|
$(HOST_TARGETS): CC = xcrun clang
|
||||||
$(IOS_TARGETS): IOS_SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path)
|
$(IOS_TARGETS): IOS_SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path)
|
||||||
@@ -297,12 +293,39 @@ $(ANDROID_TARGETS): AS = $(CC)
|
|||||||
$(ANDROID_TARGETS): CFLAGS += \
|
$(ANDROID_TARGETS): CFLAGS += \
|
||||||
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
|
$(ANDROID_ARMV7A_TARGETS): CFLAGS += -Iout/openssl/android/armeabi-v7a/usr/local/include
|
||||||
|
$(ANDROID_ARMV7A_TARGETS): LDFLAGS += -Lout/openssl/android/armeabi-v7a/usr/local/lib
|
||||||
|
$(ANDROID_ARM64_TARGETS): CFLAGS += -Iout/openssl/android/arm64-v8a/usr/local/include
|
||||||
|
$(ANDROID_ARM64_TARGETS): LDFLAGS += -Lout/openssl/android/arm64-v8a/usr/local/lib
|
||||||
|
$(ANDROID_X86_TARGETS): CFLAGS += -Iout/openssl/android/x86/usr/local/include
|
||||||
$(ANDROID_X86_TARGETS): CFLAGS += -Wno-atomic-alignment
|
$(ANDROID_X86_TARGETS): CFLAGS += -Wno-atomic-alignment
|
||||||
|
$(ANDROID_X86_TARGETS): LDFLAGS += -Lout/openssl/android/x86/usr/local/lib
|
||||||
|
$(ANDROID_X86_64_TARGETS): CFLAGS += -Iout/openssl/android/x86_64/usr/local/include
|
||||||
|
$(ANDROID_X86_64_TARGETS): LDFLAGS += -Lout/openssl/android/x86_64/usr/local/lib
|
||||||
$(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type
|
$(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type
|
||||||
$(MACOS_TARGETS): LDFLAGS += -Wl,-dead_strip
|
$(MACOS_TARGETS): LDFLAGS += -Wl,-dead_strip
|
||||||
$(NONMACOS_TARGETS): LDFLAGS += -Wl,--gc-sections -Wl,--as-needed
|
$(NONMACOS_TARGETS): LDFLAGS += -Wl,--gc-sections -Wl,--as-needed
|
||||||
$(IOS_TARGETS): CFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
$(IOS_TARGETS): CFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
||||||
$(IOS_TARGETS): LDFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
$(IOS_TARGETS): LDFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
$(IOS_TARGETS): CFLAGS += -Iout/openssl/ios/ios64-xcrun/usr/local/include
|
||||||
|
$(IOS_TARGETS): LDFLAGS += -Lout/openssl/ios/ios64-xcrun/usr/local/lib
|
||||||
|
else
|
||||||
|
$(IOS_TARGETS): CFLAGS += -Iout/openssl/$(UNAME_S)/ios64-cross/usr/local/include
|
||||||
|
$(IOS_TARGETS): LDFLAGS += -Lout/openssl/$(UNAME_S)/ios64-cross/usr/local/lib
|
||||||
|
$(filter $(BUILD_DIR)/macosdebug-x86_64/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-x86_64/usr/local/include
|
||||||
|
$(filter $(BUILD_DIR)/macosdebug-arm/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-arm/usr/local/include
|
||||||
|
$(filter $(BUILD_DIR)/macosdebug-x86_64/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-x86_64/usr/local/lib
|
||||||
|
$(filter $(BUILD_DIR)/macosdebug-arm/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-arm/usr/local/lib
|
||||||
|
$(filter $(BUILD_DIR)/macosrelease-x86_64/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-x86_64/usr/local/include
|
||||||
|
$(filter $(BUILD_DIR)/macosrelease-arm/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-arm/usr/local/include
|
||||||
|
$(filter $(BUILD_DIR)/macosrelease-x86_64/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-x86_64/usr/local/lib
|
||||||
|
$(filter $(BUILD_DIR)/macosrelease-arm/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-arm/usr/local/lib
|
||||||
|
endif
|
||||||
|
$(IOSSIM_TARGETS): CFLAGS += -Iout/openssl/ios/iossimulator-xcrun/usr/local/include
|
||||||
|
$(IOSSIM_TARGETS): LDFLAGS += -Lout/openssl/ios/iossimulator-xcrun/usr/local/lib
|
||||||
|
$(HOST_TARGETS): CFLAGS += -Iout/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/include
|
||||||
|
$(HOST_TARGETS): LDFLAGS += -Lout/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib
|
||||||
|
|
||||||
ifeq ($(UNAME_M),x86_64)
|
ifeq ($(UNAME_M),x86_64)
|
||||||
ifeq ($(UNAME_S),Linux)
|
ifeq ($(UNAME_S),Linux)
|
||||||
@@ -583,16 +606,15 @@ $(UV_OBJS): CFLAGS += \
|
|||||||
-Ideps/libuv/include \
|
-Ideps/libuv/include \
|
||||||
-Ideps/libuv/src \
|
-Ideps/libuv/src \
|
||||||
-Wno-dangling-pointer \
|
-Wno-dangling-pointer \
|
||||||
-Wno-format-truncation \
|
|
||||||
-Wno-incompatible-pointer-types \
|
-Wno-incompatible-pointer-types \
|
||||||
-Wno-maybe-uninitialized \
|
-Wno-maybe-uninitialized \
|
||||||
-Wno-nonnull \
|
|
||||||
-Wno-sign-compare \
|
-Wno-sign-compare \
|
||||||
-Wno-unknown-attributes \
|
-Wno-unknown-attributes \
|
||||||
-Wno-unused-but-set-parameter \
|
-Wno-unused-but-set-parameter \
|
||||||
-Wno-unused-but-set-variable \
|
-Wno-unused-but-set-variable \
|
||||||
-Wno-unused-result \
|
-Wno-unused-result \
|
||||||
-Wno-unused-variable
|
-Wno-unused-variable \
|
||||||
|
-Wno-nonnull
|
||||||
$(filter out/win%,$(UV_OBJS)): \
|
$(filter out/win%,$(UV_OBJS)): \
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-Wno-cast-function-type \
|
-Wno-cast-function-type \
|
||||||
@@ -619,7 +641,6 @@ SODIUM_SOURCES := \
|
|||||||
deps/libsodium/src/libsodium/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c \
|
deps/libsodium/src/libsodium/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c \
|
||||||
deps/libsodium/src/libsodium/crypto_core/salsa/ref/core_salsa_ref.c \
|
deps/libsodium/src/libsodium/crypto_core/salsa/ref/core_salsa_ref.c \
|
||||||
deps/libsodium/src/libsodium/crypto_core/softaes/softaes.c \
|
deps/libsodium/src/libsodium/crypto_core/softaes/softaes.c \
|
||||||
deps/libsodium/src/libsodium/crypto_generichash/crypto_generichash.c \
|
|
||||||
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c \
|
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c \
|
||||||
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c \
|
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c \
|
||||||
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/generichash_blake2b.c \
|
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/generichash_blake2b.c \
|
||||||
@@ -689,12 +710,12 @@ $(SQLITE_OBJS): CFLAGS += \
|
|||||||
-DSQLITE_MAX_COMPOUND_SELECT=300 \
|
-DSQLITE_MAX_COMPOUND_SELECT=300 \
|
||||||
-DSQLITE_MAX_EXPR_DEPTH=40 \
|
-DSQLITE_MAX_EXPR_DEPTH=40 \
|
||||||
-DSQLITE_MAX_FUNCTION_ARG=8 \
|
-DSQLITE_MAX_FUNCTION_ARG=8 \
|
||||||
-DSQLITE_MAX_LENGTH=10485760 \
|
-DSQLITE_MAX_LENGTH=5242880 \
|
||||||
-DSQLITE_MAX_LIKE_PATTERN_LENGTH=50 \
|
-DSQLITE_MAX_LIKE_PATTERN_LENGTH=50 \
|
||||||
-DSQLITE_MAX_SQL_LENGTH=100000 \
|
-DSQLITE_MAX_SQL_LENGTH=100000 \
|
||||||
-DSQLITE_MAX_TRIGGER_DEPTH=10 \
|
-DSQLITE_MAX_TRIGGER_DEPTH=10 \
|
||||||
-DSQLITE_MAX_VARIABLE_NUMBER=100 \
|
-DSQLITE_MAX_VARIABLE_NUMBER=100 \
|
||||||
-DSQLITE_MAX_VDBE_OP=50000 \
|
-DSQLITE_MAX_VDBE_OP=25000 \
|
||||||
-DSQLITE_OMIT_DEPRECATED \
|
-DSQLITE_OMIT_DEPRECATED \
|
||||||
-DSQLITE_OMIT_DESERIALIZE \
|
-DSQLITE_OMIT_DESERIALIZE \
|
||||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||||
@@ -713,7 +734,7 @@ $(SQLITE_OBJS): CFLAGS += \
|
|||||||
|
|
||||||
QUICKJS_SOURCES := \
|
QUICKJS_SOURCES := \
|
||||||
deps/quickjs/cutils.c \
|
deps/quickjs/cutils.c \
|
||||||
deps/quickjs/dtoa.c \
|
deps/quickjs/libbf.c \
|
||||||
deps/quickjs/libregexp.c \
|
deps/quickjs/libregexp.c \
|
||||||
deps/quickjs/libunicode.c \
|
deps/quickjs/libunicode.c \
|
||||||
deps/quickjs/quickjs.c
|
deps/quickjs/quickjs.c
|
||||||
@@ -790,6 +811,9 @@ $(MINIUNZIP_OBJS): CFLAGS += \
|
|||||||
LDFLAGS += \
|
LDFLAGS += \
|
||||||
-pthread \
|
-pthread \
|
||||||
-lm
|
-lm
|
||||||
|
$(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS) $(AARCH64_TARGETS) $(filter-out $(HOST_TARGETS),$(MACOS_TARGETS)): LDFLAGS += \
|
||||||
|
-lssl \
|
||||||
|
-lcrypto
|
||||||
ifneq ($(UNAME_S),Haiku)
|
ifneq ($(UNAME_S),Haiku)
|
||||||
ifneq ($(UNAME_S),OpenBSD)
|
ifneq ($(UNAME_S),OpenBSD)
|
||||||
$(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
$(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
||||||
@@ -797,6 +821,8 @@ $(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
$(WINDOWS_TARGETS): LDFLAGS += \
|
$(WINDOWS_TARGETS): LDFLAGS += \
|
||||||
|
-lssl \
|
||||||
|
-lcrypto \
|
||||||
-lcrypt32 \
|
-lcrypt32 \
|
||||||
-ldbghelp \
|
-ldbghelp \
|
||||||
-liphlpapi \
|
-liphlpapi \
|
||||||
@@ -809,15 +835,15 @@ $(WINDOWS_TARGETS): LDFLAGS += \
|
|||||||
$(ANDROID_TARGETS): LDFLAGS += \
|
$(ANDROID_TARGETS): LDFLAGS += \
|
||||||
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
||||||
-ldl \
|
-ldl \
|
||||||
-llog
|
-llog \
|
||||||
|
-lssl \
|
||||||
|
-lcrypto
|
||||||
$(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): CFLAGS += \
|
$(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): CFLAGS += \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
$(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
$(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
||||||
-framework Foundation \
|
-framework Foundation \
|
||||||
-framework CoreFoundation \
|
-framework CoreFoundation \
|
||||||
-framework CoreSpotlight \
|
|
||||||
-framework UIKit \
|
-framework UIKit \
|
||||||
-framework UniformTypeIdentifiers \
|
|
||||||
-framework WebKit
|
-framework WebKit
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -980,7 +1006,7 @@ $(BUNDLETOOL):
|
|||||||
@curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL)
|
@curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL)
|
||||||
|
|
||||||
out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL)
|
out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL)
|
||||||
@rm -rf out/aab/staging/ out/aab/base.zip
|
@rm -rf out/aab/staging/
|
||||||
@mkdir -p out/aab/staging
|
@mkdir -p out/aab/staging
|
||||||
@$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk \
|
@$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk \
|
||||||
-I $(ANDROID_PLATFORM)/android.jar \
|
-I $(ANDROID_PLATFORM)/android.jar \
|
||||||
@@ -1000,11 +1026,14 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
|
|||||||
@cp out/apk/classes.dex out/aab/staging/dex/
|
@cp out/apk/classes.dex out/aab/staging/dex/
|
||||||
@rm -fv out/base.zip
|
@rm -fv out/base.zip
|
||||||
@mkdir -p out/aab/staging/lib/arm64-v8a out/aab/staging/lib/armeabi-v7a out/aab/staging/lib/x86_64 out/aab/staging/lib/x86
|
@mkdir -p out/aab/staging/lib/arm64-v8a out/aab/staging/lib/armeabi-v7a out/aab/staging/lib/x86_64 out/aab/staging/lib/x86
|
||||||
@mkdir -p out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64 out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86
|
@cp out/androidrelease/tildefriends out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease/tildefriends -o out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
@cp out/androidrelease-armv7a/tildefriends out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-armv7a/tildefriends -o out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
@cp out/androidrelease-x86_64/tildefriends out/aab/staging/lib/x86_64/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-x86_64/tildefriends -o out/aab/staging/lib/x86_64/libtildefriends.so
|
@cp out/androidrelease-x86/tildefriends out/aab/staging/lib/x86/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-x86/tildefriends -o out/aab/staging/lib/x86/libtildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86_64/libtildefriends.so
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86/libtildefriends.so
|
||||||
@cp -r apps/ out/aab/staging/root/
|
@cp -r apps/ out/aab/staging/root/
|
||||||
@rm -rf out/aab/staging/root/apps/welcome*
|
@rm -rf out/aab/staging/root/apps/welcome*
|
||||||
@cp -r core/ out/aab/staging/root/
|
@cp -r core/ out/aab/staging/root/
|
||||||
@@ -1013,12 +1042,7 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
|
|||||||
@cp -r deps/codemirror/ out/aab/staging/root/deps/
|
@cp -r deps/codemirror/ out/aab/staging/root/deps/
|
||||||
@cd out/aab/staging/; zip -r ../base.zip *; cd ../../../
|
@cd out/aab/staging/; zip -r ../base.zip *; cd ../../../
|
||||||
@java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@
|
@java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libtildefriends.so.sym
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign -ks .keys/android.jks --ks-key-alias androidKey -ks-pass pass:android --min-sdk-version=$(ANDROID_MIN_SDK_VERSION) $@
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-armv7a/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a/libtildefriends.so.sym
|
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86_64/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym
|
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym
|
|
||||||
@cd out/aab/staging; zip -u ../../../$@ BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym; cd ../../../
|
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign -ks .keys/android.jks --ks-key-alias androidKey -ks-pass pass:android --min-sdk-version=$(ANDROID_MIN_SDK_VERSION) --alignment-preserved $@
|
|
||||||
|
|
||||||
aab: out/TildeFriends.aab ## Build an Android App Bundle.
|
aab: out/TildeFriends.aab ## Build an Android App Bundle.
|
||||||
.PHONY: aab
|
.PHONY: aab
|
||||||
@@ -1080,12 +1104,12 @@ out/apk/TildeFriends-%.fdroid.unsigned.apk:
|
|||||||
|
|
||||||
out/%.apk: out/apk/%.unsigned.apk
|
out/%.apk: out/apk/%.unsigned.apk
|
||||||
@echo "[apksigner] $(notdir $@)"
|
@echo "[apksigner] $(notdir $@)"
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ --alignment-preserved $<
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ $<
|
||||||
|
|
||||||
out/%.zopfli.apk: out/%.apk
|
out/%.zopfli.apk: out/%.apk
|
||||||
@echo "[zopfli] $(notdir $@)"
|
@echo "[zopfli] $(notdir $@)"
|
||||||
$(ANDROID_BUILD_TOOLS)/zipalign -f -z 4 $< $@.zopfli
|
$(ANDROID_BUILD_TOOLS)/zipalign -f -z 4 $< $@.zopfli
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ --alignment-preserved $@.zopfli
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ $@.zopfli
|
||||||
|
|
||||||
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk ## Build an Android release APK.
|
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk ## Build an Android release APK.
|
||||||
.PHONY: release-apk
|
.PHONY: release-apk
|
||||||
@@ -1103,11 +1127,6 @@ releaseapkgo: out/TildeFriends-arm-release.apk ## Build, install, and run a rele
|
|||||||
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
.PHONY: releaseapkgo
|
.PHONY: releaseapkgo
|
||||||
|
|
||||||
x86releaseapkgo: out/TildeFriends-x86-release.apk ## Build, install, and run an x86 release Android APK.
|
|
||||||
@adb install -r $<
|
|
||||||
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
|
||||||
.PHONY: x86releaseapkgo
|
|
||||||
|
|
||||||
apklog: ## Display Android log output.
|
apklog: ## Display Android log output.
|
||||||
@adb logcat *:S tildefriends
|
@adb logcat *:S tildefriends
|
||||||
.PHONY: apklog
|
.PHONY: apklog
|
||||||
@@ -1134,13 +1153,7 @@ out/zsign_build/zsign: $(wildcard deps/zsign/*.cpp deps/zsign/*.h deps/zsign/*.t
|
|||||||
@cmake -B out/zsign_build deps/zsign
|
@cmake -B out/zsign_build deps/zsign
|
||||||
@cmake --build out/zsign_build -- COLOR=0 VERBOSE=0 MAKESILENT=-s
|
@cmake --build out/zsign_build -- COLOR=0 VERBOSE=0 MAKESILENT=-s
|
||||||
|
|
||||||
ifeq ($(HAVE_LINUX_IOS),1)
|
out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/data.zip $(if $(HAVE_LINUX_IOS),out/zsign_build/zsign)
|
||||||
ZSIGN_DEP = out/zsign_build/zsign
|
|
||||||
else
|
|
||||||
ZSIGN_DEP =
|
|
||||||
endif
|
|
||||||
|
|
||||||
out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/data.zip $(ZSIGN_DEP)
|
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
@cp -v $(filter-out out/zsign%,$<) $@
|
@cp -v $(filter-out out/zsign%,$<) $@
|
||||||
@cp -v out/data.zip $(@D)/
|
@cp -v out/data.zip $(@D)/
|
||||||
@@ -1153,7 +1166,6 @@ out/tildefriends-%.ipa: out/tildefriends-ios%.app/tildefriends
|
|||||||
@echo "[ipa] $@"
|
@echo "[ipa] $@"
|
||||||
@rm -rf $@.tmp $@
|
@rm -rf $@.tmp $@
|
||||||
@mkdir -p $@.tmp/Payload/tildefriends.app/
|
@mkdir -p $@.tmp/Payload/tildefriends.app/
|
||||||
@cp src/ios/tildefriends512.png $@.tmp/iTunesArtwork
|
|
||||||
@cp -R $(dir $<)/* $@.tmp/Payload/tildefriends.app/
|
@cp -R $(dir $<)/* $@.tmp/Payload/tildefriends.app/
|
||||||
@cd $@.tmp/ && zip -u ../../$@ -q -9 -r ./
|
@cd $@.tmp/ && zip -u ../../$@ -q -9 -r ./
|
||||||
@rm -rf $@.tmp/
|
@rm -rf $@.tmp/
|
||||||
@@ -1181,11 +1193,98 @@ ios%go: out/tildefriends-ios%.app/tildefriends
|
|||||||
ideviceinstaller -i $(realpath $(dir $<))
|
ideviceinstaller -i $(realpath $(dir $<))
|
||||||
|
|
||||||
iossimdebuggo: out/tildefriends-iossimdebug.app/tildefriends ## Build, install, and run an iOS debug build.
|
iossimdebuggo: out/tildefriends-iossimdebug.app/tildefriends ## Build, install, and run an iOS debug build.
|
||||||
xcrun -sdk iphoneos codesign -f -s 'Apple Distribution' --entitlements src/ios/Entitlements.plist --generate-entitlement-der out/tildefriends-iossimdebug.app
|
|
||||||
xcrun simctl install booted out/tildefriends-iossimdebug.app/
|
xcrun simctl install booted out/tildefriends-iossimdebug.app/
|
||||||
xcrun simctl launch --console booted com.unprompted.tildefriends
|
xcrun simctl launch booted com.unprompted.tildefriends
|
||||||
.PHONY: iossimdebuggo
|
.PHONY: iossimdebuggo
|
||||||
|
|
||||||
|
ANDROID_DEPS := out/openssl/android/arm64-v8a/usr/local/lib/libssl.a
|
||||||
|
$(ANDROID_DEPS):
|
||||||
|
+@export ANDROID_NDK_ROOT=$(ANDROID_NDK)
|
||||||
|
+@export BUILD_PLATFORM=android
|
||||||
|
+@export TOOLCHAIN=$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64
|
||||||
|
+@PATH="$$TOOLCHAIN/x86_64-linux-android/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=x86_64 SSL_TARGET=android-x86_64 OPTIONS="-D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
||||||
|
+@PATH="$$TOOLCHAIN/i686-linux-android/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=x86 SSL_TARGET=android-x86 OPTIONS="-D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
||||||
|
+@PATH="$$TOOLCHAIN/arm-linux-androideabi/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=armeabi-v7a SSL_TARGET=android-arm OPTIONS="--target=armv7a-linux-androideabi -Wl,--fix-cortex-a8 -D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
||||||
|
+@PATH="$$TOOLCHAIN/aarch64-linux-android/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=arm64-v8a SSL_TARGET=android-arm64 OPTIONS="-D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/android%,$(APP_OBJS)): | $(ANDROID_DEPS)
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S),Linux)
|
||||||
|
ifneq ($(USE_SYSTEM_SSL),1)
|
||||||
|
LOCAL_DEPS := out/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib/libssl.a
|
||||||
|
$(LOCAL_DEPS):
|
||||||
|
+@tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/debug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/release/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_CROSS_AARCH64),1)
|
||||||
|
LOCAL_DEPS := out/openssl/$(UNAME_S)/aarch64/usr/local/lib/libssl.a
|
||||||
|
$(LOCAL_DEPS):
|
||||||
|
+@OPTIONS="--cross-compile-prefix=aarch64-linux-gnu-" BUILD_TARGET=aarch64 SSL_TARGET=linux-aarch64 tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/armdebug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/armrelease/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_LINUX_IOS),1)
|
||||||
|
LOCAL_DEPS := out/openssl/$(UNAME_S)/ios64-cross/usr/local/lib/libssl.a
|
||||||
|
$(LOCAL_DEPS):
|
||||||
|
+@PATH=deps/ios_toolchain/target/bin:$$PATH \
|
||||||
|
BUILD_TARGET=ios64-cross \
|
||||||
|
SSL_TARGET=ios64-cross \
|
||||||
|
CROSS_COMPILE=../../deps/ios_toolchain/target/bin/arm-apple-darwin11- \
|
||||||
|
CROSS_TOP=../../deps/ios_toolchain/target \
|
||||||
|
CROSS_SDK=iPhoneOS18.2.sdk \
|
||||||
|
CC=clang \
|
||||||
|
OPTIONS=-miphoneos-version-min=$(IPHONEOS_VERSION_MIN) \
|
||||||
|
tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/ios%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_LINUX_MACOS),1)
|
||||||
|
LOCAL_DEPS := out/openssl/$(UNAME_S)/macos-arm/usr/local/lib/libssl.a
|
||||||
|
$(LOCAL_DEPS):
|
||||||
|
+@PATH=../../deps/macos_toolchain/bin:$$PATH \
|
||||||
|
BUILD_TARGET=macos-arm \
|
||||||
|
SSL_TARGET=darwin64-arm64 \
|
||||||
|
CC=../../deps/macos_toolchain/bin/oa64-clang \
|
||||||
|
RANLIB=../../deps/macos_toolchain/bin/x86_64-apple-darwin24-ranlib \
|
||||||
|
AR=../../deps/macos_toolchain/bin/arm64-apple-darwin24-ar \
|
||||||
|
tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/macosrelease-arm/% $(BUILD_DIR)/macosdebug-arm/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
||||||
|
|
||||||
|
LOCAL_DEPS := out/openssl/$(UNAME_S)/macos-x86_64/usr/local/lib/libssl.a
|
||||||
|
$(LOCAL_DEPS):
|
||||||
|
+@PATH=../../deps/macos_toolchain/bin:$$PATH \
|
||||||
|
BUILD_TARGET=macos-x86_64 \
|
||||||
|
SSL_TARGET=darwin64-x86_64 \
|
||||||
|
CC=../../deps/macos_toolchain/bin/o64-clang \
|
||||||
|
RANLIB=../../deps/macos_toolchain/bin/x86_64-apple-darwin24-ranlib \
|
||||||
|
AR=../../deps/macos_toolchain/bin/x86_64-apple-darwin24-ar \
|
||||||
|
tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/macosrelease-x86_64/% $(BUILD_DIR)/macosdebug-x86_64/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
LOCAL_DEPS := out/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib/libssl.a
|
||||||
|
$(LOCAL_DEPS):
|
||||||
|
+@tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/debug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/release/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_WIN),1)
|
||||||
|
WINDOWS_DEPS := out/openssl/$(UNAME_S)/mingw64/usr/local/lib/libssl.a
|
||||||
|
$(WINDOWS_DEPS):
|
||||||
|
+@BUILD_TARGET=mingw64 SSL_TARGET=mingw64 OPTIONS="--cross-compile-prefix=x86_64-w64-mingw32-" tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/win%,$(APP_OBJS)): | $(WINDOWS_DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
IOS_DEPS := out/openssl/ios/ios64-xcrun/usr/local/lib/libssl.a
|
||||||
|
$(IOS_DEPS):
|
||||||
|
+@BUILD_PLATFORM=ios BUILD_TARGET=ios64-xcrun SSL_TARGET=ios64-xcrun OPTIONS="-fPIC -Wno-macro-redefined -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)" tools/ssl-local
|
||||||
|
+@BUILD_PLATFORM=ios BUILD_TARGET=iossimulator-xcrun SSL_TARGET=iossimulator-xcrun OPTIONS="-fPIC -Wno-macro-redefined" tools/ssl-local
|
||||||
|
$(filter $(BUILD_DIR)/ios%,$(APP_OBJS)): | $(IOS_DEPS)
|
||||||
|
endif
|
||||||
|
|
||||||
out/macos%/tildefriends: out/macos%-arm/tildefriends out/macos%-x86_64/tildefriends
|
out/macos%/tildefriends: out/macos%-arm/tildefriends out/macos%-x86_64/tildefriends
|
||||||
@echo [lipo] $@
|
@echo [lipo] $@
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@@ -1259,6 +1358,7 @@ tarball: ## Build an all-inclusive source tarball (.tar.xz).
|
|||||||
--exclude=deps/libsodium/test \
|
--exclude=deps/libsodium/test \
|
||||||
--exclude=deps/libuv/docs \
|
--exclude=deps/libuv/docs \
|
||||||
--exclude=deps/libuv/test \
|
--exclude=deps/libuv/test \
|
||||||
|
--exclude=deps/speedscope/*.map \
|
||||||
--exclude=deps/sqlite/shell.c \
|
--exclude=deps/sqlite/shell.c \
|
||||||
--exclude=deps/zlib/contrib/vstudio \
|
--exclude=deps/zlib/contrib/vstudio \
|
||||||
--exclude=deps/zlib/doc \
|
--exclude=deps/zlib/doc \
|
||||||
@@ -1319,7 +1419,7 @@ dist-ios: iosrelease-app
|
|||||||
mkdir -p out/Payload/tildefriends.app
|
mkdir -p out/Payload/tildefriends.app
|
||||||
cp -avR out/tildefriends-iosrelease.app/* out/Payload/tildefriends.app/
|
cp -avR out/tildefriends-iosrelease.app/* out/Payload/tildefriends.app/
|
||||||
cp src/ios/tildefriends.png out/Payload/tildefriends.app/
|
cp src/ios/tildefriends.png out/Payload/tildefriends.app/
|
||||||
xcrun -sdk iphoneos actool --compile out/Payload/tildefriends.app/ --platform iphoneos --minimum-deployment-target $(IPHONEOS_VERSION_MIN) --app-icon AppIcon src/ios/icons/Assets.xcassets src/ios/icons/*.png --output-partial-info-plist out/actool.plist
|
cp src/ios/icons/Assets.car out/Payload/tildefriends.app/
|
||||||
cp src/ios/distribution.mobileprovision out/Payload/tildefriends.app/embedded.mobileprovision
|
cp src/ios/distribution.mobileprovision out/Payload/tildefriends.app/embedded.mobileprovision
|
||||||
xcrun -sdk iphoneos codesign -f -s 'Apple Distribution' --entitlements src/ios/Entitlements.plist --generate-entitlement-der out/Payload/tildefriends.app
|
xcrun -sdk iphoneos codesign -f -s 'Apple Distribution' --entitlements src/ios/Entitlements.plist --generate-entitlement-der out/Payload/tildefriends.app
|
||||||
cd out; zip -r tildefriends.ipa Payload; cd ..
|
cd out; zip -r tildefriends.ipa Payload; cd ..
|
||||||
@@ -1365,18 +1465,6 @@ help: ## Display this help message.
|
|||||||
.PHONY: help
|
.PHONY: help
|
||||||
.DEFAULT_GOAL := help
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
docs: debug
|
|
||||||
docs: ## Build HTML docs.
|
docs: ## Build HTML docs.
|
||||||
@echo '# CLI Usage\n' > docs/usage.md
|
|
||||||
@echo "## tildefriends -h" >> docs/usage.md
|
|
||||||
@echo '\n```' >> docs/usage.md
|
|
||||||
@out/debug/tildefriends -h >> docs/usage.md
|
|
||||||
@echo '```' >> docs/usage.md
|
|
||||||
@for command in $$(out/debug/tildefriends -h | grep -Po '[A-Za-z_]*(?= - )'); do
|
|
||||||
@ echo "\n## tildefriends $$command -h" >> docs/usage.md
|
|
||||||
@ echo '\n```' >> docs/usage.md
|
|
||||||
@ out/debug/tildefriends $$command -h >> docs/usage.md
|
|
||||||
@ echo '```' >> docs/usage.md
|
|
||||||
@done
|
|
||||||
@doxygen
|
@doxygen
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ dependencies in the right places.
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
|
System OpenSSL libraries are assumed to be available on Haiku and OpenSSL.
|
||||||
|
|
||||||
On MacOS, Xcode's command-line tools are expected to be available.
|
On MacOS, Xcode's command-line tools are expected to be available.
|
||||||
|
|
||||||
### Build Commands
|
### Build Commands
|
||||||
@@ -53,8 +55,9 @@ standard.
|
|||||||
## Running
|
## Running
|
||||||
|
|
||||||
By default, running the built `out/debug/tildefriends` executable will start a
|
By default, running the built `out/debug/tildefriends` executable will start a
|
||||||
web server at <http://localhost:12345/>. `tildefriends -h` lists further
|
web server at <http://localhost:12345/>. It expects to be run with the
|
||||||
options.
|
repository root as the current working directory. `tildefriends -h` lists
|
||||||
|
further options.
|
||||||
|
|
||||||
The first user to create an account and log in will be granted administrative
|
The first user to create an account and log in will be granted administrative
|
||||||
privileges. Further administration can be done in the `admin` app at
|
privileges. Further administration can be done in the `admin` app at
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
@@ -108,8 +108,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
@@ -150,7 +148,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
@@ -178,19 +175,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
|
||||||
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
|
||||||
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
|
||||||
.w3-note{color:#000!important;background-color:#fff599!important}
|
|
||||||
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
|
||||||
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
|
||||||
.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
@@ -248,4 +232,4 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "📜",
|
"emoji": "📜",
|
||||||
"previous": "&sJqeyYjHys6Z8IqqtZ2ij2ZC1E2xieu/FU/u2hE+O1U=.sha256"
|
"previous": "&BEf0nraBdHk/+PWqx6tOSu5rheWVaxaL7orAOz3285M=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,6 @@ app.setDocument(`<head>
|
|||||||
</head>
|
</head>
|
||||||
<body style="color:#fff">
|
<body style="color:#fff">
|
||||||
${markdown(docs.docs.global)}
|
${markdown(docs.docs.global)}
|
||||||
<!--
|
|
||||||
${Object.keys(docs.docs).filter(x => [...treeify('', globalThis)].indexOf(x) == -1).map(x => `<p>STALE: ${x}</p>`).join('')}
|
|
||||||
-->
|
|
||||||
${[...treeify('', globalThis)].map(x => document(x)).join('\n')}
|
${[...treeify('', globalThis)].map(x => document(x)).join('\n')}
|
||||||
<a id="Database"></a>
|
<a id="Database"></a>
|
||||||
${markdown(docs.docs.database)}
|
${markdown(docs.docs.database)}
|
||||||
|
|||||||
@@ -195,6 +195,51 @@ Call a function after some delay.
|
|||||||
* *Number* **timeout** Number of milliseconds to wait before calling the callback function.
|
* *Number* **timeout** Number of milliseconds to wait before calling the callback function.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
docs['parseHttpRequest()'] = `
|
||||||
|
Parses an HTTP request.
|
||||||
|
### Parameters
|
||||||
|
* *Uint8Array* **request** The request data. Maybe be partial or contain extra data. The return value will
|
||||||
|
indicate when and where it is complete.
|
||||||
|
* *Number* **last_length** The length of the data passed on a previous attempt for the same request, or 0 initially.
|
||||||
|
### Returns
|
||||||
|
* *Integer* **-2** if the request is incomplete.
|
||||||
|
* *Integer* **-1** if the request could not be parsed.
|
||||||
|
* *Object* An object with **bytes_parsed**, **minor_version**, **path**, and **headers** fields on successful parse.
|
||||||
|
`;
|
||||||
|
|
||||||
|
docs['parseHttpResponse()'] = `
|
||||||
|
Parses an HTTP response.
|
||||||
|
### Parameters
|
||||||
|
* *Uint8Array* **response** The response data. Maybe be partial or contain extra data. The return value will
|
||||||
|
indicate when and where it is complete.
|
||||||
|
* *Number* **last_length** The length of the data passed on a previous attempt for the same response, or 0 initially.
|
||||||
|
### Returns
|
||||||
|
* *Integer* **-2** if the response is incomplete.
|
||||||
|
* *Integer* **-1** if the response could not be parsed.
|
||||||
|
* *Object* An object with **bytes_parsed**, **minor_version**, **status**, **message**, and **headers** fields on successful parse.
|
||||||
|
`;
|
||||||
|
|
||||||
|
docs['sha1Digest()'] = `
|
||||||
|
Calculates a SHA1 digest.
|
||||||
|
|
||||||
|
Completes synchronously.
|
||||||
|
### Parameters
|
||||||
|
* *String* **value** The value for which to calculate the digest.
|
||||||
|
### Returns
|
||||||
|
*String* The SHA1 digest of UTF-8 encoded \`value\`.
|
||||||
|
`;
|
||||||
|
|
||||||
|
docs['maskBytes()'] = `
|
||||||
|
Masks bytes for WebSocket communication.
|
||||||
|
|
||||||
|
Completes synchronously.
|
||||||
|
### Parameters
|
||||||
|
* *Uint8Array* **bytes** The byte array of data to mask.
|
||||||
|
* *Uint32* **mask** The mask to apply.
|
||||||
|
### Returns
|
||||||
|
*Uint32Array* The masked bytes.
|
||||||
|
`;
|
||||||
|
|
||||||
docs['exit()'] = `
|
docs['exit()'] = `
|
||||||
Exits the app. But why would you want to do that?
|
Exits the app. But why would you want to do that?
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
@@ -108,8 +108,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
@@ -150,7 +148,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
@@ -178,19 +175,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
|
||||||
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
|
||||||
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
|
||||||
.w3-note{color:#000!important;background-color:#fff599!important}
|
|
||||||
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
|
||||||
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
|
||||||
.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
@@ -248,4 +232,4 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||||
42
apps/blog/lit-all.min.js
vendored
@@ -1,4 +1,4 @@
|
|||||||
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
@@ -108,8 +108,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
@@ -150,7 +148,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
@@ -178,19 +175,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
|
||||||
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
|
||||||
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
|
||||||
.w3-note{color:#000!important;background-color:#fff599!important}
|
|
||||||
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
|
||||||
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
|
||||||
.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
@@ -248,4 +232,4 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "tildefriends-app",
|
|
||||||
"emoji": "💡",
|
|
||||||
"previous": "&eN6DNPpQUNhGvxneLuLPgsOXR6qyFZ7u+MAz0b4fa7k=.sha256"
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import * as tfrpc from '/tfrpc.js';
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
await app.setDocument(utf8Decode(getFile('index.html')));
|
|
||||||
}
|
|
||||||
|
|
||||||
tfrpc.register(async function complete() {
|
|
||||||
if (
|
|
||||||
core.user?.credentials?.permissions?.administration &&
|
|
||||||
(await core.globalSettingsGet('index')) == '/~core/intro/'
|
|
||||||
) {
|
|
||||||
return await core.globalSettingsSet('index', '/~core/ssb/');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html style="height: 100%; margin: 0; padding: 0; box-sizing: border-box">
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="w3.css" />
|
|
||||||
<style>
|
|
||||||
.slide {
|
|
||||||
display: none;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
.dot {
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.w3-left,
|
|
||||||
.w3-right {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body
|
|
||||||
style="
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
"
|
|
||||||
class="w3-flex w3-dark-gray w3-center"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow: auto;
|
|
||||||
contain: content;
|
|
||||||
padding-top: 16px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div class="slide">
|
|
||||||
<div
|
|
||||||
class="w3-content w3-xlarge w3-card-4 w3-blue w3-panel w3-padding-32 w3-round-xlarge"
|
|
||||||
style="margin: 32px"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div>Welcome to</div>
|
|
||||||
<div>~😎 Tilde Friends.</div>
|
|
||||||
</div>
|
|
||||||
<footer>
|
|
||||||
<button class="w3-button w3-yellow proceed">Next</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="slide w3-card-4 w3-gray" style="width: 90%">
|
|
||||||
<header class="w3-container w3-blue w3-xlarge">
|
|
||||||
<h1>This brief tutorial will introduce:</h1>
|
|
||||||
</header>
|
|
||||||
<ul class="w3-large w3-left-align">
|
|
||||||
<li><b>Secure Scuttlebutt</b>, a decentralized social network.</li>
|
|
||||||
<li>
|
|
||||||
<b>Tilde Friends</b>, the application platform that you are using
|
|
||||||
right now.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<b>How to get started</b> if you want to get gossiping right away.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<footer class="w3-center w3-xlarge w3-padding">
|
|
||||||
<button class="w3-button w3-yellow proceed">Onward</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
<div class="slide w3-gray" style="width: 90%">
|
|
||||||
<div class="w3-card-4 w3-xlarge">
|
|
||||||
<header class="w3-container w3-blue">
|
|
||||||
<h1>💻Secure Scuttlebutt in a Nutshell🦀</h1>
|
|
||||||
</header>
|
|
||||||
<div class="w3-container w3-large w3-left-align">
|
|
||||||
<p>
|
|
||||||
Secure Scuttlebutt is a social network whose technical operation
|
|
||||||
attempts to mirror human social interaction.
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
You can create your own account and post to your own feed on
|
|
||||||
your own device. This is all <b>local</b> with no external
|
|
||||||
communication. This puts you fully in control of your own words
|
|
||||||
and actions.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Before you can interact with others, you need to
|
|
||||||
<b>connect over the network</b>, either directly to your friends
|
|
||||||
(i.e., peer-to-peer between your phones on coffee shop Wi-Fi) or
|
|
||||||
to 🚪<i>rooms</i> and 🍻<i>pubs</i> (hint: search the web for
|
|
||||||
<i>#ssbroom</i>).
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Who you choose to <b>follow</b> determines what you see, with
|
|
||||||
most people choosing to see messages from friends and friends of
|
|
||||||
those friends. If you encounter content you'd rather not see,
|
|
||||||
<b>block</b> the offending account to improve the experience for
|
|
||||||
you and your followers.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Your feed is an <b>immutable</b> log of your activity. Post with
|
|
||||||
care, because like your words in real life, posts can't be taken
|
|
||||||
back.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<footer class="w3-center w3-xlarge w3-padding">
|
|
||||||
<a
|
|
||||||
class="w3-button w3-light-gray"
|
|
||||||
href="https://scuttlebutt.nz/"
|
|
||||||
target="_blank"
|
|
||||||
>See scuttlebutt.nz</a
|
|
||||||
>
|
|
||||||
<button class="w3-button w3-yellow proceed">Got It</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="slide w3-gray" style="width: 90%">
|
|
||||||
<div class="w3-card-4 w3-xlarge">
|
|
||||||
<header class="w3-container w3-blue w3-center">
|
|
||||||
<h1>~😎 Let's Talk Tilde Friends ~😎</h1>
|
|
||||||
</header>
|
|
||||||
<div class="w3-container w3-large w3-left-align">
|
|
||||||
<p>
|
|
||||||
Tilde Friends is an application platform that is an application of
|
|
||||||
its own.
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
This intro is a Tilde Friends app. You can click <b>edit</b> at
|
|
||||||
the top to look under the hood and make changes.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
It is already possible to make and share new applications using
|
|
||||||
only Tilde Friends and Secure Scuttlebutt without having to set
|
|
||||||
up development environments, configure web servers, register
|
|
||||||
domain names, or pay for hosting services.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
But it's also set up so that you can't just break an app that
|
|
||||||
everybody is using or do malicious things with personal content.
|
|
||||||
There are <b>protections</b> in place like an operating system.
|
|
||||||
The intent is also for it to be <b>safe</b> to run strange apps
|
|
||||||
without worrying about adverse effects.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
But this is all a big 🚧work in progress🚧 and
|
|
||||||
<b>experiment</b>. Let's see where it takes us.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<footer class="w3-center w3-xlarge w3-padding">
|
|
||||||
<button class="w3-button w3-yellow proceed">Okay</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="slide w3-gray" style="width: 90%">
|
|
||||||
<div class="w3-card-4 w3-xlarge">
|
|
||||||
<header class="w3-container w3-blue w3-center">
|
|
||||||
<h1>🦀Let's Get this Tilde Friends Party Started🎉</h1>
|
|
||||||
</header>
|
|
||||||
<div class="w3-container w3-large w3-left-align">
|
|
||||||
<p>The button below will take you to the Secure Scuttlebutt app.</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
Remember:
|
|
||||||
<ol>
|
|
||||||
<li>You are in charge. This is all on your device.</li>
|
|
||||||
<li>
|
|
||||||
Make network connections to exchange messages with others.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Follow more accounts to see more content, and block those
|
|
||||||
posting content you'd rather not see.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Be respectful, and consider the consequences of what you
|
|
||||||
post.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
This is all under active development. Exercise patience, and
|
|
||||||
report issues encountered.
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
To see this tutorial again later, select <b>apps</b> ->
|
|
||||||
<b>Core Apps</b> -> <b>intro</b>.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<footer class="w3-center w3-xlarge w3-padding">
|
|
||||||
<button class="w3-button w3-yellow" id="complete">Let's Go!</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="w3-text-white w3-xlarge w3-center w3-flex"
|
|
||||||
style="
|
|
||||||
width: 100%;
|
|
||||||
flex: 0 1;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<div class="w3-jumbo" id="left" style="flex: 1 0; cursor: pointer">
|
|
||||||
❮
|
|
||||||
</div>
|
|
||||||
<span class="w3-badge dot w3-border w3-hover-yellow"></span>
|
|
||||||
<span class="w3-badge dot w3-border w3-hover-yellow"></span>
|
|
||||||
<span class="w3-badge dot w3-border w3-hover-yellow"></span>
|
|
||||||
<span class="w3-badge dot w3-border w3-hover-yellow"></span>
|
|
||||||
<span class="w3-badge dot w3-border w3-hover-yellow"></span>
|
|
||||||
<div class="w3-jumbo" style="flex: 1 0; cursor: pointer" id="right">
|
|
||||||
❯
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="module">
|
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
|
||||||
|
|
||||||
let index = 0;
|
|
||||||
function set(i) {
|
|
||||||
show(i - index);
|
|
||||||
}
|
|
||||||
function show(delta) {
|
|
||||||
let slides = [...document.getElementsByClassName('slide')];
|
|
||||||
let dots = [...document.getElementsByClassName('dot')];
|
|
||||||
index = (index + delta + slides.length) % slides.length;
|
|
||||||
for (let slide of slides) {
|
|
||||||
slide.style.display =
|
|
||||||
slides.indexOf(slide) == index ? 'block' : 'none';
|
|
||||||
}
|
|
||||||
for (let dot of dots) {
|
|
||||||
if (dots.indexOf(dot) == index) {
|
|
||||||
dot.classList.add('w3-white');
|
|
||||||
} else {
|
|
||||||
dot.classList.remove('w3-white');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.getElementById('left').style.visibility =
|
|
||||||
index == 0 ? 'hidden' : 'visible';
|
|
||||||
document.getElementById('right').style.visibility =
|
|
||||||
index == slides.length - 1 ? 'hidden' : 'visible';
|
|
||||||
}
|
|
||||||
|
|
||||||
let dots = [...document.getElementsByClassName('dot')];
|
|
||||||
for (let dot of dots) {
|
|
||||||
dot.onclick = () => set(dots.indexOf(dot));
|
|
||||||
}
|
|
||||||
for (let button of document.getElementsByClassName('proceed')) {
|
|
||||||
button.onclick = () => show(1);
|
|
||||||
}
|
|
||||||
document.getElementById('left').onclick = () => show(-1);
|
|
||||||
document.getElementById('right').onclick = () => show(1);
|
|
||||||
document.getElementById('complete').onclick = function () {
|
|
||||||
console.log('completing');
|
|
||||||
tfrpc.rpc.complete().finally(function () {
|
|
||||||
console.log('completed');
|
|
||||||
let a = document.createElement('a');
|
|
||||||
a.href = '/~core/ssb/';
|
|
||||||
a.target = '_top';
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
window.addEventListener('keyup', function (event) {
|
|
||||||
if (event.key == 'ArrowLeft') {
|
|
||||||
show(-1);
|
|
||||||
} else if (event.key == 'ArrowRight') {
|
|
||||||
show(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
show(0);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
|
||||||
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item}
|
|
||||||
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
|
|
||||||
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
|
|
||||||
a{background-color:transparent}a:active,a:hover{outline-width:0}
|
|
||||||
abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
|
|
||||||
b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000}
|
|
||||||
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
|
||||||
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none}
|
|
||||||
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}
|
|
||||||
button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold}
|
|
||||||
button,input{overflow:visible}button,select{text-transform:none}
|
|
||||||
button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}
|
|
||||||
button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}
|
|
||||||
button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}
|
|
||||||
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
|
|
||||||
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
|
|
||||||
[type=checkbox],[type=radio]{padding:0}
|
|
||||||
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
|
|
||||||
[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
|
|
||||||
[type=search]::-webkit-search-decoration{-webkit-appearance:none}
|
|
||||||
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
|
|
||||||
/* End extract */
|
|
||||||
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
|
|
||||||
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}
|
|
||||||
.w3-serif{font-family:serif}.w3-sans-serif{font-family:sans-serif}.w3-cursive{font-family:cursive}.w3-monospace{font-family:monospace}
|
|
||||||
h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
|
|
||||||
hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|
||||||
.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit}
|
|
||||||
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
|
|
||||||
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
|
|
||||||
.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
|
|
||||||
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
|
|
||||||
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
|
|
||||||
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
|
||||||
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
|
|
||||||
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
|
||||||
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
|
||||||
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
|
||||||
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
|
||||||
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
|
||||||
.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
|
|
||||||
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
|
|
||||||
.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
|
|
||||||
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
|
|
||||||
.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
|
|
||||||
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
|
|
||||||
.w3-dropdown-hover:hover .w3-dropdown-content{display:block}
|
|
||||||
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
|
||||||
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
|
|
||||||
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1}
|
|
||||||
.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
|
|
||||||
.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
|
|
||||||
.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
|
|
||||||
.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
|
||||||
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
|
|
||||||
.w3-main,#main{transition:margin-left .4s}
|
|
||||||
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
|
|
||||||
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
|
|
||||||
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
|
|
||||||
.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0}
|
|
||||||
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
|
|
||||||
.w3-bar .w3-button{white-space:normal}
|
|
||||||
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0}
|
|
||||||
.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
|
|
||||||
.w3-responsive{display:block;overflow-x:auto}
|
|
||||||
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
|
|
||||||
.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
|
|
||||||
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
|
|
||||||
.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%}
|
|
||||||
.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%}
|
|
||||||
.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%}
|
|
||||||
@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}
|
|
||||||
.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%}
|
|
||||||
.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}}
|
|
||||||
@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%}
|
|
||||||
.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%}
|
|
||||||
.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}}
|
|
||||||
.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px}
|
|
||||||
.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px}
|
|
||||||
.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
|
|
||||||
.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
|
|
||||||
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
|
||||||
@media (max-width:1205px){.w3-auto{max-width:95%}}
|
|
||||||
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
|
||||||
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
|
||||||
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
|
||||||
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
|
||||||
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
|
||||||
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
|
|
||||||
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
|
|
||||||
@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}}
|
|
||||||
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
|
|
||||||
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
|
|
||||||
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
|
|
||||||
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
|
|
||||||
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
|
|
||||||
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
|
|
||||||
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
|
|
||||||
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
|
||||||
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
|
||||||
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
|
|
||||||
.w3-display-position{position:absolute}
|
|
||||||
.w3-circle{border-radius:50%}
|
|
||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
|
||||||
.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
|
|
||||||
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
|
|
||||||
.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
|
|
||||||
.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
|
||||||
.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
|
|
||||||
.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
|
||||||
.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
|
||||||
.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
|
||||||
.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
|
|
||||||
.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
|
|
||||||
.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
|
|
||||||
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
|
|
||||||
.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
|
|
||||||
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
|
|
||||||
.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
|
|
||||||
.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
|
|
||||||
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
|
|
||||||
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
|
|
||||||
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
|
|
||||||
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
|
|
||||||
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
|
|
||||||
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
|
|
||||||
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
|
|
||||||
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
|
|
||||||
.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
|
|
||||||
.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
|
|
||||||
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
|
|
||||||
.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
|
|
||||||
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
|
|
||||||
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
|
|
||||||
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
|
|
||||||
.w3-padding-top-64{padding-top:64px!important}.w3-padding-top-48{padding-top:48px!important}
|
|
||||||
.w3-padding-top-32{padding-top:32px!important}.w3-padding-top-24{padding-top:24px!important}
|
|
||||||
.w3-left{float:left!important}.w3-right{float:right!important}
|
|
||||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
|
||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
|
||||||
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
|
||||||
/* Colors */
|
|
||||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
|
||||||
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
|
||||||
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
|
||||||
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
|
||||||
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
|
||||||
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
|
|
||||||
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
|
|
||||||
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
|
|
||||||
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
|
|
||||||
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
|
|
||||||
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
|
|
||||||
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
|
|
||||||
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
|
|
||||||
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
|
||||||
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
|
||||||
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
|
||||||
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
|
||||||
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
|
||||||
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
|
||||||
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
|
||||||
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
|
||||||
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
|
||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
|
||||||
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
|
||||||
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
|
||||||
.w3-note{color:#000!important;background-color:#fff599!important}
|
|
||||||
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
|
||||||
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
|
||||||
.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
|
||||||
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
|
|
||||||
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
|
|
||||||
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
|
|
||||||
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
|
|
||||||
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
|
|
||||||
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
|
|
||||||
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
|
|
||||||
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
|
|
||||||
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
|
|
||||||
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
|
|
||||||
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
|
|
||||||
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
|
|
||||||
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
|
|
||||||
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
|
|
||||||
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
|
|
||||||
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
|
|
||||||
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
|
|
||||||
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
|
|
||||||
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
|
|
||||||
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
|
|
||||||
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
|
|
||||||
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
|
|
||||||
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
|
|
||||||
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
|
|
||||||
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
|
|
||||||
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
|
|
||||||
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
|
|
||||||
.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
|
|
||||||
.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
|
|
||||||
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
|
|
||||||
.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
|
|
||||||
.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
|
|
||||||
.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
|
|
||||||
.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
|
|
||||||
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
|
|
||||||
.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
|
|
||||||
.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
|
|
||||||
.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
|
|
||||||
.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
|
|
||||||
.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
|
|
||||||
.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
|
|
||||||
.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
|
|
||||||
.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
|
|
||||||
.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
|
|
||||||
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
|
|
||||||
.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
|
|
||||||
.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
|
|
||||||
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
|
|
||||||
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
|
|
||||||
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
|
|
||||||
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
|
|
||||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
|
||||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
|
||||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
|
||||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
|
||||||
42
apps/issues/lit-all.min.js
vendored
42
apps/journal/lit-all.min.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🚪",
|
"emoji": "🚪",
|
||||||
"previous": "&DJwkqNfYWtW9yBtJQMseEXm7l04Enpi+yAxZulLq9Vk=.sha256"
|
"previous": "&HXCdDG8gGYXElTyEFbg85jqa6lDXNL2ENPIA9UoJNbI=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
async function main() {
|
async function main() {
|
||||||
print(core.url);
|
let host = core.url.match(/.*\/\/(.*?)\//)[1];
|
||||||
let host = core.url.match(/.*?\/\/([^:/]*)/)[1];
|
let id = (await ssb.getServerIdentity()).substring(1);
|
||||||
let port = await ssb.port();
|
let room = `net:${host}:${ssb.port}~shs:${id}:SSB+Room+SK3TLYC2T86EHQCUHBUHASCASE18JBV24=`;
|
||||||
let id = (await ssb.getServerIdentity()).substring(1).split('.')[0];
|
|
||||||
let room = `net:${host}:${port}~shs:${id}:SSB+Room+PSK3TLYC2T86EHQCUHBUHASCASE18JBV24=`;
|
|
||||||
await app.setDocument(`
|
await app.setDocument(`
|
||||||
<body style="color: #fff">
|
<body style="color: #fff">
|
||||||
<h1>Server</h1>
|
<h1>Server</h1>
|
||||||
|
|||||||
42
apps/sneaker/lit-all.min.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🦀",
|
"emoji": "🦀",
|
||||||
"previous": "&7dPNAI4sffljUTiwGr3XEUeB8sBD72CFkWMk/o0Z2pw=.sha256"
|
"previous": "&jAAzd36Nmpw0sRA1Dx9wLiIwGX+q//+S/Han+RLlEOw=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import * as tfrpc from '/tfrpc.js';
|
|||||||
|
|
||||||
let g_database;
|
let g_database;
|
||||||
let g_hash;
|
let g_hash;
|
||||||
let g_sql_cache = {};
|
|
||||||
|
|
||||||
tfrpc.register(async function localStorageGet(key) {
|
tfrpc.register(async function localStorageGet(key) {
|
||||||
return app.localStorageGet(key);
|
return app.localStorageGet(key);
|
||||||
@@ -52,38 +51,11 @@ tfrpc.register(async function connect(token) {
|
|||||||
tfrpc.register(async function closeConnection(id) {
|
tfrpc.register(async function closeConnection(id) {
|
||||||
await ssb.closeConnection(id);
|
await ssb.closeConnection(id);
|
||||||
});
|
});
|
||||||
tfrpc.register(async function query(sql, args, options) {
|
tfrpc.register(async function query(sql, args) {
|
||||||
let start = new Date();
|
|
||||||
let result = [];
|
let result = [];
|
||||||
let key = options?.cacheable ? JSON.stringify([sql, args]) : undefined;
|
await ssb.sqlAsync(sql, args, function callback(row) {
|
||||||
let entry = key ? g_sql_cache[key] : undefined;
|
result.push(row);
|
||||||
const k_ideal_count = 64;
|
});
|
||||||
if (entry) {
|
|
||||||
result = entry.result;
|
|
||||||
} else {
|
|
||||||
await ssb.sqlAsync(sql, args, function callback(row) {
|
|
||||||
result.push(row);
|
|
||||||
});
|
|
||||||
if (key) {
|
|
||||||
g_sql_cache[key] = {
|
|
||||||
result: result,
|
|
||||||
time: new Date().valueOf(),
|
|
||||||
};
|
|
||||||
if (Object.keys(g_sql_cache).length > k_ideal_count * 2) {
|
|
||||||
let aged = Object.entries(g_sql_cache).map(([k, v]) => [v.time, k]);
|
|
||||||
aged.sort();
|
|
||||||
for (let i = 0; i < aged.length / 2; i++) {
|
|
||||||
delete g_sql_cache[aged[i][1]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let end = new Date();
|
|
||||||
print(
|
|
||||||
(end - start) / 1000,
|
|
||||||
entry ? 'from cache' : 'from db',
|
|
||||||
sql.replaceAll(/\s+/g, ' ').trim()
|
|
||||||
);
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
tfrpc.register(async function appendMessage(id, message) {
|
tfrpc.register(async function appendMessage(id, message) {
|
||||||
@@ -104,9 +76,6 @@ tfrpc.register(function setHash(hash) {
|
|||||||
core.register('onMessage', async function (id) {
|
core.register('onMessage', async function (id) {
|
||||||
await tfrpc.rpc.notifyNewMessage(id);
|
await tfrpc.rpc.notifyNewMessage(id);
|
||||||
});
|
});
|
||||||
core.register('onBlob', async function (id) {
|
|
||||||
await tfrpc.rpc.notifyNewBlob(id);
|
|
||||||
});
|
|
||||||
tfrpc.register(async function store_blob(blob) {
|
tfrpc.register(async function store_blob(blob) {
|
||||||
if (Array.isArray(blob)) {
|
if (Array.isArray(blob)) {
|
||||||
blob = Uint8Array.from(blob);
|
blob = Uint8Array.from(blob);
|
||||||
@@ -137,15 +106,6 @@ tfrpc.register(async function sync() {
|
|||||||
tfrpc.register(async function url() {
|
tfrpc.register(async function url() {
|
||||||
return core.url;
|
return core.url;
|
||||||
});
|
});
|
||||||
tfrpc.register(async function globalSettingsGet(key) {
|
|
||||||
return core.globalSettingsGet(key);
|
|
||||||
});
|
|
||||||
tfrpc.register(async function globalSettingsSet(key, value) {
|
|
||||||
return core.globalSettingsSet(key, value);
|
|
||||||
});
|
|
||||||
tfrpc.register(function isAdministrator() {
|
|
||||||
return core.user?.credentials?.permissions?.administration;
|
|
||||||
});
|
|
||||||
|
|
||||||
core.register('onBroadcastsChanged', async function () {
|
core.register('onBroadcastsChanged', async function () {
|
||||||
await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts());
|
await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts());
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {html, render} from './lit-all.min.js';
|
import {html, render} from './lit-all.min.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
let g_emojis;
|
let g_emojis;
|
||||||
|
|
||||||
@@ -14,8 +14,23 @@ function get_emojis() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function picker(callback, anchor, author, recent) {
|
async function get_recent(author) {
|
||||||
|
let recent = await tfrpc.rpc.query(
|
||||||
|
`
|
||||||
|
SELECT DISTINCT content ->> '$.vote.expression' AS value
|
||||||
|
FROM messages
|
||||||
|
WHERE author = ? AND
|
||||||
|
content ->> '$.type' = 'vote'
|
||||||
|
ORDER BY timestamp DESC LIMIT 10
|
||||||
|
`,
|
||||||
|
[author]
|
||||||
|
);
|
||||||
|
return recent.map((x) => x.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function picker(callback, anchor, author) {
|
||||||
let json = await get_emojis();
|
let json = await get_emojis();
|
||||||
|
let recent = await get_recent(author);
|
||||||
|
|
||||||
let div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
div.id = 'emoji_picker';
|
div.id = 'emoji_picker';
|
||||||
@@ -140,9 +155,6 @@ export async function picker(callback, anchor, author, recent) {
|
|||||||
<style>
|
<style>
|
||||||
${styles}
|
${styles}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
|
||||||
${generate_theme()}
|
|
||||||
</style>
|
|
||||||
<div
|
<div
|
||||||
class="w3-modal"
|
class="w3-modal"
|
||||||
style="display: block; box-sizing: border-box; z-index: 10"
|
style="display: block; box-sizing: border-box; z-index: 10"
|
||||||
|
|||||||
42
apps/ssb/lit-all.min.js
vendored
@@ -12,14 +12,12 @@ import * as tf_tab_news from './tf-tab-news.js';
|
|||||||
import * as tf_tab_news_feed from './tf-tab-news-feed.js';
|
import * as tf_tab_news_feed from './tf-tab-news-feed.js';
|
||||||
import * as tf_tab_search from './tf-tab-search.js';
|
import * as tf_tab_search from './tf-tab-search.js';
|
||||||
import * as tf_tab_connections from './tf-tab-connections.js';
|
import * as tf_tab_connections from './tf-tab-connections.js';
|
||||||
|
import * as tf_tab_query from './tf-tab-query.js';
|
||||||
import * as tf_tag from './tf-tag.js';
|
import * as tf_tag from './tf-tag.js';
|
||||||
import * as tf_styles from './tf-styles.js';
|
import * as tf_styles from './tf-styles.js';
|
||||||
|
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
let style = document.createElement('style');
|
let style = document.createElement('style');
|
||||||
style.innerText = tf_styles.styles;
|
style.innerText = tf_styles.styles;
|
||||||
Promise.resolve(tf_styles.generate_theme()).then(function (x) {
|
|
||||||
style.innerText += x;
|
|
||||||
});
|
|
||||||
document.body.appendChild(style);
|
document.body.appendChild(style);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html, css, guard, until} from './lit-all.min.js';
|
import {LitElement, html, css, guard, until} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfElement extends LitElement {
|
class TfElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -11,7 +11,6 @@ class TfElement extends LitElement {
|
|||||||
broadcasts: {type: Array},
|
broadcasts: {type: Array},
|
||||||
connections: {type: Array},
|
connections: {type: Array},
|
||||||
loading: {type: Boolean},
|
loading: {type: Boolean},
|
||||||
loading_about: {type: Number},
|
|
||||||
loaded: {type: Boolean},
|
loaded: {type: Boolean},
|
||||||
following: {type: Array},
|
following: {type: Array},
|
||||||
users: {type: Object},
|
users: {type: Object},
|
||||||
@@ -21,13 +20,7 @@ class TfElement extends LitElement {
|
|||||||
channels_latest: {type: Object},
|
channels_latest: {type: Object},
|
||||||
guest: {type: Boolean},
|
guest: {type: Boolean},
|
||||||
url: {type: String},
|
url: {type: String},
|
||||||
private_closed: {type: Object},
|
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
grouped_private_messages: {type: Object},
|
|
||||||
recent_reactions: {type: Array},
|
|
||||||
is_administrator: {type: Boolean},
|
|
||||||
stay_connected: {type: Boolean},
|
|
||||||
progress: {type: Number},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,14 +36,11 @@ class TfElement extends LitElement {
|
|||||||
this.following = [];
|
this.following = [];
|
||||||
this.users = {};
|
this.users = {};
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.loading_about = 0;
|
|
||||||
this.channels = [];
|
this.channels = [];
|
||||||
this.channels_unread = {};
|
this.channels_unread = {};
|
||||||
this.channels_latest = {};
|
this.channels_latest = {};
|
||||||
this.loading_latest = 0;
|
this.loading_latest = 0;
|
||||||
this.loading_latest_scheduled = 0;
|
this.loading_latest_scheduled = 0;
|
||||||
this.recent_reactions = [];
|
|
||||||
this.private_closed = {};
|
|
||||||
tfrpc.rpc.getBroadcasts().then((b) => {
|
tfrpc.rpc.getBroadcasts().then((b) => {
|
||||||
self.broadcasts = b || [];
|
self.broadcasts = b || [];
|
||||||
});
|
});
|
||||||
@@ -60,22 +50,10 @@ class TfElement extends LitElement {
|
|||||||
tfrpc.rpc.getHash().then((hash) => self.set_hash(hash));
|
tfrpc.rpc.getHash().then((hash) => self.set_hash(hash));
|
||||||
tfrpc.register(function hashChanged(hash) {
|
tfrpc.register(function hashChanged(hash) {
|
||||||
self.set_hash(hash);
|
self.set_hash(hash);
|
||||||
self.reset_progress();
|
|
||||||
});
|
});
|
||||||
tfrpc.register(async function notifyNewMessage(id) {
|
tfrpc.register(async function notifyNewMessage(id) {
|
||||||
await self.fetch_new_message(id);
|
await self.fetch_new_message(id);
|
||||||
});
|
});
|
||||||
tfrpc.register(async function notifyNewBlob(id) {
|
|
||||||
window.dispatchEvent(
|
|
||||||
new CustomEvent('blob-stored', {
|
|
||||||
bubbles: true,
|
|
||||||
composed: true,
|
|
||||||
detail: {
|
|
||||||
id: id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
tfrpc.register(function set(name, value) {
|
tfrpc.register(function set(name, value) {
|
||||||
if (name === 'broadcasts') {
|
if (name === 'broadcasts') {
|
||||||
self.broadcasts = value;
|
self.broadcasts = value;
|
||||||
@@ -91,30 +69,13 @@ class TfElement extends LitElement {
|
|||||||
async initial_load() {
|
async initial_load() {
|
||||||
let whoami = await tfrpc.rpc.getActiveIdentity();
|
let whoami = await tfrpc.rpc.getActiveIdentity();
|
||||||
let ids = (await tfrpc.rpc.getIdentities()) || [];
|
let ids = (await tfrpc.rpc.getIdentities()) || [];
|
||||||
this.is_administrator = await tfrpc.rpc.isAdministrator();
|
|
||||||
this.stay_connected =
|
|
||||||
this.is_administrator &&
|
|
||||||
(await tfrpc.rpc.globalSettingsGet('stay_connected'));
|
|
||||||
this.url = await tfrpc.rpc.url();
|
this.url = await tfrpc.rpc.url();
|
||||||
this.whoami = whoami ?? (ids.length ? ids[0] : undefined);
|
this.whoami = whoami ?? (ids.length ? ids[0] : undefined);
|
||||||
this.guest = !this.whoami?.length;
|
this.guest = !this.whoami?.length;
|
||||||
this.ids = ids;
|
this.ids = ids;
|
||||||
let private_closed =
|
|
||||||
(await tfrpc.rpc.databaseGet('private_closed')) ?? '{}';
|
|
||||||
this.private_closed = JSON.parse(private_closed);
|
|
||||||
await this.load_channels();
|
await this.load_channels();
|
||||||
}
|
}
|
||||||
|
|
||||||
async close_private_chat(event) {
|
|
||||||
let update = {};
|
|
||||||
update[event.detail.key] = true;
|
|
||||||
this.private_closed = Object.assign(update, this.private_closed);
|
|
||||||
await tfrpc.rpc.databaseSet(
|
|
||||||
'private_closed',
|
|
||||||
JSON.stringify(this.private_closed)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async load_channels() {
|
async load_channels() {
|
||||||
let channels = await tfrpc.rpc.query(
|
let channels = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
@@ -162,34 +123,8 @@ class TfElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visible_private() {
|
|
||||||
if (!this.grouped_private_messages || !this.private_closed) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
let self = this;
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(this.grouped_private_messages).filter(([key, value]) => {
|
|
||||||
let channel = '🔐' + [...new Set(JSON.parse(key))].sort().join(',');
|
|
||||||
let grouped_latest = Math.max(...value.map((x) => x.rowid));
|
|
||||||
return (
|
|
||||||
!self.private_closed[key] ||
|
|
||||||
self.channels_unread[channel] === undefined ||
|
|
||||||
grouped_latest > self.channels_unread[channel]
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
next_channel(delta) {
|
next_channel(delta) {
|
||||||
let channel_names = [
|
let channel_names = ['', '@', '🔐', ...this.channels.map((x) => '#' + x)];
|
||||||
'',
|
|
||||||
'@',
|
|
||||||
'👍',
|
|
||||||
...Object.keys(this.visible_private())
|
|
||||||
.sort()
|
|
||||||
.map((x) => '🔐' + JSON.parse(x).join(',')),
|
|
||||||
...this.channels.map((x) => '#' + x),
|
|
||||||
];
|
|
||||||
let index = channel_names.indexOf(this.hash.substring(1));
|
let index = channel_names.indexOf(this.hash.substring(1));
|
||||||
index = index != -1 ? index + delta : 0;
|
index = index != -1 ? index + delta : 0;
|
||||||
tfrpc.rpc.setHash(
|
tfrpc.rpc.setHash(
|
||||||
@@ -206,15 +141,16 @@ class TfElement extends LitElement {
|
|||||||
this.tab = 'search';
|
this.tab = 'search';
|
||||||
} else if (this.hash === '#connections') {
|
} else if (this.hash === '#connections') {
|
||||||
this.tab = 'connections';
|
this.tab = 'connections';
|
||||||
|
} else if (this.hash.startsWith('#sql=')) {
|
||||||
|
this.tab = 'query';
|
||||||
} else {
|
} else {
|
||||||
this.tab = 'news';
|
this.tab = 'news';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetch_about(following, users) {
|
async fetch_about(following, users) {
|
||||||
this.loading_about++;
|
|
||||||
let ids = Object.keys(following).sort();
|
let ids = Object.keys(following).sort();
|
||||||
const k_cache_version = 3;
|
const k_cache_version = 1;
|
||||||
let cache = await tfrpc.rpc.databaseGet('about');
|
let cache = await tfrpc.rpc.databaseGet('about');
|
||||||
let original_cache = cache;
|
let original_cache = cache;
|
||||||
cache = cache ? JSON.parse(cache) : {};
|
cache = cache ? JSON.parse(cache) : {};
|
||||||
@@ -222,86 +158,81 @@ class TfElement extends LitElement {
|
|||||||
cache = {
|
cache = {
|
||||||
version: k_cache_version,
|
version: k_cache_version,
|
||||||
about: {},
|
about: {},
|
||||||
|
last_row_id: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
let max_row_id = (
|
||||||
let ids_out_of_date = ids.filter(
|
await tfrpc.rpc.query(
|
||||||
(x) =>
|
`
|
||||||
(users[x]?.seq && !cache.about[x]?.seq) ||
|
SELECT MAX(rowid) AS max_row_id FROM messages
|
||||||
(users[x]?.seq && users[x]?.seq > cache.about[x].seq)
|
`,
|
||||||
);
|
[]
|
||||||
|
)
|
||||||
|
)[0].max_row_id;
|
||||||
for (let id of Object.keys(cache.about)) {
|
for (let id of Object.keys(cache.about)) {
|
||||||
if (ids.indexOf(id) == -1) {
|
if (ids.indexOf(id) == -1) {
|
||||||
delete cache.about[id];
|
delete cache.about[id];
|
||||||
} else {
|
|
||||||
users[id] = Object.assign(cache.about[id], users[id] || {});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
let abouts = await tfrpc.rpc.query(
|
||||||
'loading about for',
|
`
|
||||||
ids.length,
|
SELECT
|
||||||
'accounts',
|
messages.author, json(messages.content) AS content, messages.sequence
|
||||||
ids_out_of_date.length,
|
FROM
|
||||||
'out of date'
|
messages,
|
||||||
|
json_each(?1) AS following
|
||||||
|
WHERE
|
||||||
|
messages.author = following.value AND
|
||||||
|
messages.rowid > ?3 AND
|
||||||
|
messages.rowid <= ?4 AND
|
||||||
|
json_extract(messages.content, '$.type') = 'about'
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
messages.author, json(messages.content) AS content, messages.sequence
|
||||||
|
FROM
|
||||||
|
messages,
|
||||||
|
json_each(?2) AS following
|
||||||
|
WHERE
|
||||||
|
messages.author = following.value AND
|
||||||
|
messages.rowid <= ?4 AND
|
||||||
|
json_extract(messages.content, '$.type') = 'about'
|
||||||
|
ORDER BY messages.author, messages.sequence
|
||||||
|
`,
|
||||||
|
[
|
||||||
|
JSON.stringify(ids.filter((id) => cache.about[id])),
|
||||||
|
JSON.stringify(ids.filter((id) => !cache.about[id])),
|
||||||
|
cache.last_row_id,
|
||||||
|
max_row_id,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
if (ids_out_of_date.length) {
|
for (let about of abouts) {
|
||||||
try {
|
let content = JSON.parse(about.content);
|
||||||
let rows = await tfrpc.rpc.query(
|
if (content.about === about.author) {
|
||||||
`
|
delete content.type;
|
||||||
SELECT all_abouts.author, json(json_group_object(all_abouts.key, all_abouts.value)) AS about
|
delete content.about;
|
||||||
FROM (
|
cache.about[about.author] = Object.assign(
|
||||||
SELECT
|
cache.about[about.author] || {},
|
||||||
messages.author,
|
content
|
||||||
fields.key,
|
|
||||||
RANK() OVER (PARTITION BY messages.author, fields.key ORDER BY messages.sequence DESC) AS rank,
|
|
||||||
fields.value
|
|
||||||
FROM messages JOIN json_each(messages.content) AS fields
|
|
||||||
WHERE
|
|
||||||
messages.content ->> '$.type' = 'about' AND
|
|
||||||
messages.content ->> '$.about' = messages.author AND
|
|
||||||
NOT fields.key IN ('about', 'type')) all_abouts
|
|
||||||
JOIN json_each(?) AS following ON all_abouts.author = following.value
|
|
||||||
WHERE rank = 1
|
|
||||||
GROUP BY all_abouts.author
|
|
||||||
`,
|
|
||||||
[JSON.stringify(ids_out_of_date)]
|
|
||||||
);
|
);
|
||||||
users = users || {};
|
|
||||||
for (let row of rows) {
|
|
||||||
users[row.author] = Object.assign(
|
|
||||||
users[row.author] || {},
|
|
||||||
JSON.parse(row.about)
|
|
||||||
);
|
|
||||||
cache.about[row.author] = Object.assign(
|
|
||||||
{seq: users[row.author].seq},
|
|
||||||
JSON.parse(row.about)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cache.last_row_id = max_row_id;
|
||||||
for (let id of ids_out_of_date) {
|
|
||||||
if (!cache.about[id]?.seq) {
|
|
||||||
cache.about[id] = Object.assign(cache.about[id] ?? {}, {
|
|
||||||
seq: users[id]?.seq ?? 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loading_about--;
|
|
||||||
|
|
||||||
let new_cache = JSON.stringify(cache);
|
let new_cache = JSON.stringify(cache);
|
||||||
if (new_cache != original_cache) {
|
if (new_cache !== original_cache) {
|
||||||
let start_time = new Date();
|
let start_time = new Date();
|
||||||
tfrpc.rpc.databaseSet('about', new_cache).then(function () {
|
tfrpc.rpc.databaseSet('about', new_cache).then(function () {
|
||||||
console.log('saving about took', (new Date() - start_time) / 1000);
|
console.log('saving about took', (new Date() - start_time) / 1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
users = users || {};
|
||||||
|
for (let id of Object.keys(cache.about)) {
|
||||||
|
users[id] = Object.assign(
|
||||||
|
{follow_depth: following[id]?.d},
|
||||||
|
users[id] || {},
|
||||||
|
cache.about[id]
|
||||||
|
);
|
||||||
|
}
|
||||||
return Object.assign({}, users);
|
return Object.assign({}, users);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +292,11 @@ class TfElement extends LitElement {
|
|||||||
ranges.push([i, Math.min(i + k_chunk_size, latest), true]);
|
ranges.push([i, Math.min(i + k_chunk_size, latest), true]);
|
||||||
}
|
}
|
||||||
for (let i = cache.range[0]; i >= 0; i -= k_chunk_size) {
|
for (let i = cache.range[0]; i >= 0; i -= k_chunk_size) {
|
||||||
ranges.push([Math.max(i - k_chunk_size, 0), i, false]);
|
ranges.push([
|
||||||
|
Math.max(i - k_chunk_size, 0),
|
||||||
|
Math.min(cache.range[0], i + k_chunk_size),
|
||||||
|
false,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < latest; i += k_chunk_size) {
|
for (let i = 0; i < latest; i += k_chunk_size) {
|
||||||
@@ -377,7 +312,7 @@ class TfElement extends LitElement {
|
|||||||
messages.rowid > ?1 AND
|
messages.rowid > ?1 AND
|
||||||
messages.rowid <= ?2 AND
|
messages.rowid <= ?2 AND
|
||||||
json(messages.content) LIKE '"%'
|
json(messages.content) LIKE '"%'
|
||||||
ORDER BY messages.rowid DESC
|
ORDER BY sequence DESC
|
||||||
`,
|
`,
|
||||||
[range[0], range[1]]
|
[range[0], range[1]]
|
||||||
);
|
);
|
||||||
@@ -403,116 +338,52 @@ class TfElement extends LitElement {
|
|||||||
return [cache.latest, cache.messages];
|
return [cache.latest, cache.messages];
|
||||||
}
|
}
|
||||||
|
|
||||||
async group_private_messages(messages) {
|
|
||||||
let groups = {};
|
|
||||||
let result = await this.decrypt(
|
|
||||||
await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT messages.rowid, messages.id, author, timestamp, json(content) AS content
|
|
||||||
FROM messages
|
|
||||||
JOIN json_each(?) AS ids
|
|
||||||
WHERE messages.id = ids.value
|
|
||||||
ORDER BY timestamp DESC
|
|
||||||
`,
|
|
||||||
[JSON.stringify(messages)]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
for (let message of result) {
|
|
||||||
let key = JSON.stringify(
|
|
||||||
[
|
|
||||||
...new Set(
|
|
||||||
message?.decrypted?.recps?.filter((x) => x != this.whoami)
|
|
||||||
),
|
|
||||||
].sort() ?? []
|
|
||||||
);
|
|
||||||
if (!groups[key]) {
|
|
||||||
groups[key] = [];
|
|
||||||
}
|
|
||||||
groups[key].push(message);
|
|
||||||
}
|
|
||||||
return groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
async load_channels_latest(following) {
|
async load_channels_latest(following) {
|
||||||
let start_time = new Date();
|
let start_time = new Date();
|
||||||
let latest_private = this.get_latest_private(following);
|
let latest_private = this.get_latest_private(following);
|
||||||
const k_args = [
|
let channels = await tfrpc.rpc.query(
|
||||||
JSON.stringify(this.channels),
|
`
|
||||||
JSON.stringify(following),
|
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||||
'"' + this.whoami.replace('"', '""') + '"',
|
JOIN json_each(?1) AS channels ON messages.content ->> 'channel' = channels.value
|
||||||
this.whoami,
|
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||||
];
|
WHERE
|
||||||
let channels = (
|
messages.content ->> 'type' = 'post' AND
|
||||||
await Promise.all([
|
messages.content ->> 'root' IS NULL AND
|
||||||
tfrpc.rpc.query(
|
messages.author != ?4
|
||||||
`
|
GROUP by channel
|
||||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
UNION
|
||||||
JOIN json_each(?1) AS channels ON messages.content ->> 'channel' = channels.value
|
SELECT '' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||||
WHERE
|
WHERE
|
||||||
messages.content ->> 'type' = 'post' AND
|
messages.content ->> 'type' = 'post' AND
|
||||||
messages.content ->> 'root' IS NULL AND
|
messages.content ->> 'root' IS NULL AND
|
||||||
messages.author != ?4
|
messages.author != ?4
|
||||||
GROUP by channel
|
UNION
|
||||||
`,
|
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
|
||||||
k_args
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||||
),
|
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||||
tfrpc.rpc.query(
|
WHERE messages.author != ?4
|
||||||
`
|
`,
|
||||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
[
|
||||||
JOIN messages_refs ON messages.id = messages_refs.message
|
JSON.stringify(this.channels),
|
||||||
JOIN json_each(?1) AS channels ON messages_refs.ref = '#' || channels.value
|
JSON.stringify(following),
|
||||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
'"' + this.whoami.replace('"', '""') + '"',
|
||||||
WHERE
|
this.whoami,
|
||||||
messages.content ->> 'type' = 'post' AND
|
]
|
||||||
messages.content ->> 'root' IS NULL AND
|
);
|
||||||
messages.author != ?4
|
this.channels_latest = Object.fromEntries(
|
||||||
GROUP by channel
|
channels.map((x) => [x.channel, x.rowid])
|
||||||
`,
|
);
|
||||||
k_args
|
|
||||||
),
|
|
||||||
tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT '' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
|
||||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
|
||||||
WHERE
|
|
||||||
messages.content ->> 'type' = 'post' AND
|
|
||||||
messages.content ->> 'root' IS NULL AND
|
|
||||||
messages.author != ?4
|
|
||||||
`,
|
|
||||||
k_args
|
|
||||||
),
|
|
||||||
tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
|
|
||||||
JOIN messages ON messages.rowid = messages_fts.rowid
|
|
||||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
|
||||||
WHERE messages.author != ?4
|
|
||||||
`,
|
|
||||||
k_args
|
|
||||||
),
|
|
||||||
])
|
|
||||||
).flat();
|
|
||||||
let latest = {'🔐': undefined};
|
|
||||||
for (let row of channels) {
|
|
||||||
if (!latest[row.channel]) {
|
|
||||||
latest[row.channel] = row.rowid;
|
|
||||||
} else {
|
|
||||||
latest[row.channel] = Math.max(row.rowid, latest[row.channel]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.channels_latest = latest;
|
|
||||||
console.log('channels took', (new Date() - start_time) / 1000.0);
|
console.log('channels took', (new Date() - start_time) / 1000.0);
|
||||||
let self = this;
|
let self = this;
|
||||||
start_time = new Date();
|
start_time = new Date();
|
||||||
latest_private.then(async function (latest) {
|
latest_private.then(function (latest) {
|
||||||
let grouped = await self.group_private_messages(latest[1]);
|
|
||||||
self.channels_latest = Object.assign({}, self.channels_latest, {
|
self.channels_latest = Object.assign({}, self.channels_latest, {
|
||||||
'🔐': latest[0],
|
'🔐': latest[0],
|
||||||
});
|
});
|
||||||
self.private_messages = latest[1];
|
|
||||||
self.grouped_private_messages = grouped;
|
|
||||||
console.log('private took', (new Date() - start_time) / 1000.0);
|
console.log('private took', (new Date() - start_time) / 1000.0);
|
||||||
|
console.log(latest);
|
||||||
|
self.private_messages = latest[1];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,28 +392,7 @@ class TfElement extends LitElement {
|
|||||||
this.schedule_load_latest();
|
this.schedule_load_latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_progress() {
|
|
||||||
if (this.progress === undefined) {
|
|
||||||
this._progress_start = new Date();
|
|
||||||
requestAnimationFrame(this.update_progress.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_progress() {
|
|
||||||
if (
|
|
||||||
!this.loading_latest &&
|
|
||||||
!this.loading_latest_scheduled &&
|
|
||||||
!this.shadowRoot.getElementById('tf-tab-news')?.is_loading()
|
|
||||||
) {
|
|
||||||
this.progress = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.progress = (new Date() - this._progress_start).valueOf();
|
|
||||||
requestAnimationFrame(this.update_progress.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
schedule_load_latest() {
|
schedule_load_latest() {
|
||||||
this.reset_progress();
|
|
||||||
if (!this.loading_latest) {
|
if (!this.loading_latest) {
|
||||||
this.shadowRoot.getElementById('tf-tab-news')?.load_latest();
|
this.shadowRoot.getElementById('tf-tab-news')?.load_latest();
|
||||||
this.load();
|
this.load();
|
||||||
@@ -562,59 +412,43 @@ class TfElement extends LitElement {
|
|||||||
[JSON.stringify(Object.keys(users))]
|
[JSON.stringify(Object.keys(users))]
|
||||||
);
|
);
|
||||||
for (let row of info) {
|
for (let row of info) {
|
||||||
users[row.author] = Object.assign(users[row.author], {
|
users[row.author].seq = row.max_seq;
|
||||||
seq: row.max_sequence,
|
users[row.author].ts = row.max_ts;
|
||||||
ts: row.max_ts,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
async load_recent_reactions() {
|
|
||||||
this.recent_reactions = (
|
|
||||||
await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT DISTINCT content ->> '$.vote.expression' AS value
|
|
||||||
FROM messages
|
|
||||||
WHERE author = ? AND
|
|
||||||
content ->> '$.type' = 'vote'
|
|
||||||
ORDER BY timestamp DESC LIMIT 10
|
|
||||||
`,
|
|
||||||
[this.whoami]
|
|
||||||
)
|
|
||||||
).map((x) => x.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
this.loading_latest = true;
|
this.loading_latest = true;
|
||||||
this.reset_progress();
|
|
||||||
try {
|
try {
|
||||||
let start_time = new Date();
|
let start_time = new Date();
|
||||||
let whoami = this.whoami;
|
let whoami = this.whoami;
|
||||||
let following = await tfrpc.rpc.following([whoami], 2);
|
let following = await tfrpc.rpc.following([whoami], 2);
|
||||||
let old_users = this.users ?? {};
|
|
||||||
let users = {};
|
let users = {};
|
||||||
let by_count = [];
|
let by_count = [];
|
||||||
for (let [id, v] of Object.entries(following)) {
|
for (let [id, v] of Object.entries(following)) {
|
||||||
users[id] = Object.assign(
|
users[id] = {
|
||||||
{
|
following: v.of,
|
||||||
following: v.of,
|
blocking: v.ob,
|
||||||
blocking: v.ob,
|
followed: v.if,
|
||||||
followed: v.if,
|
blocked: v.ib,
|
||||||
blocked: v.ib,
|
};
|
||||||
follow_depth: following[id]?.d,
|
|
||||||
},
|
|
||||||
old_users[id]
|
|
||||||
);
|
|
||||||
by_count.push({count: v.of, id: id});
|
by_count.push({count: v.of, id: id});
|
||||||
}
|
}
|
||||||
let reactions = this.load_recent_reactions();
|
|
||||||
this.load_channels_latest(Object.keys(following));
|
this.load_channels_latest(Object.keys(following));
|
||||||
this.channels_unread = JSON.parse(
|
this.channels_unread = JSON.parse(
|
||||||
(await tfrpc.rpc.databaseGet('unread')) ?? '{}'
|
(await tfrpc.rpc.databaseGet('unread')) ?? '{}'
|
||||||
);
|
);
|
||||||
this.following = Object.keys(following);
|
this.following = Object.keys(following);
|
||||||
let about_start_time = new Date();
|
let about_start_time = new Date();
|
||||||
|
users = await this.fetch_about(following, users);
|
||||||
|
console.log(
|
||||||
|
'about took',
|
||||||
|
(new Date() - about_start_time) / 1000.0,
|
||||||
|
'seconds for',
|
||||||
|
Object.keys(users).length,
|
||||||
|
'users'
|
||||||
|
);
|
||||||
start_time = new Date();
|
start_time = new Date();
|
||||||
users = await this.fetch_user_info(users);
|
users = await this.fetch_user_info(users);
|
||||||
console.log(
|
console.log(
|
||||||
@@ -623,22 +457,9 @@ class TfElement extends LitElement {
|
|||||||
'seconds'
|
'seconds'
|
||||||
);
|
);
|
||||||
this.users = users;
|
this.users = users;
|
||||||
|
|
||||||
let self = this;
|
|
||||||
this.fetch_about(following, users).then(function (result) {
|
|
||||||
self.users = result;
|
|
||||||
console.log(
|
|
||||||
'about took',
|
|
||||||
(new Date() - about_start_time) / 1000.0,
|
|
||||||
'seconds for',
|
|
||||||
Object.keys(users).length,
|
|
||||||
'users'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
console.log(
|
console.log(
|
||||||
`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
|
`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
|
||||||
);
|
);
|
||||||
await reactions;
|
|
||||||
this.whoami = whoami;
|
this.whoami = whoami;
|
||||||
this.loaded = whoami;
|
this.loaded = whoami;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -689,22 +510,13 @@ class TfElement extends LitElement {
|
|||||||
whoami=${this.whoami}
|
whoami=${this.whoami}
|
||||||
.users=${this.users}
|
.users=${this.users}
|
||||||
hash=${this.hash}
|
hash=${this.hash}
|
||||||
?loading=${this.loading || this.loading_about != 0}
|
?loading=${this.loading}
|
||||||
.channels=${this.channels}
|
.channels=${this.channels}
|
||||||
.channels_latest=${this.channels_latest}
|
.channels_latest=${this.channels_latest}
|
||||||
.channels_unread=${this.channels_unread}
|
.channels_unread=${this.channels_unread}
|
||||||
@channelsetunread=${this.channel_set_unread}
|
@channelsetunread=${this.channel_set_unread}
|
||||||
@refresh=${this.refresh}
|
|
||||||
@toggle_stay_connected=${this.toggle_stay_connected}
|
|
||||||
@loadmessages=${this.reset_progress}
|
|
||||||
@closeprivatechat=${this.close_private_chat}
|
|
||||||
.connections=${this.connections}
|
.connections=${this.connections}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
.visible_private_messages=${this.visible_private()}
|
|
||||||
.grouped_private_messages=${this.grouped_private_messages}
|
|
||||||
.recent_reactions=${this.recent_reactions}
|
|
||||||
?is_administrator=${this.is_administrator}
|
|
||||||
?stay_connected=${this.stay_connected}
|
|
||||||
></tf-tab-news>
|
></tf-tab-news>
|
||||||
`;
|
`;
|
||||||
} else if (this.tab === 'connections') {
|
} else if (this.tab === 'connections') {
|
||||||
@@ -726,16 +538,28 @@ class TfElement extends LitElement {
|
|||||||
: null}
|
: null}
|
||||||
></tf-tab-search>
|
></tf-tab-search>
|
||||||
`;
|
`;
|
||||||
|
} else if (this.tab === 'query') {
|
||||||
|
return html`
|
||||||
|
<tf-tab-query
|
||||||
|
.following=${this.following}
|
||||||
|
whoami=${this.whoami}
|
||||||
|
.users=${this.users}
|
||||||
|
query=${this.hash?.startsWith('#sql=')
|
||||||
|
? decodeURIComponent(this.hash.substring(5))
|
||||||
|
: null}
|
||||||
|
></tf-tab-query>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async set_tab(tab) {
|
async set_tab(tab) {
|
||||||
this.tab = tab;
|
this.tab = tab;
|
||||||
if (tab === 'news') {
|
if (tab === 'news') {
|
||||||
this.schedule_load_latest();
|
|
||||||
await tfrpc.rpc.setHash('#');
|
await tfrpc.rpc.setHash('#');
|
||||||
} else if (tab === 'connections') {
|
} else if (tab === 'connections') {
|
||||||
await tfrpc.rpc.setHash('#connections');
|
await tfrpc.rpc.setHash('#connections');
|
||||||
|
} else if (tab === 'query') {
|
||||||
|
await tfrpc.rpc.setHash('#sql=');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,29 +567,6 @@ class TfElement extends LitElement {
|
|||||||
tfrpc.rpc.sync();
|
tfrpc.rpc.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggle_stay_connected() {
|
|
||||||
let stay_connected = await tfrpc.rpc.globalSettingsGet('stay_connected');
|
|
||||||
let new_stay_connected = !this.stay_connected;
|
|
||||||
try {
|
|
||||||
if (new_stay_connected != stay_connected) {
|
|
||||||
await tfrpc.rpc.globalSettingsSet('stay_connected', new_stay_connected);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.stay_connected = await tfrpc.rpc.globalSettingsGet('stay_connected');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async pick_color() {
|
|
||||||
let input = document.createElement('input');
|
|
||||||
input.type = 'color';
|
|
||||||
input.value = (await tfrpc.rpc.localStorageGet('color')) ?? '#ff0000';
|
|
||||||
input.addEventListener('change', async function () {
|
|
||||||
await tfrpc.rpc.localStorageSet('color', input.value);
|
|
||||||
window.location.reload();
|
|
||||||
});
|
|
||||||
input.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
@@ -780,6 +581,7 @@ class TfElement extends LitElement {
|
|||||||
'📰': 'news',
|
'📰': 'news',
|
||||||
'📡': 'connections',
|
'📡': 'connections',
|
||||||
'🔍': 'search',
|
'🔍': 'search',
|
||||||
|
'👩💻': 'query',
|
||||||
};
|
};
|
||||||
|
|
||||||
let tabs = html`
|
let tabs = html`
|
||||||
@@ -787,25 +589,14 @@ class TfElement extends LitElement {
|
|||||||
class="w3-bar w3-theme-l1"
|
class="w3-bar w3-theme-l1"
|
||||||
style="position: static; top: 0; z-index: 10"
|
style="position: static; top: 0; z-index: 10"
|
||||||
>
|
>
|
||||||
${this.is_administrator
|
<button
|
||||||
? html`
|
class=${'w3-bar-item w3-button w3-circle w3-ripple' +
|
||||||
<button
|
(this.connections?.some((x) => x.flags.one_shot) ? ' w3-spin' : '')}
|
||||||
class=${'w3-bar-item w3-button w3-circle w3-ripple' +
|
style="width: 1.5em; height: 1.5em; padding: 8px"
|
||||||
(this.connections?.some((x) => x.flags.one_shot)
|
@click=${this.refresh}
|
||||||
? ' w3-spin'
|
>
|
||||||
: '')}
|
↻
|
||||||
@click=${this.refresh}
|
</button>
|
||||||
>
|
|
||||||
↻
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="w3-bar-item w3-button w3-ripple"
|
|
||||||
@click=${this.toggle_stay_connected}
|
|
||||||
>
|
|
||||||
${this.stay_connected ? '🔗' : '⛓️💥'}
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: undefined}
|
|
||||||
${Object.entries(k_tabs).map(
|
${Object.entries(k_tabs).map(
|
||||||
([k, v]) => html`
|
([k, v]) => html`
|
||||||
<button
|
<button
|
||||||
@@ -822,12 +613,6 @@ class TfElement extends LitElement {
|
|||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
<button
|
|
||||||
class="w3-bar-item w3-button w3-right"
|
|
||||||
@click=${this.pick_color}
|
|
||||||
>
|
|
||||||
🎨<span class="w3-hide-small">Color</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
let contents = this.guest
|
let contents = this.guest
|
||||||
@@ -851,26 +636,11 @@ class TfElement extends LitElement {
|
|||||||
Loading...
|
Loading...
|
||||||
</div>`
|
</div>`
|
||||||
: this.render_tab();
|
: this.render_tab();
|
||||||
let progress =
|
|
||||||
this.progress !== undefined
|
|
||||||
? html`
|
|
||||||
<div style="position: absolute; width: 100%" id="progress">
|
|
||||||
<div
|
|
||||||
class="w3-theme-l3"
|
|
||||||
style=${`height: 4px; position: absolute; right: ${Math.cos(this.progress / 250) > 0 ? 'auto' : '0'}; width: ${50 * Math.sin(this.progress / 250) + 50}%`}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: undefined;
|
|
||||||
return html`
|
return html`
|
||||||
<style>
|
|
||||||
${generate_theme()}
|
|
||||||
</style>
|
|
||||||
<div
|
<div
|
||||||
style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column"
|
style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column"
|
||||||
class="w3-theme-dark"
|
class="w3-theme-dark"
|
||||||
>
|
>
|
||||||
${progress}
|
|
||||||
<div style="flex: 0 0">${tabs}</div>
|
<div style="flex: 0 0">${tabs}</div>
|
||||||
<div style="flex: 1 1; overflow: auto; contain: layout">
|
<div style="flex: 1 1; overflow: auto; contain: layout">
|
||||||
${contents}
|
${contents}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {LitElement, html, unsafeHTML, live} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML, live} from './lit-all.min.js';
|
||||||
import * as tfutils from './tf-utils.js';
|
import * as tfutils from './tf-utils.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
import Tribute from './tribute.esm.js';
|
import Tribute from './tribute.esm.js';
|
||||||
|
|
||||||
class TfComposeElement extends LitElement {
|
class TfComposeElement extends LitElement {
|
||||||
@@ -16,7 +16,6 @@ class TfComposeElement extends LitElement {
|
|||||||
author: {type: String},
|
author: {type: String},
|
||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
new_thread: {type: Boolean},
|
new_thread: {type: Boolean},
|
||||||
recipients: {type: Array},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,9 +91,7 @@ class TfComposeElement extends LitElement {
|
|||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
detail: {
|
detail: {
|
||||||
id:
|
id: this.branch,
|
||||||
this.branch ??
|
|
||||||
(this.recipients ? this.recipients.join(',') : undefined),
|
|
||||||
draft: draft,
|
draft: draft,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -258,12 +255,10 @@ class TfComposeElement extends LitElement {
|
|||||||
let self = this;
|
let self = this;
|
||||||
let input = document.createElement('input');
|
let input = document.createElement('input');
|
||||||
input.type = 'file';
|
input.type = 'file';
|
||||||
input.addEventListener('change', function (event) {
|
input.onchange = function (event) {
|
||||||
input.parentNode.removeChild(input);
|
|
||||||
let file = event.target.files[0];
|
let file = event.target.files[0];
|
||||||
self.add_file(file);
|
self.add_file(file);
|
||||||
});
|
};
|
||||||
document.body.appendChild(input);
|
|
||||||
input.click();
|
input.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +289,7 @@ class TfComposeElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get_values() {
|
firstUpdated() {
|
||||||
let values = Object.entries(this.users).map((x) => ({
|
let values = Object.entries(this.users).map((x) => ({
|
||||||
key: x[1].name ?? x[0],
|
key: x[1].name ?? x[0],
|
||||||
value: x[0],
|
value: x[0],
|
||||||
@@ -310,15 +305,11 @@ class TfComposeElement extends LitElement {
|
|||||||
values
|
values
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
let tribute = new Tribute({
|
let tribute = new Tribute({
|
||||||
iframe: this.shadowRoot,
|
iframe: this.shadowRoot,
|
||||||
collection: [
|
collection: [
|
||||||
{
|
{
|
||||||
values: this.get_values(),
|
values: values,
|
||||||
selectTemplate: function (item) {
|
selectTemplate: function (item) {
|
||||||
return item
|
return item
|
||||||
? `[@${item.original.key}](${item.original.value})`
|
? `[@${item.original.key}](${item.original.value})`
|
||||||
@@ -337,7 +328,6 @@ class TfComposeElement extends LitElement {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
tribute.attach(this.renderRoot.getElementById('edit'));
|
tribute.attach(this.renderRoot.getElementById('edit'));
|
||||||
this._tribute = tribute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updated() {
|
updated() {
|
||||||
@@ -348,7 +338,6 @@ class TfComposeElement extends LitElement {
|
|||||||
preview.innerHTML = this.process_text(edit.innerText);
|
preview.innerHTML = this.process_text(edit.innerText);
|
||||||
this.last_updated_text = edit.innerText;
|
this.last_updated_text = edit.innerText;
|
||||||
}
|
}
|
||||||
this._tribute.collection[0].values = this.get_values();
|
|
||||||
let encrypt = this.renderRoot.getElementById('encrypt_to');
|
let encrypt = this.renderRoot.getElementById('encrypt_to');
|
||||||
if (encrypt) {
|
if (encrypt) {
|
||||||
let tribute = new Tribute({
|
let tribute = new Tribute({
|
||||||
@@ -368,7 +357,7 @@ class TfComposeElement extends LitElement {
|
|||||||
remove_mention(id) {
|
remove_mention(id) {
|
||||||
let draft = this.get_draft();
|
let draft = this.get_draft();
|
||||||
delete draft.mentions[id];
|
delete draft.mentions[id];
|
||||||
setTimeout(() => this.notify(draft), 0);
|
setTimeout(() => this.notify(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
render_mention(mention) {
|
render_mention(mention) {
|
||||||
@@ -455,15 +444,12 @@ class TfComposeElement extends LitElement {
|
|||||||
self.apps = await tfrpc.rpc.apps();
|
self.apps = await tfrpc.rpc.apps();
|
||||||
}
|
}
|
||||||
if (!this.apps) {
|
if (!this.apps) {
|
||||||
return html`<button
|
return html`<button class="w3-button w3-theme-d1" @click=${attach_app}>
|
||||||
class="w3-button w3-bar-item w3-theme-d1"
|
|
||||||
@click=${attach_app}
|
|
||||||
>
|
|
||||||
Attach App
|
Attach App
|
||||||
</button>`;
|
</button>`;
|
||||||
} else {
|
} else {
|
||||||
return html`<button
|
return html`<button
|
||||||
class="w3-button w3-bar-item w3-theme-d1"
|
class="w3-button w3-theme-d1"
|
||||||
@click=${() => (this.apps = null)}
|
@click=${() => (this.apps = null)}
|
||||||
>
|
>
|
||||||
Discard App
|
Discard App
|
||||||
@@ -484,9 +470,18 @@ class TfComposeElement extends LitElement {
|
|||||||
if (draft.content_warning !== undefined) {
|
if (draft.content_warning !== undefined) {
|
||||||
return html`
|
return html`
|
||||||
<div class="w3-container w3-padding">
|
<div class="w3-container w3-padding">
|
||||||
|
<p>
|
||||||
|
<input type="checkbox" class="w3-check w3-theme-d1" id="cw" @change=${() => self.set_content_warning(undefined)} checked="checked"></input>
|
||||||
|
<label for="cw">CW</label>
|
||||||
|
</p>
|
||||||
<input type="text" class="w3-input w3-border w3-theme-d1" id="content_warning" placeholder="Enter a content warning here." @input=${self.input} value=${draft.content_warning}></input>
|
<input type="text" class="w3-input w3-border w3-theme-d1" id="content_warning" placeholder="Enter a content warning here." @input=${self.input} value=${draft.content_warning}></input>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
} else {
|
||||||
|
return html`
|
||||||
|
<input type="checkbox" class="w3-check w3-theme-d1" id="cw" @change=${() => self.set_content_warning('')}></input>
|
||||||
|
<label for="cw">CW</label>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,17 +500,7 @@ class TfComposeElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_draft() {
|
get_draft() {
|
||||||
let key =
|
return this.drafts[this.branch || ''] || {};
|
||||||
this.branch ||
|
|
||||||
(this.recipients ? this.recipients.join(',') : undefined) ||
|
|
||||||
'';
|
|
||||||
let draft = this.drafts[key] || {};
|
|
||||||
if (this.recipients && !draft.encrypt_to?.length) {
|
|
||||||
draft.encrypt_to = [
|
|
||||||
...new Set(this.recipients).union(new Set(draft.encrypt_to ?? [])),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return draft;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_encrypt(event) {
|
update_encrypt(event) {
|
||||||
@@ -537,7 +522,7 @@ class TfComposeElement extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div style="display: flex; flex-direction: row; width: 100%">
|
<div style="display: flex; flex-direction: row; width: 100%">
|
||||||
<label for="encrypt_to">🔐 To:</label>
|
<label for="encrypt_to">🔐 To:</label>
|
||||||
<input type="text" id="encrypt_to" class="w3-input w3-theme-d1 w3-border" style="display: flex; flex: 1 1" @input=${this.update_encrypt}></input>
|
<input type="text" id="encrypt_to" style="display: flex; flex: 1 1" @input=${this.update_encrypt}></input>
|
||||||
<button class="w3-button w3-theme-d1" @click=${() => this.set_encrypt(undefined)}>🚮</button>
|
<button class="w3-button w3-theme-d1" @click=${() => this.set_encrypt(undefined)}>🚮</button>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -559,31 +544,6 @@ class TfComposeElement extends LitElement {
|
|||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_menu(event) {
|
|
||||||
event.srcElement.parentNode
|
|
||||||
.querySelector('.w3-dropdown-content')
|
|
||||||
.classList.toggle('w3-show');
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
this._click_callback = this.document_click.bind(this);
|
|
||||||
document.body.addEventListener('mouseup', this._click_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
super.disconnectedCallback();
|
|
||||||
document.body.removeEventListener('mouseup', this._click_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
document_click(event) {
|
|
||||||
let content = this.renderRoot.querySelector('.w3-dropdown-content');
|
|
||||||
let target = event.target;
|
|
||||||
if (content && !content.contains(target)) {
|
|
||||||
content.classList.remove('w3-show');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
let draft = self.get_draft();
|
let draft = self.get_draft();
|
||||||
@@ -597,15 +557,12 @@ class TfComposeElement extends LitElement {
|
|||||||
draft.encrypt_to !== undefined
|
draft.encrypt_to !== undefined
|
||||||
? undefined
|
? undefined
|
||||||
: html`<button
|
: html`<button
|
||||||
class="w3-button w3-bar-item w3-theme-d1"
|
class="w3-button w3-theme-d1"
|
||||||
@click=${() => this.set_encrypt([])}
|
@click=${() => this.set_encrypt([])}
|
||||||
>
|
>
|
||||||
🔐 Encrypt
|
🔐
|
||||||
</button>`;
|
</button>`;
|
||||||
let result = html`
|
let result = html`
|
||||||
<style>
|
|
||||||
${generate_theme()}
|
|
||||||
</style>
|
|
||||||
<style>
|
<style>
|
||||||
.w3-input:empty::before {
|
.w3-input:empty::before {
|
||||||
content: attr(placeholder);
|
content: attr(placeholder);
|
||||||
@@ -624,11 +581,11 @@ class TfComposeElement extends LitElement {
|
|||||||
: undefined}
|
: undefined}
|
||||||
${this.render_encrypt()}
|
${this.render_encrypt()}
|
||||||
</header>
|
</header>
|
||||||
<div class="w3-container" style="padding: 0 0 16px 0">
|
<div class="w3-container w3-padding-small">
|
||||||
<div class="w3-half">
|
<div class="w3-half">
|
||||||
<span
|
<span
|
||||||
class="w3-input w3-theme-d1 w3-border"
|
class="w3-input w3-theme-d1 w3-border"
|
||||||
style="resize: vertical; width: 100%; white-space: pre-wrap"
|
style="resize: vertical; width: 100%; overflow: hidden; white-space: pre-wrap"
|
||||||
placeholder="Write a post here."
|
placeholder="Write a post here."
|
||||||
id="edit"
|
id="edit"
|
||||||
@input=${this.input}
|
@input=${this.input}
|
||||||
@@ -645,7 +602,7 @@ class TfComposeElement extends LitElement {
|
|||||||
${Object.values(draft.mentions || {}).map((x) =>
|
${Object.values(draft.mentions || {}).map((x) =>
|
||||||
self.render_mention(x)
|
self.render_mention(x)
|
||||||
)}
|
)}
|
||||||
<footer>
|
<footer class="w3-container">
|
||||||
${this.render_attach_app()} ${this.render_content_warning()}
|
${this.render_attach_app()} ${this.render_content_warning()}
|
||||||
${this.render_new_thread()}
|
${this.render_new_thread()}
|
||||||
<button
|
<button
|
||||||
@@ -655,43 +612,13 @@ class TfComposeElement extends LitElement {
|
|||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
<div class="w3-dropdown-click">
|
<button class="w3-button w3-theme-d1" @click=${this.attach}>
|
||||||
<button class="w3-button w3-theme-d1" @click=${this.toggle_menu}>
|
Attach
|
||||||
⚙️
|
</button>
|
||||||
</button>
|
${this.render_attach_app_button()} ${encrypt}
|
||||||
<div class="w3-dropdown-content w3-bar-block">
|
<button class="w3-button w3-theme-d1" @click=${this.discard}>
|
||||||
${this.get_draft().content_warning === undefined
|
Discard
|
||||||
? html`
|
</button>
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-theme-d1"
|
|
||||||
@click=${() => self.set_content_warning('')}
|
|
||||||
>
|
|
||||||
Add Content Warning
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-theme-d1"
|
|
||||||
@click=${() => self.set_content_warning(undefined)}
|
|
||||||
>
|
|
||||||
Remove Content Warning
|
|
||||||
</button>
|
|
||||||
`}
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-theme-d1"
|
|
||||||
@click=${this.attach}
|
|
||||||
>
|
|
||||||
Attach
|
|
||||||
</button>
|
|
||||||
${this.render_attach_app_button()} ${encrypt}
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-theme-d1"
|
|
||||||
@click=${this.discard}
|
|
||||||
>
|
|
||||||
Discard
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
import {
|
import {LitElement, html, repeat, render, unsafeHTML} from './lit-all.min.js';
|
||||||
LitElement,
|
|
||||||
css,
|
|
||||||
html,
|
|
||||||
repeat,
|
|
||||||
render,
|
|
||||||
unsafeCSS,
|
|
||||||
unsafeHTML,
|
|
||||||
until,
|
|
||||||
} from './lit-all.min.js';
|
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import * as tfutils from './tf-utils.js';
|
import * as tfutils from './tf-utils.js';
|
||||||
import * as emojis from './emojis.js';
|
import * as emojis from './emojis.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfMessageElement extends LitElement {
|
class TfMessageElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -25,8 +16,6 @@ class TfMessageElement extends LitElement {
|
|||||||
expanded: {type: Object},
|
expanded: {type: Object},
|
||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
channel_unread: {type: Number},
|
channel_unread: {type: Number},
|
||||||
recent_reactions: {type: Array},
|
|
||||||
depth: {type: Number},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,40 +31,6 @@ class TfMessageElement extends LitElement {
|
|||||||
this.format = 'message';
|
this.format = 'message';
|
||||||
this.expanded = {};
|
this.expanded = {};
|
||||||
this.channel_unread = -1;
|
this.channel_unread = -1;
|
||||||
this.recent_reactions = [];
|
|
||||||
this.depth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
this._click_callback = this.document_click.bind(this);
|
|
||||||
this._blob_stored = this.blob_stored.bind(this);
|
|
||||||
document.body.addEventListener('mouseup', this._click_callback);
|
|
||||||
window.addEventListener('blob-stored', this._blob_stored);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
super.disconnectedCallback();
|
|
||||||
window.removeEventListener('blob-stored', this._blob_stored);
|
|
||||||
document.body.removeEventListener('mouseup', this._click_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
document_click(event) {
|
|
||||||
let content = this.renderRoot.querySelector('.w3-dropdown-content');
|
|
||||||
let target = event.target;
|
|
||||||
if (content && !content.contains(target)) {
|
|
||||||
content.classList.remove('w3-show');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blob_stored(event) {
|
|
||||||
let search = `/${event.detail.id}/view`;
|
|
||||||
for (let img of this.shadowRoot.querySelectorAll('img')) {
|
|
||||||
if (img.src.indexOf(search) != -1) {
|
|
||||||
let src = img.src.split('?')[0];
|
|
||||||
img.src = `${src}?${new Date().valueOf()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
show_reply() {
|
show_reply() {
|
||||||
@@ -110,27 +65,20 @@ class TfMessageElement extends LitElement {
|
|||||||
|
|
||||||
render_votes() {
|
render_votes() {
|
||||||
function normalize_expression(expression) {
|
function normalize_expression(expression) {
|
||||||
if (
|
if (expression === 'Like' || !expression) {
|
||||||
expression === 'Unlike' ||
|
return '👍';
|
||||||
expression === 'unlike' ||
|
} else if (expression === 'Unlike') {
|
||||||
expression == 'undig'
|
|
||||||
) {
|
|
||||||
return '👎';
|
return '👎';
|
||||||
} else if (expression === 'heart') {
|
} else if (expression === 'heart') {
|
||||||
return '❤️';
|
return '❤️';
|
||||||
} else if (
|
|
||||||
(expression ?? '').split('').every((x) => x.charCodeAt(0) < 256)
|
|
||||||
) {
|
|
||||||
return '👍';
|
|
||||||
} else {
|
} else {
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.message?.votes?.length) {
|
if (this.message?.votes?.length) {
|
||||||
return html` <footer class="w3-container">
|
return html` <div class="w3-container">
|
||||||
<div
|
<div
|
||||||
class="w3-button w3-bar"
|
class="w3-button w3-bar w3-padding-small"
|
||||||
style="padding: 0"
|
|
||||||
@click=${this.show_reactions}
|
@click=${this.show_reactions}
|
||||||
>
|
>
|
||||||
${(this.message.votes || []).map(
|
${(this.message.votes || []).map(
|
||||||
@@ -145,7 +93,7 @@ class TfMessageElement extends LitElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</footer>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,12 +136,7 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
react(event) {
|
react(event) {
|
||||||
emojis.picker(
|
emojis.picker((x) => this.vote(x), null, this.whoami);
|
||||||
(x) => this.vote(x),
|
|
||||||
null,
|
|
||||||
this.whoami,
|
|
||||||
this.recent_reactions
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
show_image(link) {
|
show_image(link) {
|
||||||
@@ -208,12 +151,12 @@ class TfMessageElement extends LitElement {
|
|||||||
div.style.display = 'grid';
|
div.style.display = 'grid';
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
img.src = link;
|
img.src = link;
|
||||||
img.style.maxWidth = '100vw';
|
img.style.maxWidth = '100%';
|
||||||
img.style.maxHeight = '100vh';
|
img.style.maxHeight = '100%';
|
||||||
img.style.display = 'block';
|
img.style.display = 'block';
|
||||||
img.style.margin = 'auto';
|
img.style.margin = 'auto';
|
||||||
img.style.objectFit = 'contain';
|
img.style.objectFit = 'contain';
|
||||||
img.style.width = '100vw';
|
img.style.width = '100%';
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
function image_close(event) {
|
function image_close(event) {
|
||||||
document.body.removeChild(div);
|
document.body.removeChild(div);
|
||||||
@@ -327,76 +270,53 @@ class TfMessageElement extends LitElement {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
expanded_key() {
|
|
||||||
return (
|
|
||||||
this.message?.id || this.message?.messages?.map((x) => x.id).join(':')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_expanded(expanded, tag) {
|
set_expanded(expanded, tag) {
|
||||||
let key = this.expanded_key();
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('tf-expand', {
|
new CustomEvent('tf-expand', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
detail: {id: key + (tag || ''), expanded: expanded},
|
detail: {id: (this.message.id || '') + (tag || ''), expanded: expanded},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_expanded(tag) {
|
toggle_expanded(tag) {
|
||||||
let key = this.expanded_key();
|
this.set_expanded(
|
||||||
this.set_expanded(!this.expanded[key + (tag || '')], tag);
|
!this.expanded[(this.message.id || '') + (tag || '')],
|
||||||
}
|
tag
|
||||||
|
);
|
||||||
is_expanded(tag) {
|
|
||||||
let key = this.expanded_key();
|
|
||||||
return this.expanded[key + (tag || '')];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render_children() {
|
render_children() {
|
||||||
let self = this;
|
let self = this;
|
||||||
if (this.message.child_messages?.length) {
|
if (this.message.child_messages?.length) {
|
||||||
if (!this.expanded[this.expanded_key()]) {
|
if (!this.expanded[this.message.id]) {
|
||||||
return html`
|
return html`<button
|
||||||
<button
|
class="w3-button w3-theme-d1"
|
||||||
class="w3-button w3-theme-d1 w3-block w3-bar"
|
@click=${() => self.set_expanded(true)}
|
||||||
style="box-sizing: border-box"
|
>
|
||||||
@click=${() => self.set_expanded(true)}
|
+ ${this.total_child_messages(this.message) + ' More'}
|
||||||
>
|
</button>`;
|
||||||
+ ${this.total_child_messages(this.message) + ' More'}
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
} else {
|
} else {
|
||||||
return html` <ul class="w3-container w3-margin-bottom w3-ul w3-card-4">
|
return html`<button
|
||||||
${repeat(
|
class="w3-button w3-theme-d1"
|
||||||
|
@click=${() => self.set_expanded(false)}
|
||||||
|
>
|
||||||
|
Collapse</button
|
||||||
|
>${repeat(
|
||||||
this.message.child_messages || [],
|
this.message.child_messages || [],
|
||||||
(x) => x.id,
|
(x) => x.id,
|
||||||
(x) =>
|
(x) =>
|
||||||
html`<li style="padding: 0">
|
html`<tf-message
|
||||||
<tf-message
|
.message=${x}
|
||||||
.message=${x}
|
whoami=${this.whoami}
|
||||||
whoami=${this.whoami}
|
.users=${this.users}
|
||||||
.users=${this.users}
|
.drafts=${this.drafts}
|
||||||
.drafts=${this.drafts}
|
.expanded=${this.expanded}
|
||||||
.expanded=${this.expanded}
|
channel=${this.channel}
|
||||||
channel=${this.channel}
|
channel_unread=${this.channel_unread}
|
||||||
channel_unread=${this.channel_unread}
|
></tf-message>`
|
||||||
.recent_reactions=${this.recent_reactions}
|
)}`;
|
||||||
depth=${this.depth + 1}
|
|
||||||
></tf-message>
|
|
||||||
</li>`
|
|
||||||
)}
|
|
||||||
<li style="padding: 0" class="w3-margin-bottom">
|
|
||||||
<button
|
|
||||||
class="w3-button w3-theme-d1 w3-block w3-bar"
|
|
||||||
style="box-sizing: border-box"
|
|
||||||
@click=${() => self.set_expanded(false)}
|
|
||||||
>
|
|
||||||
Collapse
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>`;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -438,7 +358,7 @@ class TfMessageElement extends LitElement {
|
|||||||
class_background() {
|
class_background() {
|
||||||
return this.message?.decrypted
|
return this.message?.decrypted
|
||||||
? 'w3-pale-red'
|
? 'w3-pale-red'
|
||||||
: this.allow_unread() && this.message?.rowid >= this.channel_unread
|
: this.message?.rowid >= this.channel_unread
|
||||||
? 'w3-theme-d2'
|
? 'w3-theme-d2'
|
||||||
: 'w3-theme-d4';
|
: 'w3-theme-d4';
|
||||||
}
|
}
|
||||||
@@ -451,74 +371,62 @@ class TfMessageElement extends LitElement {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_id(event) {
|
render_raw_button() {
|
||||||
navigator.clipboard.writeText(this.message?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle_menu(event) {
|
|
||||||
event.srcElement.parentNode
|
|
||||||
.querySelector('.w3-dropdown-content')
|
|
||||||
.classList.toggle('w3-show');
|
|
||||||
}
|
|
||||||
|
|
||||||
render_menu() {
|
|
||||||
let content = this.get_content();
|
let content = this.get_content();
|
||||||
let formats = [['message', 'Message']];
|
let raw_button;
|
||||||
if (content?.type == 'post' || content?.type == 'blog') {
|
switch (this.format) {
|
||||||
formats.push(['md', 'Markdown']);
|
case 'raw':
|
||||||
}
|
if (content?.type == 'post' || content?.type == 'blog') {
|
||||||
if (this.message?.decrypted) {
|
raw_button = html`<button
|
||||||
formats.push(['decrypted', 'Decrypted']);
|
class="w3-button w3-theme-d1"
|
||||||
}
|
@click=${() => (this.format = 'md')}
|
||||||
formats.push(['raw', 'Raw']);
|
>
|
||||||
return html`
|
Markdown
|
||||||
<div class="w3-bar-item w3-right">
|
</button>`;
|
||||||
<button class="w3-button w3-theme-d1" @click=${this.toggle_menu}>
|
} else {
|
||||||
%
|
raw_button = html`<button
|
||||||
</button>
|
class="w3-button w3-theme-d1"
|
||||||
<div
|
@click=${() => (this.format = 'message')}
|
||||||
class="w3-dropdown-content w3-bar-block w3-card-4 w3-theme-l1"
|
>
|
||||||
style="right: 48px"
|
Message
|
||||||
|
</button>`;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'md':
|
||||||
|
raw_button = html`<button
|
||||||
|
class="w3-button w3-theme-d1"
|
||||||
|
@click=${() => (this.format = 'message')}
|
||||||
>
|
>
|
||||||
<a
|
Message
|
||||||
target="_top"
|
</button>`;
|
||||||
class="w3-button w3-bar-item"
|
break;
|
||||||
href=${'#' + encodeURIComponent(this.message?.id)}
|
case 'decrypted':
|
||||||
>View Message</a
|
raw_button = html`<button
|
||||||
|
class="w3-button w3-theme-d1"
|
||||||
|
@click=${() => (this.format = 'raw')}
|
||||||
|
>
|
||||||
|
Raw
|
||||||
|
</button>`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (this.message.decrypted) {
|
||||||
|
raw_button = html`<button
|
||||||
|
class="w3-button w3-theme-d1"
|
||||||
|
@click=${() => (this.format = 'decrypted')}
|
||||||
>
|
>
|
||||||
<button
|
Decrypted
|
||||||
class="w3-button w3-bar-item w3-border-bottom"
|
</button>`;
|
||||||
@click=${this.copy_id}
|
} else {
|
||||||
|
raw_button = html`<button
|
||||||
|
class="w3-button w3-theme-d1"
|
||||||
|
@click=${() => (this.format = 'raw')}
|
||||||
>
|
>
|
||||||
Copy ID
|
Raw
|
||||||
</button>
|
</button>`;
|
||||||
${this.drafts[this.message?.id] === undefined
|
}
|
||||||
? html`
|
break;
|
||||||
<button class="w3-button w3-bar-item" @click=${this.show_reply}>
|
}
|
||||||
↩️ Reply
|
return raw_button;
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: undefined}
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-border-bottom"
|
|
||||||
@click=${this.react}
|
|
||||||
>
|
|
||||||
👍 React
|
|
||||||
</button>
|
|
||||||
${formats.map(
|
|
||||||
([format, name]) => html`
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item"
|
|
||||||
style=${format == this.format ? 'font-weight: bold' : ''}
|
|
||||||
@click=${() => (this.format = format)}
|
|
||||||
>
|
|
||||||
${name}
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render_header() {
|
render_header() {
|
||||||
@@ -530,15 +438,16 @@ class TfMessageElement extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<header class="w3-bar">
|
<header class="w3-bar">
|
||||||
<span class="w3-bar-item">
|
<span class="w3-bar-item">
|
||||||
${this.render_unread_icon()}<tf-user
|
<tf-user id=${this.message.author} .users=${this.users}></tf-user>
|
||||||
id=${this.message.author}
|
|
||||||
.users=${this.users}
|
|
||||||
></tf-user>
|
|
||||||
</span>
|
</span>
|
||||||
${is_encrypted} ${this.render_menu()}
|
${is_encrypted}
|
||||||
<div class="w3-bar-item w3-right" style="text-wrap: nowrap">
|
<span class="w3-bar-item w3-right">${this.render_raw_button()}</span>
|
||||||
${new Date(this.message.timestamp).toLocaleString()}
|
<span class="w3-bar-item w3-right" style="text-wrap: nowrap"
|
||||||
</div>
|
><a target="_top" href=${'#' + encodeURIComponent(this.message.id)}
|
||||||
|
>%</a
|
||||||
|
>
|
||||||
|
${new Date(this.message.timestamp).toLocaleString()}</span
|
||||||
|
>
|
||||||
</header>
|
</header>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -560,11 +469,8 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div
|
<div
|
||||||
class="w3-card-4 ${this.class_background()} w3-border-theme ${this
|
class="w3-card-4 ${this.class_background()} w3-border-theme w3-margin-top"
|
||||||
.depth == 0
|
style="overflow: auto; overflow-wrap: anywhere; display: block; max-width: 100%"
|
||||||
? 'w3-margin-top'
|
|
||||||
: ''}"
|
|
||||||
style="overflow-wrap: anywhere; display: block; max-width: 100%"
|
|
||||||
>
|
>
|
||||||
${inner}
|
${inner}
|
||||||
</div>
|
</div>
|
||||||
@@ -589,8 +495,6 @@ class TfMessageElement extends LitElement {
|
|||||||
.expanded=${self.expanded}
|
.expanded=${self.expanded}
|
||||||
channel=${self.channel}
|
channel=${self.channel}
|
||||||
channel_unread=${self.channel_unread}
|
channel_unread=${self.channel_unread}
|
||||||
.recent_reactions=${self.recent_reactions}
|
|
||||||
depth=${self.depth + 1}
|
|
||||||
></tf-message>
|
></tf-message>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@@ -602,108 +506,33 @@ class TfMessageElement extends LitElement {
|
|||||||
let reply =
|
let reply =
|
||||||
this.drafts[this.message?.id] !== undefined
|
this.drafts[this.message?.id] !== undefined
|
||||||
? html`
|
? html`
|
||||||
<div class="w3-section w3-container">
|
<tf-compose
|
||||||
<tf-compose
|
whoami=${this.whoami}
|
||||||
whoami=${this.whoami}
|
.users=${this.users}
|
||||||
.users=${this.users}
|
root=${content.root || this.message.id}
|
||||||
root=${content.root || this.message.id}
|
branch=${this.message.id}
|
||||||
branch=${this.message.id}
|
.drafts=${this.drafts}
|
||||||
.drafts=${this.drafts}
|
@tf-discard=${this.discard_reply}
|
||||||
@tf-discard=${this.discard_reply}
|
author=${this.message.author}
|
||||||
author=${this.message.author}
|
></tf-compose>
|
||||||
.recent_reactions=${this.recent_reactions}
|
|
||||||
></tf-compose>
|
|
||||||
</div>
|
|
||||||
`
|
`
|
||||||
: undefined;
|
: html`
|
||||||
|
<button class="w3-button w3-theme-d1" @click=${this.show_reply}>
|
||||||
|
Reply
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
return html`
|
return html`
|
||||||
${reply}
|
<div class="w3-section w3-container">
|
||||||
<footer>${this.render_children()}</footer>
|
${reply}
|
||||||
|
<button class="w3-button w3-theme-d1" @click=${this.react}>
|
||||||
|
React
|
||||||
|
</button>
|
||||||
|
${this.render_children()}
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
content_group_by_author() {
|
render() {
|
||||||
let sorted = this.message.messages
|
|
||||||
.map((x) => [
|
|
||||||
x.author,
|
|
||||||
x.content.following && x.content.blocking
|
|
||||||
? 'is following and blocking'
|
|
||||||
: x.content.following
|
|
||||||
? 'is following'
|
|
||||||
: x.content.blocking
|
|
||||||
? 'is blocking'
|
|
||||||
: x.content.blocking !== undefined
|
|
||||||
? 'is no longer blocking'
|
|
||||||
: x.content.following !== undefined
|
|
||||||
? 'is no longer following'
|
|
||||||
: '',
|
|
||||||
x.content.contact,
|
|
||||||
x,
|
|
||||||
])
|
|
||||||
.sort();
|
|
||||||
let result = [];
|
|
||||||
let last;
|
|
||||||
let group;
|
|
||||||
for (let row of sorted) {
|
|
||||||
if (last && last[0] == row[0] && last[1] == row[1]) {
|
|
||||||
group.push(row[2]);
|
|
||||||
} else {
|
|
||||||
if (group) {
|
|
||||||
result.push({author: last[0], action: last[1], users: group});
|
|
||||||
}
|
|
||||||
last = row;
|
|
||||||
group = [row[2]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (group) {
|
|
||||||
result.push({author: last[0], action: last[1], users: group});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
channel_group_by_author() {
|
|
||||||
let sorted = this.message.messages
|
|
||||||
.map((x) => [
|
|
||||||
x.author,
|
|
||||||
x.content.subscribed ? 'subscribed to' : 'unsubscribed from',
|
|
||||||
x.content.channel,
|
|
||||||
x,
|
|
||||||
])
|
|
||||||
.sort();
|
|
||||||
let result = [];
|
|
||||||
let last;
|
|
||||||
let group;
|
|
||||||
for (let row of sorted) {
|
|
||||||
if (last && last[0] == row[0] && last[1] == row[1]) {
|
|
||||||
group.push(row[2]);
|
|
||||||
} else {
|
|
||||||
if (group) {
|
|
||||||
result.push({author: last[0], action: last[1], channels: group});
|
|
||||||
}
|
|
||||||
last = row;
|
|
||||||
group = [row[2]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (group) {
|
|
||||||
result.push({author: last[0], action: last[1], channels: group});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
allow_unread() {
|
|
||||||
return (
|
|
||||||
this.channel == '@' ||
|
|
||||||
(!this.channel.startsWith('@') && !this.channel.startsWith('%'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render_unread_icon() {
|
|
||||||
return this.allow_unread() && this.message?.rowid >= this.channel_unread
|
|
||||||
? html`✉️`
|
|
||||||
: undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
_render() {
|
|
||||||
let content = this.message?.content;
|
let content = this.message?.content;
|
||||||
if (this.message?.decrypted?.type == 'post') {
|
if (this.message?.decrypted?.type == 'post') {
|
||||||
content = this.message.decrypted;
|
content = this.message.decrypted;
|
||||||
@@ -711,145 +540,29 @@ class TfMessageElement extends LitElement {
|
|||||||
let class_background = this.class_background();
|
let class_background = this.class_background();
|
||||||
let self = this;
|
let self = this;
|
||||||
if (this.message?.type === 'contact_group') {
|
if (this.message?.type === 'contact_group') {
|
||||||
if (this.expanded[this.expanded_key()]) {
|
return this.render_frame(
|
||||||
return this.render_frame(html`
|
html` ${this.message.messages.map(
|
||||||
<div class="w3-padding">
|
(x) =>
|
||||||
${this.message.messages.map(
|
html`<tf-message
|
||||||
(x) =>
|
.message=${x}
|
||||||
html`<tf-message
|
whoami=${this.whoami}
|
||||||
.message=${x}
|
.users=${this.users}
|
||||||
whoami=${this.whoami}
|
.drafts=${this.drafts}
|
||||||
.users=${this.users}
|
.expanded=${this.expanded}
|
||||||
.drafts=${this.drafts}
|
channel=${this.channel}
|
||||||
.expanded=${this.expanded}
|
channel_unread=${this.channel_unread}
|
||||||
channel=${this.channel}
|
></tf-message>`
|
||||||
channel_unread=${this.channel_unread}
|
)}`
|
||||||
depth=${this.depth + 1}
|
);
|
||||||
></tf-message>`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-theme-d1 w3-block w3-bar"
|
|
||||||
style="box-sizing: border-box"
|
|
||||||
@click=${() => self.set_expanded(false)}
|
|
||||||
>
|
|
||||||
Collapse
|
|
||||||
</button>
|
|
||||||
`);
|
|
||||||
} else {
|
|
||||||
return this.render_frame(html`
|
|
||||||
<div class="w3-padding">
|
|
||||||
${this.content_group_by_author().map(
|
|
||||||
(x) => html`
|
|
||||||
<div>
|
|
||||||
<tf-user id=${x.author} .users=${this.users}></tf-user>
|
|
||||||
${x.action}
|
|
||||||
${x.users.map(
|
|
||||||
(y) => html`
|
|
||||||
<tf-user
|
|
||||||
id=${y}
|
|
||||||
.users=${this.users}
|
|
||||||
icon_only="true"
|
|
||||||
></tf-user>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-theme-d1 w3-block w3-bar"
|
|
||||||
style="box-sizing: border-box"
|
|
||||||
@click=${() => self.set_expanded(true)}
|
|
||||||
>
|
|
||||||
Expand
|
|
||||||
</button>
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
} else if (this.message?.type === 'channel_group') {
|
|
||||||
if (this.expanded[this.expanded_key()]) {
|
|
||||||
return this.render_frame(html`
|
|
||||||
<div class="w3-padding">
|
|
||||||
${this.message.messages.map(
|
|
||||||
(x) =>
|
|
||||||
html`<tf-message
|
|
||||||
.message=${x}
|
|
||||||
whoami=${this.whoami}
|
|
||||||
.users=${this.users}
|
|
||||||
.drafts=${this.drafts}
|
|
||||||
.expanded=${this.expanded}
|
|
||||||
channel=${this.channel}
|
|
||||||
channel_unread=${this.channel_unread}
|
|
||||||
depth=${this.depth + 1}
|
|
||||||
></tf-message>`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-theme-d1 w3-block w3-bar"
|
|
||||||
style="box-sizing: border-box"
|
|
||||||
@click=${() => self.set_expanded(false)}
|
|
||||||
>
|
|
||||||
Collapse
|
|
||||||
</button>
|
|
||||||
`);
|
|
||||||
} else {
|
|
||||||
return this.render_frame(html`
|
|
||||||
<div class="w3-padding">
|
|
||||||
${this.channel_group_by_author().map(
|
|
||||||
(x) => html`
|
|
||||||
<div>
|
|
||||||
<tf-user id=${x.author} .users=${this.users}></tf-user>
|
|
||||||
${x.action}
|
|
||||||
${x.channels.map(
|
|
||||||
(y) => html` <tf-tag tag=${'#' + y}></tf-tag> `
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-theme-d1 w3-block w3-bar"
|
|
||||||
style="box-sizing: border-box"
|
|
||||||
@click=${() => self.set_expanded(true)}
|
|
||||||
>
|
|
||||||
Expand
|
|
||||||
</button>
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
} else if (this.message.placeholder) {
|
} else if (this.message.placeholder) {
|
||||||
return this.render_frame(
|
return this.render_frame(
|
||||||
html`<div>
|
html`<div class="w3-padding">
|
||||||
<div class="w3-bar">
|
<p>
|
||||||
<a
|
<a target="_top" href=${'#' + encodeURIComponent(this.message.id)}
|
||||||
class="w3-bar-item w3-panel w3-round-xlarge w3-theme-d1 w3-margin w3-button"
|
>${this.message.id}</a
|
||||||
target="_top"
|
|
||||||
href=${'#' + encodeURIComponent(this.message?.id)}
|
|
||||||
>
|
>
|
||||||
This message is not currently available.
|
(placeholder)
|
||||||
</a>
|
</p>
|
||||||
<div class="w3-bar-item w3-right">
|
|
||||||
<button class="w3-button w3-theme-d1" @click=${this.toggle_menu}>
|
|
||||||
%
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
class="w3-dropdown-content w3-bar-block w3-card-4 w3-theme-l1"
|
|
||||||
style="right: 48px"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
target="_top"
|
|
||||||
class="w3-button w3-bar-item"
|
|
||||||
href=${'#' + encodeURIComponent(this.message?.id)}
|
|
||||||
>View Message</a
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-border-bottom"
|
|
||||||
@click=${this.copy_id}
|
|
||||||
>
|
|
||||||
Copy ID
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>${this.render_votes()}</div>
|
<div>${this.render_votes()}</div>
|
||||||
${(this.message.child_messages || []).map(
|
${(this.message.child_messages || []).map(
|
||||||
(x) => html`
|
(x) => html`
|
||||||
@@ -861,7 +574,6 @@ class TfMessageElement extends LitElement {
|
|||||||
.expanded=${this.expanded}
|
.expanded=${this.expanded}
|
||||||
channel=${this.channel}
|
channel=${this.channel}
|
||||||
channel_unread=${this.channel_unread}
|
channel_unread=${this.channel_unread}
|
||||||
depth=${this.depth + 1}
|
|
||||||
></tf-message>
|
></tf-message>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@@ -877,7 +589,7 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
if (content.image !== undefined) {
|
if (content.image !== undefined) {
|
||||||
image = html`
|
image = html`
|
||||||
<div @click=${this.body_click}><img src=${'/' + (typeof content.image?.link == 'string' ? content.image.link : content.image) + '/view'} style="width: 256px; height: auto"></img></div>
|
<div><img src=${'/' + (typeof content.image?.link == 'string' ? content.image.link : content.image) + '/view'} style="width: 256px; height: auto"></img></div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
if (content.description !== undefined) {
|
if (content.description !== undefined) {
|
||||||
@@ -900,45 +612,25 @@ class TfMessageElement extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
} else if (content.type == 'contact') {
|
} else if (content.type == 'contact') {
|
||||||
switch (this.format) {
|
return html`
|
||||||
case 'message':
|
<div class="w3-padding">
|
||||||
default:
|
<tf-user id=${this.message.author} .users=${this.users}></tf-user>
|
||||||
return this.render_frame(html`
|
is
|
||||||
<div class="w3-bar">
|
${content.blocking === true
|
||||||
<div class="w3-bar-item">
|
? 'blocking'
|
||||||
<tf-user
|
: content.blocking === false
|
||||||
id=${this.message.author}
|
? 'no longer blocking'
|
||||||
.users=${this.users}
|
: content.following === true
|
||||||
></tf-user>
|
? 'following'
|
||||||
is
|
: content.following === false
|
||||||
${content.blocking === true
|
? 'no longer following'
|
||||||
? 'blocking'
|
: '?'}
|
||||||
: content.blocking === false
|
<tf-user
|
||||||
? 'no longer blocking'
|
id=${this.message.content.contact}
|
||||||
: content.following === true
|
.users=${this.users}
|
||||||
? 'following'
|
></tf-user>
|
||||||
: content.following === false
|
</div>
|
||||||
? 'no longer following'
|
`;
|
||||||
: '?'}
|
|
||||||
<tf-user
|
|
||||||
id=${this.message.content.contact}
|
|
||||||
.users=${this.users}
|
|
||||||
></tf-user>
|
|
||||||
</div>
|
|
||||||
${this.render_menu()} ${this.render_votes()}
|
|
||||||
${this.render_actions()}
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
break;
|
|
||||||
case 'raw':
|
|
||||||
return this.render_frame(html`
|
|
||||||
${this.render_header()}
|
|
||||||
<div class="w3-container">${this.render_raw()}</div>
|
|
||||||
${this.render_votes()} ${this.render_actions()}
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (content.type == 'post') {
|
} else if (content.type == 'post') {
|
||||||
let self = this;
|
let self = this;
|
||||||
let body;
|
let body;
|
||||||
@@ -961,14 +653,11 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
let content_warning = html`
|
let content_warning = html`
|
||||||
<div
|
<div
|
||||||
class="w3-panel w3-round-xlarge w3-theme-l4 w3"
|
class="w3-panel w3-round-xlarge w3-theme-l4"
|
||||||
style="cursor: pointer"
|
style="cursor: pointer"
|
||||||
@click=${(x) => this.toggle_expanded(':cw')}
|
@click=${(x) => this.toggle_expanded(':cw')}
|
||||||
>
|
>
|
||||||
<p>${content.contentWarning}</p>
|
<p>${content.contentWarning}</p>
|
||||||
<p class="w3-small">
|
|
||||||
${this.is_expanded(':cw') ? 'Show less' : 'Show more'}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
let content_html = html`
|
let content_html = html`
|
||||||
@@ -1097,15 +786,6 @@ class TfMessageElement extends LitElement {
|
|||||||
return this.render_small_frame(this.render_raw());
|
return this.render_small_frame(this.render_raw());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
${generate_theme()}
|
|
||||||
</style>
|
|
||||||
${this._render()}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('tf-message', TfMessageElement);
|
customElements.define('tf-message', TfMessageElement);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfNewsElement extends LitElement {
|
class TfNewsElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -13,8 +13,6 @@ class TfNewsElement extends LitElement {
|
|||||||
expanded: {type: Object},
|
expanded: {type: Object},
|
||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
channel_unread: {type: Number},
|
channel_unread: {type: Number},
|
||||||
recent_reactions: {type: Array},
|
|
||||||
hash: {type: String},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +28,6 @@ class TfNewsElement extends LitElement {
|
|||||||
this.drafts = {};
|
this.drafts = {};
|
||||||
this.expanded = {};
|
this.expanded = {};
|
||||||
this.channel_unread = -1;
|
this.channel_unread = -1;
|
||||||
this.recent_reactions = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process_messages(messages) {
|
process_messages(messages) {
|
||||||
@@ -160,80 +157,46 @@ class TfNewsElement extends LitElement {
|
|||||||
return recursive_sort(roots, true);
|
return recursive_sort(roots, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
group_messages(messages) {
|
group_following(messages) {
|
||||||
let result = [];
|
let result = [];
|
||||||
let group = [];
|
let group = [];
|
||||||
let type = undefined;
|
|
||||||
for (let message of messages) {
|
for (let message of messages) {
|
||||||
if (
|
if (message?.content?.type === 'contact') {
|
||||||
message?.content?.type === 'contact' ||
|
|
||||||
message?.content?.type === 'channel'
|
|
||||||
) {
|
|
||||||
if (type && message.content.type !== type) {
|
|
||||||
if (group.length == 1) {
|
|
||||||
result.push(group[0]);
|
|
||||||
group = [];
|
|
||||||
} else if (group.length > 1) {
|
|
||||||
result.push({
|
|
||||||
rowid: Math.max(...group.map((x) => x.rowid)),
|
|
||||||
type: `${type}_group`,
|
|
||||||
messages: group,
|
|
||||||
});
|
|
||||||
group = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type = message.content.type;
|
|
||||||
group.push(message);
|
group.push(message);
|
||||||
} else {
|
} else {
|
||||||
if (group.length == 1) {
|
if (group.length > 0) {
|
||||||
result.push(group[0]);
|
|
||||||
group = [];
|
|
||||||
} else if (group.length > 1) {
|
|
||||||
result.push({
|
result.push({
|
||||||
rowid: Math.max(...group.map((x) => x.rowid)),
|
rowid: Math.max(...group.map((x) => x.rowid)),
|
||||||
type: `${type}_group`,
|
type: 'contact_group',
|
||||||
messages: group,
|
messages: group,
|
||||||
});
|
});
|
||||||
group = [];
|
group = [];
|
||||||
}
|
}
|
||||||
result.push(message);
|
result.push(message);
|
||||||
type = undefined;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (group.length == 1) {
|
if (group.length > 0) {
|
||||||
result.push(group[0]);
|
|
||||||
group = [];
|
|
||||||
} else if (group.length > 1) {
|
|
||||||
result.push({
|
result.push({
|
||||||
rowid: Math.max(...group.map((x) => x.rowid)),
|
rowid: Math.max(...group.map((x) => x.rowid)),
|
||||||
type: `${type}_group`,
|
type: 'contact_group',
|
||||||
messages: group,
|
messages: group,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
unread_allowed() {
|
|
||||||
return !this.hash?.startsWith('#%') && !this.hash?.startsWith('#@');
|
|
||||||
}
|
|
||||||
|
|
||||||
load_and_render(messages) {
|
load_and_render(messages) {
|
||||||
let messages_by_id = this.process_messages(messages);
|
let messages_by_id = this.process_messages(messages);
|
||||||
let final_messages = this.group_messages(
|
let final_messages = this.group_following(
|
||||||
this.finalize_messages(messages_by_id)
|
this.finalize_messages(messages_by_id)
|
||||||
);
|
);
|
||||||
let unread_rowid = -1;
|
let unread_rowid = -1;
|
||||||
if (this.unread_allowed()) {
|
for (let message of final_messages) {
|
||||||
for (let message of final_messages) {
|
if (message.rowid >= this.channel_unread) {
|
||||||
if (message.rowid >= this.channel_unread) {
|
unread_rowid = message.rowid;
|
||||||
unread_rowid = message.rowid;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<style>
|
|
||||||
${generate_theme()}
|
|
||||||
</style>
|
|
||||||
<div>
|
<div>
|
||||||
${repeat(
|
${repeat(
|
||||||
final_messages,
|
final_messages,
|
||||||
@@ -248,26 +211,13 @@ class TfNewsElement extends LitElement {
|
|||||||
collapsed="true"
|
collapsed="true"
|
||||||
channel=${this.channel}
|
channel=${this.channel}
|
||||||
channel_unread=${this.channel_unread}
|
channel_unread=${this.channel_unread}
|
||||||
.recent_reactions=${this.recent_reactions}
|
|
||||||
></tf-message>
|
></tf-message>
|
||||||
${x.rowid == unread_rowid
|
${x.rowid == unread_rowid
|
||||||
? html`<div style="display: flex; flex-direction: row">
|
? html`<div style="display: flex; flex-direction: row">
|
||||||
<div
|
<div
|
||||||
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
||||||
></div>
|
></div>
|
||||||
<button
|
<div style="color: #f00; padding: 8px">unread</div>
|
||||||
style="color: #f00; padding: 8px"
|
|
||||||
class="w3-button"
|
|
||||||
@click=${() =>
|
|
||||||
this.dispatchEvent(
|
|
||||||
new Event('mark_all_read', {
|
|
||||||
bubbles: true,
|
|
||||||
composed: true,
|
|
||||||
})
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
unread
|
|
||||||
</button>
|
|
||||||
<div
|
<div
|
||||||
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {LitElement, html, until, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import * as tfutils from './tf-utils.js';
|
import * as tfutils from './tf-utils.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfProfileElement extends LitElement {
|
class TfProfileElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -11,10 +11,8 @@ class TfProfileElement extends LitElement {
|
|||||||
id: {type: String},
|
id: {type: String},
|
||||||
users: {type: Object},
|
users: {type: Object},
|
||||||
size: {type: Number},
|
size: {type: Number},
|
||||||
sequence: {type: Number},
|
|
||||||
following: {type: Boolean},
|
following: {type: Boolean},
|
||||||
blocking: {type: Boolean},
|
blocking: {type: Boolean},
|
||||||
show_followed: {type: Boolean},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +26,6 @@ class TfProfileElement extends LitElement {
|
|||||||
this.id = null;
|
this.id = null;
|
||||||
this.users = {};
|
this.users = {};
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
this.sequence = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
@@ -37,22 +34,16 @@ class TfProfileElement extends LitElement {
|
|||||||
this.following = undefined;
|
this.following = undefined;
|
||||||
this.blocking = undefined;
|
this.blocking = undefined;
|
||||||
|
|
||||||
let latest = (
|
|
||||||
await tfrpc.rpc.query('SELECT MAX(rowid) AS latest FROM messages')
|
|
||||||
)[0].latest;
|
|
||||||
|
|
||||||
let result = await tfrpc.rpc.query(
|
let result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT json_extract(content, '$.following') AS following
|
SELECT json_extract(content, '$.following') AS following
|
||||||
FROM messages WHERE author = ? AND
|
FROM messages WHERE author = ? AND
|
||||||
json_extract(content, '$.type') = 'contact' AND
|
json_extract(content, '$.type') = 'contact' AND
|
||||||
json_extract(content, '$.contact') = ? AND
|
json_extract(content, '$.contact') = ? AND
|
||||||
following IS NOT NULL AND
|
following IS NOT NULL
|
||||||
messages.rowid <= ?
|
|
||||||
ORDER BY sequence DESC LIMIT 1
|
ORDER BY sequence DESC LIMIT 1
|
||||||
`,
|
`,
|
||||||
[this.whoami, this.id, latest],
|
[this.whoami, this.id]
|
||||||
{cacheable: true}
|
|
||||||
);
|
);
|
||||||
this.following = result?.[0]?.following ?? false;
|
this.following = result?.[0]?.following ?? false;
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
@@ -61,12 +52,10 @@ class TfProfileElement extends LitElement {
|
|||||||
FROM messages WHERE author = ? AND
|
FROM messages WHERE author = ? AND
|
||||||
json_extract(content, '$.type') = 'contact' AND
|
json_extract(content, '$.type') = 'contact' AND
|
||||||
json_extract(content, '$.contact') = ? AND
|
json_extract(content, '$.contact') = ? AND
|
||||||
blocking IS NOT NULL AND
|
blocking IS NOT NULL
|
||||||
messages.rowid <= ?
|
|
||||||
ORDER BY sequence DESC LIMIT 1
|
ORDER BY sequence DESC LIMIT 1
|
||||||
`,
|
`,
|
||||||
[this.whoami, this.id, latest],
|
[this.whoami, this.id]
|
||||||
{cacheable: true}
|
|
||||||
);
|
);
|
||||||
this.blocking = result?.[0]?.blocking ?? false;
|
this.blocking = result?.[0]?.blocking ?? false;
|
||||||
}
|
}
|
||||||
@@ -150,8 +139,7 @@ class TfProfileElement extends LitElement {
|
|||||||
let self = this;
|
let self = this;
|
||||||
let input = document.createElement('input');
|
let input = document.createElement('input');
|
||||||
input.type = 'file';
|
input.type = 'file';
|
||||||
input.addEventListener('change', function (event) {
|
input.onchange = function (event) {
|
||||||
input.parentNode.removeChild(input);
|
|
||||||
let file = event.target.files[0];
|
let file = event.target.files[0];
|
||||||
file
|
file
|
||||||
.arrayBuffer()
|
.arrayBuffer()
|
||||||
@@ -166,8 +154,7 @@ class TfProfileElement extends LitElement {
|
|||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
alert(e.message);
|
alert(e.message);
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
document.body.appendChild(input);
|
|
||||||
input.click();
|
input.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,83 +162,17 @@ class TfProfileElement extends LitElement {
|
|||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
show_image(link) {
|
|
||||||
let div = document.createElement('div');
|
|
||||||
div.style.left = 0;
|
|
||||||
div.style.top = 0;
|
|
||||||
div.style.width = '100%';
|
|
||||||
div.style.height = '100%';
|
|
||||||
div.style.position = 'fixed';
|
|
||||||
div.style.background = '#000';
|
|
||||||
div.style.zIndex = 100;
|
|
||||||
div.style.display = 'grid';
|
|
||||||
let img = document.createElement('img');
|
|
||||||
img.src = link;
|
|
||||||
img.style.maxWidth = '100vw';
|
|
||||||
img.style.maxHeight = '100vh';
|
|
||||||
img.style.display = 'block';
|
|
||||||
img.style.margin = 'auto';
|
|
||||||
img.style.objectFit = 'contain';
|
|
||||||
img.style.width = '100vw';
|
|
||||||
div.appendChild(img);
|
|
||||||
function image_close(event) {
|
|
||||||
document.body.removeChild(div);
|
|
||||||
window.removeEventListener('keydown', image_close);
|
|
||||||
}
|
|
||||||
div.onclick = image_close;
|
|
||||||
window.addEventListener('keydown', image_close);
|
|
||||||
document.body.appendChild(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
body_click(event) {
|
|
||||||
if (event.srcElement.tagName == 'IMG') {
|
|
||||||
this.show_image(event.srcElement.src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle_account_list(event) {
|
|
||||||
let content = event.srcElement.nextElementSibling;
|
|
||||||
this.show_followed = !this.show_followed;
|
|
||||||
}
|
|
||||||
|
|
||||||
async load_follows() {
|
|
||||||
let accounts = await tfrpc.rpc.following([this.id], 1);
|
|
||||||
return html`
|
|
||||||
<div class="w3-container">
|
|
||||||
<button
|
|
||||||
class="w3-button w3-block w3-theme-d1 followed_accounts"
|
|
||||||
@click=${this.toggle_account_list}
|
|
||||||
>
|
|
||||||
${this.show_followed ? 'Hide' : 'Show'} Followed Accounts
|
|
||||||
(${Object.keys(accounts).length})
|
|
||||||
</button>
|
|
||||||
<div class=${'w3-card' + (this.show_followed ? '' : ' w3-hide')}>
|
|
||||||
<ul class="w3-ul w3-theme-d4 w3-border-theme">
|
|
||||||
${Object.keys(accounts).map(
|
|
||||||
(x) => html`
|
|
||||||
<li class="w3-border-theme">
|
|
||||||
<tf-user id=${x} .users=${this.users}></tf-user>
|
|
||||||
</li>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.load();
|
this.load();
|
||||||
let self = this;
|
let self = this;
|
||||||
let profile = this.users[this.id] || {};
|
let profile = this.users[this.id] || {};
|
||||||
tfrpc.rpc
|
tfrpc.rpc
|
||||||
.query(
|
.query(
|
||||||
`SELECT size AS size, max_sequence AS sequence FROM messages_stats WHERE author = ?`,
|
`SELECT SUM(LENGTH(content)) AS size FROM messages WHERE author = ?`,
|
||||||
[this.id]
|
[this.id]
|
||||||
)
|
)
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
self.size = result[0].size;
|
self.size = result[0].size;
|
||||||
self.sequence = result[0].sequence;
|
|
||||||
});
|
});
|
||||||
let edit;
|
let edit;
|
||||||
let follow;
|
let follow;
|
||||||
@@ -316,28 +237,22 @@ class TfProfileElement extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
: null;
|
: null;
|
||||||
let image = profile.image;
|
let image =
|
||||||
if (typeof image == 'string' && !image.startsWith('&')) {
|
typeof profile.image == 'string' ? profile.image : profile.image?.link;
|
||||||
try {
|
|
||||||
image = JSON.parse(image)?.link;
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
image = this.editing?.image ?? image;
|
image = this.editing?.image ?? image;
|
||||||
let description = this.editing?.description ?? profile.description;
|
let description = this.editing?.description ?? profile.description;
|
||||||
return html`
|
return html`<div class="w3-card-4 w3-container w3-theme-d3" style="box-sizing: border-box">
|
||||||
<style>${generate_theme()}</style>
|
|
||||||
<div class="w3-card-4 w3-container w3-theme-d3" style="box-sizing: border-box">
|
|
||||||
<header class="w3-container">
|
<header class="w3-container">
|
||||||
<p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)} in ${this.sequence} messages)</p>
|
<p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})</p>
|
||||||
</header>
|
</header>
|
||||||
<div class="w3-container" @click=${this.body_click}>
|
<div class="w3-container">
|
||||||
<div class="w3-margin-bottom" style="display: flex; flex-direction: row">
|
<div class="w3-margin-bottom" style="display: flex; flex-direction: row">
|
||||||
<input type="text" class="w3-input w3-border w3-theme-d1" style="display: flex 1 1" readonly value=${this.id}></input>
|
<input type="text" class="w3-input w3-border w3-theme-d1" style="display: flex 1 1" readonly value=${this.id}></input>
|
||||||
<button class="w3-button w3-theme-d1 w3-ripple" style="flex: 0 0 auto" @click=${this.copy_id}>Copy</button>
|
<button class="w3-button w3-theme-d1 w3-ripple" style="flex: 0 0 auto" @click=${this.copy_id}>Copy</button>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; flex-direction: row; gap: 1em">
|
<div style="display: flex; flex-direction: row; gap: 1em">
|
||||||
${edit_profile}
|
${edit_profile}
|
||||||
<div style="flex: 1 0 50%; contain: layout; overflow: auto; word-wrap: normal; word-break: normal">
|
<div style="flex: 1 0 50%">
|
||||||
${
|
${
|
||||||
image
|
image
|
||||||
? html`<div><img src=${'/' + image + '/view'} style="width: 256px; height: auto"></img></div>`
|
? html`<div><img src=${'/' + image + '/view'} style="width: 256px; height: auto"></img></div>`
|
||||||
@@ -356,12 +271,8 @@ class TfProfileElement extends LitElement {
|
|||||||
Blocked by ${profile.blocked} identities.
|
Blocked by ${profile.blocked} identities.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${until(this.load_follows(), html`<p>Loading accounts followed...</p>`)}
|
|
||||||
<footer class="w3-container">
|
<footer class="w3-container">
|
||||||
<p>
|
<p>
|
||||||
<a class="w3-button w3-theme-d1" href=${'#🔐' + (this.id != this.whoami ? this.id : '')}>
|
|
||||||
Open Private Chat
|
|
||||||
</a>
|
|
||||||
${edit}
|
${edit}
|
||||||
${follow}
|
${follow}
|
||||||
${block}
|
${block}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfReactionsModalElement extends LitElement {
|
class TfReactionsModalElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -24,57 +24,47 @@ class TfReactionsModalElement extends LitElement {
|
|||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
return this.votes?.length
|
return this.votes?.length
|
||||||
? html` <style>
|
? html` <div
|
||||||
${generate_theme()}
|
class="w3-modal w3-animate-opacity"
|
||||||
</style>
|
style="display: block; box-sizing: border-box; z-index: 10"
|
||||||
|
@click=${this.clear}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="w3-modal w3-animate-opacity"
|
class="w3-modal-content w3-card-4 w3-theme-d1"
|
||||||
style="display: block; box-sizing: border-box; z-index: 10"
|
onclick="event.stopPropagation()"
|
||||||
@click=${this.clear}
|
|
||||||
>
|
>
|
||||||
<div
|
<div class="w3-container w3-padding">
|
||||||
class="w3-modal-content w3-card-4 w3-theme-d1"
|
<header class="w3-container">
|
||||||
onclick="event.stopPropagation()"
|
<h2>Reactions</h2>
|
||||||
>
|
<span class="w3-button w3-display-topright" @click=${this.clear}
|
||||||
<div class="w3-container w3-padding">
|
>×</span
|
||||||
<header class="w3-container">
|
>
|
||||||
<h2>Reactions</h2>
|
</header>
|
||||||
<span
|
<ul class="w3-theme-dark w3-container w3-ul">
|
||||||
class="w3-button w3-display-topright"
|
${this.votes.map(
|
||||||
@click=${this.clear}
|
(x) => html`
|
||||||
>×</span
|
<li class="w3-bar">
|
||||||
>
|
<span class="w3-bar-item"
|
||||||
</header>
|
>${x?.content?.vote?.expression}</span
|
||||||
<ul class="w3-theme-dark w3-container w3-ul">
|
>
|
||||||
${this.votes
|
<tf-user
|
||||||
.sort((x, y) => y.timestamp - x.timestamp)
|
class="w3-bar-item"
|
||||||
.map(
|
id=${x.author}
|
||||||
(x) => html`
|
.users=${this.users}
|
||||||
<li
|
></tf-user>
|
||||||
style="display: flex; flex-direction: row; gap: 4px"
|
<span class="w3-bar-item w3-right"
|
||||||
>
|
>${new Date(x?.timestamp).toLocaleString()}</span
|
||||||
<span style="flex-basis: 3em"
|
>
|
||||||
>${x?.content?.vote?.expression}</span
|
</li>
|
||||||
>
|
`
|
||||||
<tf-user
|
)}
|
||||||
style="flex: 1 1; overflow: hidden"
|
</ul>
|
||||||
id=${x.author}
|
<footer class="w3-container w3-padding">
|
||||||
.users=${this.users}
|
<button class="w3-button" @click=${this.clear}>Close</button>
|
||||||
></tf-user>
|
</footer>
|
||||||
<span
|
|
||||||
style="flex-shrink: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
|
|
||||||
>${new Date(x?.timestamp).toLocaleString()}</span
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
<footer class="w3-container w3-padding">
|
|
||||||
<button class="w3-button" @click=${this.clear}>Close</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>
|
||||||
|
</div>`
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import {css, unsafeCSS, until} from './lit-all.min.js';
|
import {css, unsafeCSS} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
|
||||||
|
|
||||||
const tf = css`
|
const tf = css`
|
||||||
img {
|
img {
|
||||||
@@ -44,14 +43,12 @@ const tf = css`
|
|||||||
border-left: 4px solid #fff;
|
border-left: 4px solid #fff;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const w3 = css`
|
const w3 = css`
|
||||||
/* W3.CSS 5.01 March 14 2025 by Jan Egil and Borge Refsnes */
|
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
@@ -91,7 +88,7 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
||||||
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
|
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
|
||||||
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
||||||
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||||
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
||||||
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
||||||
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
||||||
@@ -139,7 +136,7 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
||||||
@media (max-width:1205px){.w3-auto{max-width:95%}}
|
@media (max-width:1205px){.w3-auto{max-width:95%}}
|
||||||
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
||||||
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
||||||
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
||||||
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
||||||
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
||||||
@@ -161,10 +158,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
|
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
@@ -206,9 +199,9 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
/* Colors */
|
/* Colors */
|
||||||
.w3-amber,.w3-hover-amber:hover,.w3-warning{color:#000!important;background-color:#ffc107!important}
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
.w3-blue,.w3-hover-blue:hover,.w3-info,.w3-primary{color:#fff!important;background-color:#2196F3!important}
|
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||||
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||||
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||||
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||||
@@ -223,24 +216,15 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||||
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||||
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||||
.w3-red,.w3-hover-red:hover,.w3-danger{color:#fff!important;background-color:#f44336!important}
|
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||||
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||||
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||||
.w3-yellow,.w3-hover-yellow:hover,.w3-note{color:#000!important;background-color:#ffeb3b!important}
|
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||||
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||||
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||||
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover,.w3-secondary{color:#000!important;background-color:#9e9e9e!important}
|
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
|
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover,.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
@@ -409,8 +393,16 @@ function is_dark(hex, value) {
|
|||||||
return (r * 299 + g * 587 + b * 114) / 1000 < value;
|
return (r * 299 + g * 587 + b * 114) / 1000 < value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generate(color) {
|
function generated() {
|
||||||
let [r, g, b] = hex_to_rgb(color);
|
let now = new Date();
|
||||||
|
let k_color = rgb_to_hex([
|
||||||
|
(now.getDay() * 128) / 6,
|
||||||
|
(now.getHours() * 128) / 23,
|
||||||
|
(now.getSeconds() * 128) / 59,
|
||||||
|
]);
|
||||||
|
//let k_color = '#034f84';
|
||||||
|
//let k_color = rgb_to_hex([Math.random() * 256, Math.random() * 256, Math.random() * 256]);
|
||||||
|
let [r, g, b] = hex_to_rgb(k_color);
|
||||||
let [h, s, l] = rgb_to_hsl(r, g, b);
|
let [h, s, l] = rgb_to_hsl(r, g, b);
|
||||||
|
|
||||||
let theme1 = {
|
let theme1 = {
|
||||||
@@ -454,28 +446,4 @@ export function generate(color) {
|
|||||||
return unsafeCSS(result);
|
return unsafeCSS(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
let g_theme;
|
export let styles = [tf, w3, generated()];
|
||||||
export function generate_theme() {
|
|
||||||
return g_theme
|
|
||||||
? g_theme
|
|
||||||
: until(
|
|
||||||
tfrpc.rpc.localStorageGet('color').then(function (value) {
|
|
||||||
g_theme = generate(value ?? '#034f84');
|
|
||||||
return g_theme;
|
|
||||||
}),
|
|
||||||
generated_now()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function generated_now() {
|
|
||||||
let now = new Date();
|
|
||||||
return generate(
|
|
||||||
rgb_to_hex([
|
|
||||||
(now.getDay() * 128) / 6,
|
|
||||||
(now.getHours() * 128) / 23,
|
|
||||||
(now.getSeconds() * 128) / 59,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export let styles = [tf, w3];
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html} from './lit-all.min.js';
|
import {LitElement, html} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabConnectionsElement extends LitElement {
|
class TfTabConnectionsElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -15,7 +15,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
connect_attempt: {type: Object},
|
connect_attempt: {type: Object},
|
||||||
connect_message: {type: String},
|
connect_message: {type: String},
|
||||||
connect_success: {type: Boolean},
|
connect_success: {type: Boolean},
|
||||||
peer_exchange: {type: Boolean},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,20 +47,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
tfrpc.rpc.getServerIdentity().then(function (identity) {
|
tfrpc.rpc.getServerIdentity().then(function (identity) {
|
||||||
self.server_identity = identity;
|
self.server_identity = identity;
|
||||||
});
|
});
|
||||||
this.check_peer_exchange();
|
|
||||||
}
|
|
||||||
|
|
||||||
async check_peer_exchange() {
|
|
||||||
if (await tfrpc.rpc.isAdministrator()) {
|
|
||||||
this.peer_exchange = await tfrpc.rpc.globalSettingsGet('peer_exchange');
|
|
||||||
} else {
|
|
||||||
this.peer_exchange = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async enable_peer_exchange() {
|
|
||||||
await tfrpc.rpc.globalSettingsSet('peer_exchange', true);
|
|
||||||
await this.check_peer_exchange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render_connection_summary(connection) {
|
render_connection_summary(connection) {
|
||||||
@@ -118,23 +103,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_progress(name, value, max) {
|
|
||||||
if (max && value != max) {
|
|
||||||
return html`
|
|
||||||
<div class="w3-theme-d1 w3-small">
|
|
||||||
<div
|
|
||||||
class="w3-container w3-theme-l1"
|
|
||||||
style="width: ${Math.floor(
|
|
||||||
(100.0 * value) / max
|
|
||||||
)}%; text-wrap: nowrap"
|
|
||||||
>
|
|
||||||
${name} ${value} / ${max} (${Math.round((100.0 * value) / max)}%)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render_broadcast(connection) {
|
render_broadcast(connection) {
|
||||||
let self = this;
|
let self = this;
|
||||||
return html`
|
return html`
|
||||||
@@ -186,16 +154,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
: undefined}
|
: undefined}
|
||||||
${connection.flags.one_shot ? '🔃' : undefined}
|
${connection.flags.one_shot ? '🔃' : undefined}
|
||||||
<tf-user id=${connection.id} .users=${this.users}></tf-user>
|
<tf-user id=${connection.id} .users=${this.users}></tf-user>
|
||||||
${this.render_progress(
|
|
||||||
'recv',
|
|
||||||
connection.progress.in.total - connection.progress.in.current,
|
|
||||||
connection.progress.in.total
|
|
||||||
)}
|
|
||||||
${this.render_progress(
|
|
||||||
'send',
|
|
||||||
connection.progress.out.total - connection.progress.out.current,
|
|
||||||
connection.progress.out.total
|
|
||||||
)}
|
|
||||||
${connection.tunnel !== undefined
|
${connection.tunnel !== undefined
|
||||||
? '🚇'
|
? '🚇'
|
||||||
: html`(${connection.host}:${connection.port})`}
|
: html`(${connection.host}:${connection.port})`}
|
||||||
@@ -248,44 +206,10 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_accordian(id) {
|
|
||||||
let element = this.renderRoot.getElementById(id);
|
|
||||||
element.classList.toggle('w3-hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
valid_connections() {
|
|
||||||
return this.connections.filter((x) => x.tunnel === undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
valid_broadcasts() {
|
|
||||||
return this.broadcasts
|
|
||||||
.filter((x) => x.address)
|
|
||||||
.filter((x) => this.connections.map((c) => c.id).indexOf(x.pubkey) == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
return html`
|
return html`
|
||||||
<style>
|
|
||||||
${generate_theme()}
|
|
||||||
</style>
|
|
||||||
<div class="w3-container" style="box-sizing: border-box">
|
<div class="w3-container" style="box-sizing: border-box">
|
||||||
<div
|
|
||||||
class=${'w3-panel w3-padding w3-theme-l3' +
|
|
||||||
(this.peer_exchange !== false ? ' w3-hide' : '')}
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
Looking for connections? Enabling this option will include publicly
|
|
||||||
advertised rooms and pubs among the list of discovered connections
|
|
||||||
to help you replicate.
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-theme-d1"
|
|
||||||
@click=${this.enable_peer_exchange}
|
|
||||||
>
|
|
||||||
🔍🌐 Use publicly advertised peers
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<h2>New Connection</h2>
|
<h2>New Connection</h2>
|
||||||
<textarea class="w3-input w3-theme-d1" id="code"></textarea>
|
<textarea class="w3-input w3-theme-d1" id="code"></textarea>
|
||||||
${this.render_message(this.renderRoot.getElementById('code')?.value)}
|
${this.render_message(this.renderRoot.getElementById('code')?.value)}
|
||||||
@@ -296,33 +220,27 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
>
|
>
|
||||||
Connect
|
Connect
|
||||||
</button>
|
</button>
|
||||||
<h2
|
<h2>Broadcasts</h2>
|
||||||
class="w3-button w3-block w3-theme-d1"
|
<ul class="w3-ul w3-border">
|
||||||
@click=${() => self.toggle_accordian('connections')}
|
${this.broadcasts
|
||||||
>
|
.filter((x) => x.address)
|
||||||
Connections (${this.valid_connections().length})
|
.filter(
|
||||||
</h2>
|
(x) => self.connections.map((c) => c.id).indexOf(x.pubkey) == -1
|
||||||
<ul class="w3-ul w3-border" id="connections">
|
)
|
||||||
${this.valid_connections().map(
|
.map((x) => self.render_broadcast(x))}
|
||||||
(x) => html` <li class="w3-bar">${this.render_connection(x)}</li> `
|
|
||||||
)}
|
|
||||||
</ul>
|
</ul>
|
||||||
<h2
|
<h2>Connections</h2>
|
||||||
class="w3-button w3-block w3-theme-d1"
|
<ul class="w3-ul w3-border">
|
||||||
@click=${() => self.toggle_accordian('broadcasts')}
|
${this.connections
|
||||||
>
|
.filter((x) => x.tunnel === undefined)
|
||||||
Discovery (${this.valid_broadcasts().length})
|
.map(
|
||||||
</h2>
|
(x) => html`
|
||||||
<ul class="w3-ul w3-border w3-hide" id="broadcasts">
|
<li class="w3-bar">${this.render_connection(x)}</li>
|
||||||
${this.valid_broadcasts().map((x) => self.render_broadcast(x))}
|
`
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<h2
|
<h2>Stored Connections</h2>
|
||||||
class="w3-button w3-block w3-theme-d1"
|
<ul class="w3-ul w3-border">
|
||||||
@click=${() => self.toggle_accordian('stored_connections')}
|
|
||||||
>
|
|
||||||
Stored Connections (${this.stored_connections.length})
|
|
||||||
</h2>
|
|
||||||
<ul class="w3-ul w3-border w3-hide" id="stored_connections">
|
|
||||||
${this.stored_connections.map(
|
${this.stored_connections.map(
|
||||||
(x) => html`
|
(x) => html`
|
||||||
<li>
|
<li>
|
||||||
@@ -342,12 +260,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
<div class="w3-bar-item">
|
<div class="w3-bar-item">
|
||||||
<tf-user id=${x.pubkey} .users=${self.users}></tf-user>
|
<tf-user id=${x.pubkey} .users=${self.users}></tf-user>
|
||||||
<div><small>${x.address}:${x.port}</small></div>
|
<div><small>${x.address}:${x.port}</small></div>
|
||||||
<div>
|
|
||||||
<small
|
|
||||||
>Last connection:
|
|
||||||
${new Date(x.last_success * 1000)}</small
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${this.render_message(x)}
|
${this.render_message(x)}
|
||||||
@@ -355,13 +267,8 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<h2
|
<h2>Local Accounts</h2>
|
||||||
class="w3-button w3-block w3-theme-d1"
|
<div class="w3-container">
|
||||||
@click=${() => self.toggle_accordian('local_accounts')}
|
|
||||||
>
|
|
||||||
Local Accounts (${this.identities.length})
|
|
||||||
</h2>
|
|
||||||
<div class="w3-container w3-hide" id="local_accounts">
|
|
||||||
${this.identities.map(
|
${this.identities.map(
|
||||||
(x) =>
|
(x) =>
|
||||||
html`<div
|
html`<div
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, cache, html, unsafeHTML, until} from './lit-all.min.js';
|
import {LitElement, cache, html, unsafeHTML, until} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabNewsFeedElement extends LitElement {
|
class TfTabNewsFeedElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -18,8 +18,6 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
time_range: {type: Array},
|
time_range: {type: Array},
|
||||||
time_loading: {type: Array},
|
time_loading: {type: Array},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
grouped_private_messages: {type: Object},
|
|
||||||
recent_reactions: {type: Array},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +37,6 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
this.start_time = new Date().valueOf();
|
this.start_time = new Date().valueOf();
|
||||||
this.time_range = [0, 0];
|
this.time_range = [0, 0];
|
||||||
this.time_loading = undefined;
|
this.time_loading = undefined;
|
||||||
this.recent_reactions = [];
|
|
||||||
this.loading = 0;
|
this.loading = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,73 +46,9 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
: this.hash.substring(1);
|
: this.hash.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fetch_related_messages(messages) {
|
|
||||||
let refs = await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
WITH
|
|
||||||
news AS (
|
|
||||||
SELECT value AS id FROM json_each(?)
|
|
||||||
)
|
|
||||||
SELECT refs_out.ref AS ref FROM messages_refs refs_out JOIN news ON refs_out.message = news.id
|
|
||||||
UNION
|
|
||||||
SELECT refs_in.message AS ref FROM messages_refs refs_in JOIN news ON refs_in.ref = news.id
|
|
||||||
`,
|
|
||||||
[JSON.stringify(messages.map((x) => x.id))]
|
|
||||||
);
|
|
||||||
let related_messages = await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
|
||||||
FROM messages
|
|
||||||
JOIN json_each(?2) refs ON messages.id = refs.value
|
|
||||||
JOIN json_each(?1) AS following ON messages.author = following.value
|
|
||||||
`,
|
|
||||||
[JSON.stringify(this.following), JSON.stringify(refs.map((x) => x.ref))]
|
|
||||||
);
|
|
||||||
let combined = [].concat(messages, related_messages);
|
|
||||||
let refs2 = await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
WITH
|
|
||||||
news AS (
|
|
||||||
SELECT value AS id FROM json_each(?)
|
|
||||||
)
|
|
||||||
SELECT refs_out.ref AS ref FROM messages_refs refs_out JOIN news ON refs_out.message = news.id
|
|
||||||
UNION
|
|
||||||
SELECT refs_in.message AS ref FROM messages_refs refs_in JOIN news ON refs_in.ref = news.id
|
|
||||||
`,
|
|
||||||
[JSON.stringify(combined.map((x) => x.id))]
|
|
||||||
);
|
|
||||||
let t0 = new Date();
|
|
||||||
let result = [].concat(
|
|
||||||
combined,
|
|
||||||
await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
|
||||||
FROM json_each(?2) refs
|
|
||||||
JOIN messages ON messages.id = refs.value
|
|
||||||
JOIN json_each(?1) following ON messages.author = following.value
|
|
||||||
WHERE messages.content ->> 'type' != 'post'
|
|
||||||
`,
|
|
||||||
[
|
|
||||||
JSON.stringify(this.following),
|
|
||||||
JSON.stringify(refs2.map((x) => x.ref)),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
let t1 = new Date();
|
|
||||||
console.log((t1 - t0) / 1000);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetch_messages(start_time, end_time) {
|
async fetch_messages(start_time, end_time) {
|
||||||
this.dispatchEvent(
|
|
||||||
new CustomEvent('loadmessages', {
|
|
||||||
bubbles: true,
|
|
||||||
composed: true,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this.time_loading = [start_time, end_time];
|
this.time_loading = [start_time, end_time];
|
||||||
let result;
|
let result;
|
||||||
const k_max_results = 64;
|
|
||||||
if (this.hash == '#@') {
|
if (this.hash == '#@') {
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
@@ -126,7 +59,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
WHERE
|
WHERE
|
||||||
messages.author != ?1 AND
|
messages.author != ?1 AND
|
||||||
(?3 IS NULL OR messages.timestamp >= ?3) AND messages.timestamp < ?4
|
(?3 IS NULL OR messages.timestamp >= ?3) AND messages.timestamp < ?4
|
||||||
ORDER BY timestamp DESC limit ?5)
|
ORDER BY timestamp DESC limit 20)
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM mentions
|
FROM mentions
|
||||||
JOIN messages_refs ON mentions.id = messages_refs.ref
|
JOIN messages_refs ON mentions.id = messages_refs.ref
|
||||||
@@ -139,7 +72,6 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
JSON.stringify(this.following),
|
JSON.stringify(this.following),
|
||||||
start_time,
|
start_time,
|
||||||
end_time,
|
end_time,
|
||||||
k_max_results,
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
} else if (this.hash.startsWith('#@')) {
|
} else if (this.hash.startsWith('#@')) {
|
||||||
@@ -149,7 +81,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
selected AS (SELECT rowid, id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
selected AS (SELECT rowid, id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
||||||
FROM messages
|
FROM messages
|
||||||
WHERE messages.author = ?1 AND (?2 IS NULL OR messages.timestamp >= 2) AND messages.timestamp < ?3
|
WHERE messages.author = ?1 AND (?2 IS NULL OR messages.timestamp >= 2) AND messages.timestamp < ?3
|
||||||
ORDER BY sequence DESC LIMIT ?4
|
ORDER BY sequence DESC LIMIT 20
|
||||||
)
|
)
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM selected
|
FROM selected
|
||||||
@@ -158,7 +90,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
UNION
|
UNION
|
||||||
SELECT TRUE AS is_primary, * FROM selected
|
SELECT TRUE AS is_primary, * FROM selected
|
||||||
`,
|
`,
|
||||||
[this.hash.substring(1), start_time, end_time, k_max_results]
|
[this.hash.substring(1), start_time, end_time]
|
||||||
);
|
);
|
||||||
} else if (this.hash.startsWith('#%')) {
|
} else if (this.hash.startsWith('#%')) {
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
@@ -175,37 +107,44 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
[this.hash.substring(1)]
|
[this.hash.substring(1)]
|
||||||
);
|
);
|
||||||
} else if (this.hash.startsWith('##')) {
|
} else if (this.hash.startsWith('##')) {
|
||||||
let initial_messages = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
WITH
|
WITH
|
||||||
all_news AS (
|
all_news AS (
|
||||||
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM messages
|
FROM messages
|
||||||
JOIN json_each(?) AS following ON messages.author = following.value
|
JOIN json_each(?) AS following ON messages.author = following.value
|
||||||
WHERE messages.content ->> 'channel' = ?4 AND messages.content ->> 'type' != 'vote'
|
WHERE messages.content ->> 'channel' = ?4
|
||||||
UNION
|
UNION
|
||||||
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM messages_refs
|
FROM messages_fts(?5)
|
||||||
JOIN messages ON messages.id = messages_refs.message
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||||
JOIN json_each(?1) AS following ON messages.author = following.value
|
JOIN json_each(?1) AS following ON messages.author = following.value
|
||||||
WHERE messages_refs.ref = '#' || ?4 AND messages.content ->> 'type' != 'vote'
|
JOIN json_tree(messages.content, '$.mentions') AS mention ON mention.value = '#' || ?4),
|
||||||
)
|
news AS (SELECT * FROM all_news
|
||||||
SELECT TRUE AS is_primary, all_news.* FROM all_news
|
WHERE (?2 IS NULL OR all_news.timestamp >= ?2) AND all_news.timestamp < ?3
|
||||||
WHERE (?2 IS NULL OR all_news.timestamp >= ?2) AND all_news.timestamp < ?3
|
ORDER BY all_news.timestamp DESC LIMIT 20)
|
||||||
ORDER BY all_news.timestamp DESC LIMIT ?5
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
|
FROM news
|
||||||
|
JOIN messages_refs ON news.id = messages_refs.ref
|
||||||
|
JOIN messages ON messages_refs.message = messages.id
|
||||||
|
UNION
|
||||||
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
|
FROM news
|
||||||
|
JOIN messages_refs ON news.id = messages_refs.message
|
||||||
|
JOIN messages ON messages_refs.ref = messages.id
|
||||||
|
UNION
|
||||||
|
SELECT TRUE AS is_primary, news.* FROM news
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
JSON.stringify(this.following),
|
JSON.stringify(this.following),
|
||||||
start_time,
|
start_time,
|
||||||
end_time,
|
end_time,
|
||||||
this.hash.substring(2),
|
this.hash.substring(2),
|
||||||
k_max_results,
|
'"#' + this.hash.substring(2).replace('"', '""') + '"',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
result = await this._fetch_related_messages(initial_messages);
|
} else if (this.hash == '#🔐') {
|
||||||
} else if (this.hash.startsWith('#🔐')) {
|
|
||||||
let ids =
|
|
||||||
this.hash == '#🔐' ? [] : this.hash.substring('#🔐'.length).split(',');
|
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT TRUE AS is_primary, messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
SELECT TRUE AS is_primary, messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
||||||
@@ -214,65 +153,39 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
WHERE
|
WHERE
|
||||||
(?2 IS NULL OR (messages.timestamp >= ?2)) AND messages.timestamp < ?3 AND
|
(?2 IS NULL OR (messages.timestamp >= ?2)) AND messages.timestamp < ?3 AND
|
||||||
json(messages.content) LIKE '"%'
|
json(messages.content) LIKE '"%'
|
||||||
ORDER BY messages.rowid DESC LIMIT ?4
|
ORDER BY messages.sequence DESC LIMIT 20
|
||||||
`,
|
`,
|
||||||
[
|
[JSON.stringify(this.private_messages), start_time, end_time]
|
||||||
JSON.stringify(
|
|
||||||
this.grouped_private_messages?.[JSON.stringify(ids)]?.map(
|
|
||||||
(x) => x.id
|
|
||||||
) ?? []
|
|
||||||
),
|
|
||||||
start_time,
|
|
||||||
end_time,
|
|
||||||
k_max_results,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
result = (await this.decrypt(result)).filter((x) => x.decrypted);
|
result = (await this.decrypt(result)).filter((x) => x.decrypted);
|
||||||
} else if (this.hash == '#👍') {
|
} else {
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
|
||||||
WITH votes AS (SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
|
||||||
FROM messages
|
|
||||||
JOIN json_each(?1) AS following ON messages.author = following.value
|
|
||||||
WHERE
|
|
||||||
messages.content ->> 'type' = 'vote' AND
|
|
||||||
(?2 IS NULL OR messages.timestamp >= ?2) AND messages.timestamp < ?3
|
|
||||||
ORDER BY timestamp DESC limit ?4)
|
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
|
||||||
FROM votes
|
|
||||||
JOIN messages ON messages.id = votes.content ->> '$.vote.link'
|
|
||||||
UNION
|
|
||||||
SELECT TRUE AS is_primary, * FROM votes
|
|
||||||
`,
|
|
||||||
[JSON.stringify(this.following), start_time, end_time, k_max_results]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let initial_messages = await tfrpc.rpc.query(
|
|
||||||
`
|
`
|
||||||
WITH
|
WITH
|
||||||
channels AS (SELECT '#' || value AS value FROM json_each(?5))
|
all_news AS (
|
||||||
SELECT TRUE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM messages
|
FROM messages
|
||||||
JOIN json_each(?1) AS following ON messages.author = following.value
|
JOIN json_each(?) AS following ON messages.author = following.value
|
||||||
WHERE messages.timestamp < ?3 AND (?2 IS NULL OR messages.timestamp >= ?2) AND
|
WHERE timestamp >= 0 AND timestamp < ?3),
|
||||||
messages.content ->> 'type' != 'vote' AND
|
news AS (
|
||||||
(messages.content ->> 'root' IS NULL OR (
|
SELECT * FROM all_news
|
||||||
NOT EXISTS (SELECT * FROM messages root JOIN channels ON ('#' || (root.content ->> 'channel')) = channels.value WHERE root.id = messages.content ->> 'root') AND
|
WHERE (?2 IS NULL OR all_news.timestamp >= ?2) AND all_news.timestamp < ?3
|
||||||
NOT EXISTS (SELECT * FROM messages root JOIN messages_refs ON root.id = messages.content ->> 'root' JOIN channels ON messages_refs.message = root.id AND messages_refs.ref = channels.value)
|
ORDER BY timestamp DESC LIMIT 20
|
||||||
)) AND
|
)
|
||||||
(messages.content ->> 'channel' IS NULL OR ('#' || (messages.content ->> 'channel')) NOT IN (SELECT * FROM channels)) AND
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
NOT EXISTS (SELECT * FROM messages_refs JOIN channels ON messages_refs.message = messages.id AND messages_refs.ref = channels.value)
|
FROM news
|
||||||
ORDER BY timestamp DESC LIMIT ?4
|
JOIN messages_refs ON news.id = messages_refs.ref
|
||||||
|
JOIN messages ON messages_refs.message = messages.id
|
||||||
|
UNION
|
||||||
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
|
FROM news
|
||||||
|
JOIN messages_refs ON news.id = messages_refs.message
|
||||||
|
JOIN messages ON messages_refs.ref = messages.id
|
||||||
|
UNION
|
||||||
|
SELECT TRUE AS is_primary, news.* FROM news
|
||||||
`,
|
`,
|
||||||
[
|
[JSON.stringify(this.following), start_time, end_time]
|
||||||
JSON.stringify(this.following),
|
|
||||||
start_time,
|
|
||||||
end_time,
|
|
||||||
k_max_results,
|
|
||||||
JSON.stringify(Object.keys(this.channels_latest)),
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
result = await this._fetch_related_messages(initial_messages);
|
|
||||||
}
|
}
|
||||||
this.time_loading = undefined;
|
this.time_loading = undefined;
|
||||||
return result;
|
return result;
|
||||||
@@ -292,24 +205,13 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
unread_allowed() {
|
|
||||||
return (
|
|
||||||
this.hash == '#@' ||
|
|
||||||
(!this.hash.startsWith('#%') && !this.hash.startsWith('#@'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async load_more() {
|
async load_more() {
|
||||||
this.loading++;
|
this.loading++;
|
||||||
this.loading_canceled = false;
|
this.loading_canceled = false;
|
||||||
try {
|
try {
|
||||||
let more = [];
|
let more = [];
|
||||||
let last_start_time = this.time_range[0];
|
let last_start_time = this.time_range[0];
|
||||||
try {
|
more = await this.fetch_messages(null, last_start_time);
|
||||||
more = await this.fetch_messages(null, last_start_time);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
this.update_time_range_from_messages(
|
this.update_time_range_from_messages(
|
||||||
more.filter((x) => x.timestamp < last_start_time)
|
more.filter((x) => x.timestamp < last_start_time)
|
||||||
);
|
);
|
||||||
@@ -388,20 +290,12 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
let self = this;
|
let self = this;
|
||||||
this.loading++;
|
this.loading++;
|
||||||
let messages = [];
|
let messages = [];
|
||||||
let original_hash = this.hash;
|
|
||||||
try {
|
try {
|
||||||
if (this._messages_hash !== this.hash) {
|
if (this._messages_hash !== this.hash) {
|
||||||
this.messages = [];
|
this.messages = [];
|
||||||
this._messages_hash = this.hash;
|
this._messages_hash = this.hash;
|
||||||
}
|
}
|
||||||
this._messages_following = JSON.stringify(this.following);
|
this._messages_following = this.following;
|
||||||
this._private_messages = JSON.stringify([
|
|
||||||
this.private_messages,
|
|
||||||
this.grouped_private_messages,
|
|
||||||
]);
|
|
||||||
this._channels_latest = JSON.stringify(
|
|
||||||
Object.keys(this.channels_latest ?? {})
|
|
||||||
);
|
|
||||||
let now = new Date().valueOf();
|
let now = new Date().valueOf();
|
||||||
let start_time = now - 24 * 60 * 60 * 1000;
|
let start_time = now - 24 * 60 * 60 * 1000;
|
||||||
this.start_time = start_time;
|
this.start_time = start_time;
|
||||||
@@ -414,12 +308,10 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
} finally {
|
} finally {
|
||||||
this.loading--;
|
this.loading--;
|
||||||
}
|
}
|
||||||
if (this.hash == original_hash) {
|
this.messages = this.merge_messages(this.messages, messages);
|
||||||
this.messages = this.merge_messages(this.messages, messages);
|
|
||||||
}
|
|
||||||
this.time_loading = undefined;
|
this.time_loading = undefined;
|
||||||
console.log(
|
console.log(
|
||||||
`loading ${messages.length} messages done for ${self.whoami} in ${(new Date() - start_time) / 1000}s`
|
`loading messages done for ${self.whoami} in ${(new Date() - start_time) / 1000}s`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,49 +334,15 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close_private_chat() {
|
|
||||||
this.mark_all_read();
|
|
||||||
this.dispatchEvent(
|
|
||||||
new CustomEvent('closeprivatechat', {
|
|
||||||
bubbles: true,
|
|
||||||
composed: true,
|
|
||||||
detail: {
|
|
||||||
key: JSON.stringify(
|
|
||||||
this.hash == '#🔐'
|
|
||||||
? []
|
|
||||||
: this.hash.substring('#🔐'.length).split(',')
|
|
||||||
),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
tfrpc.rpc.setHash('#');
|
|
||||||
}
|
|
||||||
|
|
||||||
render_close_chat_button() {
|
|
||||||
if (this.hash.startsWith('#🔐')) {
|
|
||||||
return html`
|
|
||||||
<button class="w3-button w3-theme-d1" @click=${this.close_private_chat}>
|
|
||||||
Close Chat
|
|
||||||
</button>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (
|
if (
|
||||||
!this.messages ||
|
!this.messages ||
|
||||||
this._messages_hash !== this.hash ||
|
this._messages_hash !== this.hash ||
|
||||||
this._messages_following !== JSON.stringify(this.following) ||
|
JSON.stringify(this._messages_following) !==
|
||||||
this._private_messages !==
|
JSON.stringify(this.following)
|
||||||
JSON.stringify([
|
|
||||||
this.private_messages,
|
|
||||||
this.grouped_private_messages,
|
|
||||||
]) ||
|
|
||||||
this._channels_latest !==
|
|
||||||
JSON.stringify(Object.keys(this.channels_latest))
|
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
`loading messages for ${this.whoami} (messages=${!this.messages},${this._messages_hash != this.hash} following=${this._messages_following !== JSON.stringify(this.following)}, channels=${this._channels_latest !== JSON.stringify(Object.keys(this.channels_latest))}, private=${this._private_messages !== JSON.stringify([this.private_messages, this.grouped_private_messages])},${this.private_messages?.length},${Object.keys(this.grouped_private_messages ?? {}).length})`
|
`loading messages for ${this.whoami} (following ${this.following.length})`
|
||||||
);
|
);
|
||||||
this.load_messages();
|
this.load_messages();
|
||||||
}
|
}
|
||||||
@@ -492,16 +350,9 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
if (!this.hash.startsWith('#%')) {
|
if (!this.hash.startsWith('#%')) {
|
||||||
more = html`
|
more = html`
|
||||||
<p>
|
<p>
|
||||||
${this.unread_allowed()
|
<button class="w3-button w3-theme-d1" @click=${this.mark_all_read}>
|
||||||
? html`
|
Mark All Read
|
||||||
<button
|
</button>
|
||||||
class="w3-button w3-theme-d1"
|
|
||||||
@click=${this.mark_all_read}
|
|
||||||
>
|
|
||||||
Mark All Read
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: undefined}
|
|
||||||
<button
|
<button
|
||||||
?disabled=${this.loading}
|
?disabled=${this.loading}
|
||||||
class="w3-button w3-theme-d1"
|
class="w3-button w3-theme-d1"
|
||||||
@@ -533,18 +384,9 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return cache(html`
|
return cache(html`
|
||||||
<style>
|
<button class="w3-button w3-theme-d1" @click=${this.mark_all_read}>
|
||||||
${generate_theme()}
|
Mark All Read
|
||||||
</style>
|
</button>
|
||||||
${this.unread_allowed()
|
|
||||||
? html`<button
|
|
||||||
class="w3-button w3-theme-d1"
|
|
||||||
@click=${this.mark_all_read}
|
|
||||||
>
|
|
||||||
Mark All Read
|
|
||||||
</button>`
|
|
||||||
: undefined}
|
|
||||||
${this.render_close_chat_button()}
|
|
||||||
<tf-news
|
<tf-news
|
||||||
id="news"
|
id="news"
|
||||||
whoami=${this.whoami}
|
whoami=${this.whoami}
|
||||||
@@ -553,11 +395,8 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
.following=${this.following}
|
.following=${this.following}
|
||||||
.drafts=${this.drafts}
|
.drafts=${this.drafts}
|
||||||
.expanded=${this.expanded}
|
.expanded=${this.expanded}
|
||||||
hash=${this.hash}
|
|
||||||
channel=${this.channel()}
|
channel=${this.channel()}
|
||||||
channel_unread=${this.channels_unread?.[this.channel()]}
|
channel_unread=${this.channels_unread?.[this.channel()]}
|
||||||
.recent_reactions=${this.recent_reactions}
|
|
||||||
@mark_all_read=${this.mark_all_read}
|
|
||||||
></tf-news>
|
></tf-news>
|
||||||
${more}
|
${more}
|
||||||
`);
|
`);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
until,
|
until,
|
||||||
} from './lit-all.min.js';
|
} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabNewsElement extends LitElement {
|
class TfTabNewsElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -24,12 +24,6 @@ class TfTabNewsElement extends LitElement {
|
|||||||
channels_latest: {type: Object},
|
channels_latest: {type: Object},
|
||||||
connections: {type: Array},
|
connections: {type: Array},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
grouped_private_messages: {type: Object},
|
|
||||||
visible_private_messages: {type: Object},
|
|
||||||
recent_reactions: {type: Array},
|
|
||||||
peer_exchange: {type: Boolean},
|
|
||||||
is_administrator: {type: Boolean},
|
|
||||||
stay_connected: {type: Boolean},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,11 +43,9 @@ class TfTabNewsElement extends LitElement {
|
|||||||
this.channels_latest = {};
|
this.channels_latest = {};
|
||||||
this.channels = [];
|
this.channels = [];
|
||||||
this.connections = [];
|
this.connections = [];
|
||||||
this.recent_reactions = [];
|
|
||||||
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
|
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
|
||||||
self.drafts = JSON.parse(d || '{}');
|
self.drafts = JSON.parse(d || '{}');
|
||||||
});
|
});
|
||||||
this.check_peer_exchange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
@@ -66,14 +58,6 @@ class TfTabNewsElement extends LitElement {
|
|||||||
document.body.removeEventListener('keypress', this.on_keypress.bind(this));
|
document.body.removeEventListener('keypress', this.on_keypress.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
async check_peer_exchange() {
|
|
||||||
if (await tfrpc.rpc.isAdministrator()) {
|
|
||||||
this.peer_exchange = await tfrpc.rpc.globalSettingsGet('peer_exchange');
|
|
||||||
} else {
|
|
||||||
this.peer_exchange = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
load_latest() {
|
load_latest() {
|
||||||
let news = this.shadowRoot?.getElementById('news');
|
let news = this.shadowRoot?.getElementById('news');
|
||||||
if (news) {
|
if (news) {
|
||||||
@@ -111,26 +95,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unread_status(channel) {
|
unread_status(channel) {
|
||||||
if (channel === undefined) {
|
if (
|
||||||
if (
|
|
||||||
Object.keys(this.channels_unread).some((x) => this.unread_status(x))
|
|
||||||
) {
|
|
||||||
return '✉️ ';
|
|
||||||
}
|
|
||||||
} else if (channel?.startsWith('🔐')) {
|
|
||||||
let key = JSON.stringify(channel.substring('🔐'.length).split(','));
|
|
||||||
if (this.grouped_private_messages?.[key]) {
|
|
||||||
let grouped_latest = Math.max(
|
|
||||||
...this.grouped_private_messages?.[key]?.map((x) => x.rowid)
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
this.channels_unread[channel] === undefined ||
|
|
||||||
grouped_latest > this.channels_unread[channel]
|
|
||||||
) {
|
|
||||||
return '✉️ ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
this.channels_latest[channel] &&
|
this.channels_latest[channel] &&
|
||||||
this.channels_latest[channel] > 0 &&
|
this.channels_latest[channel] > 0 &&
|
||||||
(this.channels_unread[channel] === undefined ||
|
(this.channels_unread[channel] === undefined ||
|
||||||
@@ -171,8 +136,11 @@ class TfTabNewsElement extends LitElement {
|
|||||||
return this.hash.startsWith('##') ? this.hash.substring(2) : undefined;
|
return this.hash.startsWith('##') ? this.hash.substring(2) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
compare_follows(a, b) {
|
compare_follows() {
|
||||||
return b[1].ts > a[1].ts ? 1 : b[1].ts < a[1].ts ? -1 : 0;
|
const now = new Date().valueOf();
|
||||||
|
return function (a, b) {
|
||||||
|
return (b[1].ts > now ? -1 : b[1].ts) - (a[1].ts > now ? -1 : a[1].ts);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
suggested_follows() {
|
suggested_follows() {
|
||||||
@@ -181,24 +149,13 @@ class TfTabNewsElement extends LitElement {
|
|||||||
** pinned at the top.
|
** pinned at the top.
|
||||||
*/
|
*/
|
||||||
let self = this;
|
let self = this;
|
||||||
let now = new Date().valueOf();
|
|
||||||
return Object.entries(this.users)
|
return Object.entries(this.users)
|
||||||
.filter((x) => x[1].ts < now)
|
|
||||||
.filter((x) => x[1].follow_depth > 1)
|
.filter((x) => x[1].follow_depth > 1)
|
||||||
.sort(self.compare_follows)
|
.sort(self.compare_follows())
|
||||||
.slice(0, 8)
|
.slice(0, 8)
|
||||||
.map((x) => x[0]);
|
.map((x) => x[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async enable_peer_exchange() {
|
|
||||||
await tfrpc.rpc.globalSettingsSet('peer_exchange', true);
|
|
||||||
await this.check_peer_exchange();
|
|
||||||
}
|
|
||||||
|
|
||||||
is_loading() {
|
|
||||||
return this.shadowRoot?.getElementById('news')?.loading;
|
|
||||||
}
|
|
||||||
|
|
||||||
render_sidebar() {
|
render_sidebar() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
@@ -220,7 +177,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
href="#"
|
href="#"
|
||||||
class="w3-bar-item w3-button"
|
class="w3-bar-item w3-button"
|
||||||
style="font-weight: bold"
|
style="font-weight: bold"
|
||||||
>${this.hash.substring(1)}</a
|
>${this.hash.substring(2)}</a
|
||||||
>
|
>
|
||||||
`
|
`
|
||||||
: undefined}
|
: undefined}
|
||||||
@@ -238,34 +195,11 @@ class TfTabNewsElement extends LitElement {
|
|||||||
>${this.unread_status('@')}@mentions</a
|
>${this.unread_status('@')}@mentions</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="#👍"
|
href="#🔐"
|
||||||
class="w3-bar-item w3-button"
|
class="w3-bar-item w3-button"
|
||||||
style=${this.hash == '#👍' ? 'font-weight: bold' : undefined}
|
style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined}
|
||||||
>${this.unread_status('👍')}👍votes</a
|
>${this.unread_status('🔐')}🔐private</a
|
||||||
>
|
>
|
||||||
${Object.keys(this?.visible_private_messages ?? [])
|
|
||||||
?.sort()
|
|
||||||
?.map(
|
|
||||||
(key) => html`
|
|
||||||
<a
|
|
||||||
href=${'#🔐' + JSON.parse(key).join(',')}
|
|
||||||
class="w3-bar-item w3-button"
|
|
||||||
style=${this.hash == '#🔐' + JSON.parse(key).join(',')
|
|
||||||
? 'font-weight: bold'
|
|
||||||
: undefined}
|
|
||||||
>${this.unread_status('🔐' + JSON.parse(key).join(','))}
|
|
||||||
${(key != '[]' ? JSON.parse(key) : [this.whoami]).map(
|
|
||||||
(id) => html`
|
|
||||||
<tf-user
|
|
||||||
id=${id}
|
|
||||||
nolink="true"
|
|
||||||
.users=${this.users}
|
|
||||||
></tf-user>
|
|
||||||
`
|
|
||||||
)}</a
|
|
||||||
>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
${Object.keys(this.drafts)
|
${Object.keys(this.drafts)
|
||||||
.sort()
|
.sort()
|
||||||
.map(
|
.map(
|
||||||
@@ -289,62 +223,15 @@ class TfTabNewsElement extends LitElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<a class="w3-bar-item w3-theme-d2 w3-button" href="#connections">
|
<h4 class="w3-bar-item w3-theme-d2">Connections</h4>
|
||||||
<h4 style="margin: 0">Connections</h4>
|
|
||||||
</a>
|
|
||||||
${this.connections?.filter((x) => x.id)?.length == 0
|
|
||||||
? html`
|
|
||||||
<button
|
|
||||||
class=${'w3-bar-item w3-button' +
|
|
||||||
(this.connections?.some((x) => x.flags.one_shot)
|
|
||||||
? ' w3-spin'
|
|
||||||
: '')}
|
|
||||||
@click=${() =>
|
|
||||||
this.dispatchEvent(
|
|
||||||
new Event('refresh', {bubbles: true, composed: true})
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
↻ Sync now
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="w3-bar-item w3-button w3-ripple"
|
|
||||||
@click=${() =>
|
|
||||||
this.dispatchEvent(
|
|
||||||
new Event('toggle_stay_connected', {
|
|
||||||
bubbles: true,
|
|
||||||
composed: true,
|
|
||||||
})
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span style="display: inline-block; width: 1.8em"
|
|
||||||
>${this.stay_connected ? '🔗' : '⛓️💥'}</span
|
|
||||||
>
|
|
||||||
${this.stay_connected ? 'Online mode' : 'Passive mode'}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class=${'w3-bar-item w3-button w3-border w3-leftbar w3-rightbar' +
|
|
||||||
(this.peer_exchange !== false ? ' w3-hide' : '')}
|
|
||||||
@click=${this.enable_peer_exchange}
|
|
||||||
>
|
|
||||||
🔍🌐 Use publicly advertised peers
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: undefined}
|
|
||||||
${this.connections
|
${this.connections
|
||||||
.filter((x) => x.id)
|
.filter((x) => x.id && !x.destroy_reason)
|
||||||
.map(
|
.map(
|
||||||
(x) => html`
|
(x) => html`
|
||||||
<tf-user
|
<tf-user
|
||||||
class="w3-bar-item"
|
class="w3-bar-item"
|
||||||
style=${x.destroy_reason
|
style="max-width: 100%"
|
||||||
? 'border-left: 4px solid red; border-right: 4px solid red'
|
|
||||||
: x.connected
|
|
||||||
? x.flags?.one_shot
|
|
||||||
? 'border-left: 4px solid blue; border-right: 4px solid blue'
|
|
||||||
: 'border-left: 4px solid green; border-right: 4px solid green'
|
|
||||||
: ''}
|
|
||||||
id=${x.id}
|
id=${x.id}
|
||||||
fallback_name=${x.host}
|
|
||||||
.users=${this.users}
|
.users=${this.users}
|
||||||
></tf-user>
|
></tf-user>
|
||||||
`
|
`
|
||||||
@@ -396,12 +283,9 @@ class TfTabNewsElement extends LitElement {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
return cache(html`
|
return cache(html`
|
||||||
<style>
|
|
||||||
${generate_theme()}
|
|
||||||
</style>
|
|
||||||
${this.render_sidebar()}
|
${this.render_sidebar()}
|
||||||
<div
|
<div
|
||||||
style="margin-left: 2in; padding: 0px; top: 0; height: 100vh; max-height: 100%; overflow: auto; contain: layout"
|
style="margin-left: 2in; padding: 0px; top: 0; max-height: 100%; overflow: auto"
|
||||||
id="main"
|
id="main"
|
||||||
class="w3-main"
|
class="w3-main"
|
||||||
>
|
>
|
||||||
@@ -426,14 +310,9 @@ class TfTabNewsElement extends LitElement {
|
|||||||
class="w3-button w3-hide-large"
|
class="w3-button w3-hide-large"
|
||||||
@click=${this.show_sidebar}
|
@click=${this.show_sidebar}
|
||||||
>
|
>
|
||||||
${this.unread_status()}☰
|
☰
|
||||||
</div>
|
</div>
|
||||||
<span
|
Welcome, <tf-user id=${this.whoami} .users=${this.users}></tf-user>!
|
||||||
style="display: inline-block; width: 100%; max-width: 100%; white-space: nowrap; overflow: hidden"
|
|
||||||
>
|
|
||||||
Welcome,
|
|
||||||
<tf-user id=${this.whoami} .users=${this.users}></tf-user>!
|
|
||||||
</span>
|
|
||||||
${edit_profile}
|
${edit_profile}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -444,9 +323,6 @@ class TfTabNewsElement extends LitElement {
|
|||||||
.drafts=${this.drafts}
|
.drafts=${this.drafts}
|
||||||
@tf-draft=${this.draft}
|
@tf-draft=${this.draft}
|
||||||
.channel=${this.channel()}
|
.channel=${this.channel()}
|
||||||
.recipients=${this.hash.startsWith('#🔐')
|
|
||||||
? this.hash.substring('#🔐'.length).split(',')
|
|
||||||
: undefined}
|
|
||||||
></tf-compose>
|
></tf-compose>
|
||||||
</div>
|
</div>
|
||||||
${profile}
|
${profile}
|
||||||
@@ -463,8 +339,6 @@ class TfTabNewsElement extends LitElement {
|
|||||||
.channels_unread=${this.channels_unread}
|
.channels_unread=${this.channels_unread}
|
||||||
.channels_latest=${this.channels_latest}
|
.channels_latest=${this.channels_latest}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
.grouped_private_messages=${this.grouped_private_messages}
|
|
||||||
.recent_reactions=${this.recent_reactions}
|
|
||||||
></tf-tab-news-feed>
|
></tf-tab-news-feed>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
136
apps/ssb/tf-tab-query.js
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
|
class TfTabQueryElement extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
whoami: {type: String},
|
||||||
|
users: {type: Object},
|
||||||
|
following: {type: Array},
|
||||||
|
query: {type: String},
|
||||||
|
expanded: {type: Object},
|
||||||
|
results: {type: Array},
|
||||||
|
error: {type: Object},
|
||||||
|
duration: {type: Number},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = styles;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
let self = this;
|
||||||
|
this.whoami = null;
|
||||||
|
this.users = {};
|
||||||
|
this.following = [];
|
||||||
|
this.expanded = {};
|
||||||
|
this.duration = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async search(query) {
|
||||||
|
console.log('Searching...', this.whoami, query);
|
||||||
|
this.results = [];
|
||||||
|
this.error = undefined;
|
||||||
|
this.duration = undefined;
|
||||||
|
let search = this.renderRoot.getElementById('search');
|
||||||
|
if (search) {
|
||||||
|
search.value = query;
|
||||||
|
search.focus();
|
||||||
|
}
|
||||||
|
await tfrpc.rpc.setHash('#sql=' + encodeURIComponent(query));
|
||||||
|
let start_time = new Date();
|
||||||
|
try {
|
||||||
|
this.results = await tfrpc.rpc.query(query, []);
|
||||||
|
} catch (error) {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
let end_time = new Date();
|
||||||
|
this.duration = (end_time - start_time).valueOf();
|
||||||
|
console.log('Done.');
|
||||||
|
search = this.renderRoot.getElementById('search');
|
||||||
|
if (search) {
|
||||||
|
search.value = query;
|
||||||
|
search.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
search_keydown(event) {
|
||||||
|
if (event.keyCode == 13 && event.ctrlKey) {
|
||||||
|
this.query = this.renderRoot.getElementById('search').value;
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on_expand(event) {
|
||||||
|
if (event.detail.expanded) {
|
||||||
|
let expand = {};
|
||||||
|
expand[event.detail.id] = true;
|
||||||
|
this.expanded = Object.assign({}, this.expanded, expand);
|
||||||
|
} else {
|
||||||
|
delete this.expanded[event.detail.id];
|
||||||
|
this.expanded = Object.assign({}, this.expanded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render_results() {
|
||||||
|
if (!this.results?.length) {
|
||||||
|
return html`<div>No results.</div>`;
|
||||||
|
} else {
|
||||||
|
let keys = Object.keys(this.results[0]).sort();
|
||||||
|
return html`<table style="width: 100%; max-width: 100%">
|
||||||
|
<tr>
|
||||||
|
${keys.map((key) => html`<th>${key}</th>`)}
|
||||||
|
</tr>
|
||||||
|
${this.results.map(
|
||||||
|
(row) =>
|
||||||
|
html`<tr>
|
||||||
|
${keys.map((key) => html`<td>${row[key]}</td>`)}
|
||||||
|
</tr>`
|
||||||
|
)}
|
||||||
|
</table>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render_error() {
|
||||||
|
if (this.error) {
|
||||||
|
return html`<h2 style="color: red">${this.error.message}</h2>
|
||||||
|
<pre style="color: red">${this.error.stack}</pre>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.query !== this.last_query) {
|
||||||
|
this.last_query = this.query;
|
||||||
|
this.search(this.query);
|
||||||
|
}
|
||||||
|
let self = this;
|
||||||
|
return html`
|
||||||
|
<div style="display: flex; flex-direction: row; gap: 4px">
|
||||||
|
<textarea
|
||||||
|
id="search"
|
||||||
|
rows="8"
|
||||||
|
class="w3-input w3-theme-d1"
|
||||||
|
style="flex: 1; resize: vertical"
|
||||||
|
@keydown=${this.search_keydown}
|
||||||
|
>
|
||||||
|
${this.query}</textarea
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="w3-button w3-theme-d1"
|
||||||
|
@click=${(event) =>
|
||||||
|
self.search(self.renderRoot.getElementById('search').value)}
|
||||||
|
>
|
||||||
|
Execute
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div ?hidden=${this.duration === undefined}>
|
||||||
|
Took ${this.duration / 1000.0} seconds.
|
||||||
|
</div>
|
||||||
|
<div ?hidden=${this.duration !== undefined}>Executing...</div>
|
||||||
|
${this.render_error()} ${this.render_results()}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('tf-tab-query', TfTabQueryElement);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabSearchElement extends LitElement {
|
class TfTabSearchElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -11,9 +11,6 @@ class TfTabSearchElement extends LitElement {
|
|||||||
following: {type: Array},
|
following: {type: Array},
|
||||||
query: {type: String},
|
query: {type: String},
|
||||||
expanded: {type: Object},
|
expanded: {type: Object},
|
||||||
messages: {type: Array},
|
|
||||||
results: {type: Array},
|
|
||||||
error: {type: Object},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,40 +38,24 @@ class TfTabSearchElement extends LitElement {
|
|||||||
search.select();
|
search.select();
|
||||||
}
|
}
|
||||||
await tfrpc.rpc.setHash('#q=' + encodeURIComponent(query));
|
await tfrpc.rpc.setHash('#q=' + encodeURIComponent(query));
|
||||||
this.error = undefined;
|
let results = await tfrpc.rpc.query(
|
||||||
this.results = [];
|
`
|
||||||
this.messages = [];
|
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
if (query.startsWith('sql:')) {
|
FROM messages_fts(?)
|
||||||
this.messages = [];
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||||
try {
|
JOIN json_each(?) AS following ON messages.author = following.value
|
||||||
this.results = await tfrpc.rpc.query(
|
ORDER BY timestamp DESC limit 100
|
||||||
query.substring('sql:'.length),
|
`,
|
||||||
[]
|
['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)]
|
||||||
);
|
);
|
||||||
} catch (e) {
|
console.log('Done.');
|
||||||
this.results = [];
|
search = this.renderRoot.getElementById('search');
|
||||||
this.error = e;
|
if (search) {
|
||||||
}
|
search.value = query;
|
||||||
} else {
|
search.focus();
|
||||||
let results = await tfrpc.rpc.query(
|
search.select();
|
||||||
`
|
|
||||||
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
|
||||||
FROM messages_fts(?)
|
|
||||||
JOIN messages ON messages.rowid = messages_fts.rowid
|
|
||||||
JOIN json_each(?) AS following ON messages.author = following.value
|
|
||||||
ORDER BY timestamp DESC limit 100
|
|
||||||
`,
|
|
||||||
['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)]
|
|
||||||
);
|
|
||||||
console.log('Done.');
|
|
||||||
search = this.renderRoot.getElementById('search');
|
|
||||||
if (search) {
|
|
||||||
search.value = query;
|
|
||||||
search.focus();
|
|
||||||
search.select();
|
|
||||||
}
|
|
||||||
this.messages = results;
|
|
||||||
}
|
}
|
||||||
|
this.renderRoot.getElementById('news').messages = results;
|
||||||
}
|
}
|
||||||
|
|
||||||
search_keydown(event) {
|
search_keydown(event) {
|
||||||
@@ -106,39 +87,6 @@ class TfTabSearchElement extends LitElement {
|
|||||||
tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts));
|
tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts));
|
||||||
}
|
}
|
||||||
|
|
||||||
render_results() {
|
|
||||||
if (this.error) {
|
|
||||||
return html`<h2 style="color: red">${this.error.message}</h2>
|
|
||||||
<pre style="color: red">${this.error.stack}</pre>`;
|
|
||||||
} else if (this.messages?.length) {
|
|
||||||
return html`<tf-news
|
|
||||||
id="news"
|
|
||||||
whoami=${this.whoami}
|
|
||||||
.messages=${this.messages}
|
|
||||||
.users=${this.users}
|
|
||||||
.expanded=${this.expanded}
|
|
||||||
.drafts=${this.drafts}
|
|
||||||
@tf-expand=${this.on_expand}
|
|
||||||
@tf-draft=${this.draft}
|
|
||||||
></tf-news>`;
|
|
||||||
} else if (this.results?.length) {
|
|
||||||
let keys = Object.keys(this.results[0]).sort();
|
|
||||||
return html`<table style="width: 100%; max-width: 100%">
|
|
||||||
<tr>
|
|
||||||
${keys.map((key) => html`<th>${key}</th>`)}
|
|
||||||
</tr>
|
|
||||||
${this.results.map(
|
|
||||||
(row) =>
|
|
||||||
html`<tr>
|
|
||||||
${keys.map((key) => html`<td>${row[key]}</td>`)}
|
|
||||||
</tr>`
|
|
||||||
)}
|
|
||||||
</table>`;
|
|
||||||
} else {
|
|
||||||
return html`<div>No results.</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.query !== this.last_query) {
|
if (this.query !== this.last_query) {
|
||||||
this.last_query = this.query;
|
this.last_query = this.query;
|
||||||
@@ -146,14 +94,11 @@ class TfTabSearchElement extends LitElement {
|
|||||||
}
|
}
|
||||||
let self = this;
|
let self = this;
|
||||||
return html`
|
return html`
|
||||||
<style>${generate_theme()}</style>
|
<div style="display: flex; flex-direction: row; gap: 4px">
|
||||||
<div class="w3-padding">
|
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>
|
||||||
<div style="display: flex; flex-direction: row; gap: 4px">
|
<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button>
|
||||||
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>
|
|
||||||
<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button>
|
|
||||||
</div>
|
|
||||||
${this.render_results()}
|
|
||||||
</div>
|
</div>
|
||||||
|
<tf-news id="news" whoami=${this.whoami} .messages=${this.messages} .users=${this.users} .expanded=${this.expanded} .drafts=${this.drafts} @tf-expand=${this.on_expand} @tf-draft=${this.draft}></tf-news>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTagElement extends LitElement {
|
class TfTagElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -17,15 +17,11 @@ class TfTagElement extends LitElement {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
let number = this.count ? html` (${this.count})` : undefined;
|
let number = this.count ? html` (${this.count})` : undefined;
|
||||||
return html`
|
return html`<a
|
||||||
<style>
|
href=${'#' + encodeURIComponent(this.tag)}
|
||||||
${generate_theme()}</style
|
class="w3-tag w3-theme-d1 w3-round-4 w3-button"
|
||||||
><a
|
>${this.tag}${number}</a
|
||||||
href=${'#' + encodeURIComponent(this.tag)}
|
> `;
|
||||||
class="w3-tag w3-theme-d1 w3-round-4 w3-button"
|
|
||||||
>${this.tag}${number}</a
|
|
||||||
>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import {LitElement, html} from './lit-all.min.js';
|
import {LitElement, html} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles, generate_theme} from './tf-styles.js';
|
import {styles} from './tf-styles.js';
|
||||||
|
|
||||||
class TfUserElement extends LitElement {
|
class TfUserElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
id: {type: String},
|
id: {type: String},
|
||||||
fallback_name: {type: String},
|
|
||||||
icon_only: {type: Boolean},
|
|
||||||
users: {type: Object},
|
users: {type: Object},
|
||||||
nolink: {type: Boolean},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,8 +15,6 @@ class TfUserElement extends LitElement {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.id = null;
|
this.id = null;
|
||||||
this.fallback_name = null;
|
|
||||||
this.icon_only = false;
|
|
||||||
this.users = {};
|
this.users = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,38 +30,27 @@ class TfUserElement extends LitElement {
|
|||||||
>😎</span
|
>😎</span
|
||||||
>`;
|
>`;
|
||||||
let name = this.users?.[this.id]?.name;
|
let name = this.users?.[this.id]?.name;
|
||||||
let name_string = name ?? this.fallback_name ?? this.id;
|
name = html`<a target="_top" href=${'#' + this.id}
|
||||||
name = this.icon_only
|
>${name !== undefined ? name : this.id}</a
|
||||||
? undefined
|
>`;
|
||||||
: !this.nolink
|
|
||||||
? html`<a target="_top" href=${'#' + this.id}>${name_string}</a>`
|
|
||||||
: html`<span>${name_string}</span>`;
|
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
let image_link = user.image;
|
let image_link = user.image;
|
||||||
if (typeof image_link == 'string' && !image_link.startsWith('&')) {
|
image_link =
|
||||||
try {
|
typeof image_link == 'string' ? image_link : image_link?.link;
|
||||||
image_link = JSON.parse(image_link)?.link;
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
if (image_link !== undefined) {
|
if (image_link !== undefined) {
|
||||||
image = html`<img
|
image = html`<img
|
||||||
class=${'w3-theme-l4 ' + shape}
|
class=${'w3-theme-l4 ' + shape}
|
||||||
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover"
|
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover"
|
||||||
src="/${image_link}/view"
|
src="/${image_link}/view"
|
||||||
title=${name_string + ' (' + this.id + ')'}
|
|
||||||
/>`;
|
/>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return html` <style>
|
return html` <div
|
||||||
${generate_theme()}
|
style="display: inline-block; vertical-align: middle; font-weight: bold; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis"
|
||||||
</style>
|
>
|
||||||
<div
|
${image} ${name}
|
||||||
style=${'display: inline-block; vertical-align: middle; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis' +
|
</div>`;
|
||||||
(this.nolink ? '' : '; font-weight: bold')}
|
|
||||||
>
|
|
||||||
${image} ${name}
|
|
||||||
</div>`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ function image(node, entering) {
|
|||||||
'</div>'
|
'</div>'
|
||||||
);
|
);
|
||||||
if (this.options.safe && potentiallyUnsafe(node.destination)) {
|
if (this.options.safe && potentiallyUnsafe(node.destination)) {
|
||||||
this.lit('<img src="" title="');
|
this.lit('<img src="" alt="');
|
||||||
} else {
|
} else {
|
||||||
this.lit('<img src="' + this.esc(node.destination) + '" title="');
|
this.lit('<img src="' + this.esc(node.destination) + '" alt="');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.disableTags += 1;
|
this.disableTags += 1;
|
||||||
@@ -104,12 +104,12 @@ export function markdown(md) {
|
|||||||
node.destination.startsWith('@') &&
|
node.destination.startsWith('@') &&
|
||||||
node.destination.endsWith('.ed25519')
|
node.destination.endsWith('.ed25519')
|
||||||
) {
|
) {
|
||||||
node.destination = '#' + encodeURIComponent(node.destination);
|
node.destination = '#' + node.destination;
|
||||||
} else if (
|
} else if (
|
||||||
node.destination.startsWith('%') &&
|
node.destination.startsWith('%') &&
|
||||||
node.destination.endsWith('.sha256')
|
node.destination.endsWith('.sha256')
|
||||||
) {
|
) {
|
||||||
node.destination = '#' + encodeURIComponent(node.destination);
|
node.destination = '#' + node.destination;
|
||||||
} else if (
|
} else if (
|
||||||
node.destination.startsWith('&') &&
|
node.destination.startsWith('&') &&
|
||||||
node.destination.endsWith('.sha256')
|
node.destination.endsWith('.sha256')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "💾",
|
"emoji": "💾",
|
||||||
"previous": "&tzZFIe7Y54O4sx1QtAPdemkXh+p5qHXSG/dlS7NP6OQ=.sha256"
|
"previous": "&mvGTlWKFR5QM/3nb4fJ2WQq0n/gNKvBmhGDkAvb8ki8=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ async function query(sql, args) {
|
|||||||
|
|
||||||
async function get_biggest() {
|
async function get_biggest() {
|
||||||
return query(`
|
return query(`
|
||||||
select author, size from messages_stats group by author order by size desc limit 10;
|
select author, sum(length(content)) as size from messages group by author order by size desc limit 10;
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,14 +62,15 @@ function nice_size(bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
await app.setDocument('<p style="color: #fff">Analyzing feeds...</p>');
|
await app.setDocument(
|
||||||
let most_follows = get_most_follows();
|
'<p style="color: #fff">Finding the top 10 largest feeds...</p>'
|
||||||
|
);
|
||||||
|
let most_follows = await get_most_follows();
|
||||||
let total = await get_total();
|
let total = await get_total();
|
||||||
let identities = await ssb.getAllIdentities();
|
let identities = await ssb.getAllIdentities();
|
||||||
let following1 = await ssb.following(identities, 1);
|
let following1 = await ssb.following(identities, 1);
|
||||||
let following2 = await ssb.following(identities, 2);
|
let following2 = await ssb.following(identities, 2);
|
||||||
let biggest = await get_biggest();
|
let biggest = await get_biggest();
|
||||||
most_follows = await most_follows;
|
|
||||||
let names = await get_names(
|
let names = await get_names(
|
||||||
[].concat(
|
[].concat(
|
||||||
biggest.map((x) => x.author),
|
biggest.map((x) => x.author),
|
||||||
@@ -93,7 +94,7 @@ async function main() {
|
|||||||
}
|
}
|
||||||
let html = `<body style="color: #000; background-color: #ddd">\n
|
let html = `<body style="color: #000; background-color: #ddd">\n
|
||||||
<h1>Storage Summary</h1>
|
<h1>Storage Summary</h1>
|
||||||
<h2>Top Accounts by Size</h2>
|
<h2>Top 10 Accounts by Size</h2>
|
||||||
<ol>`;
|
<ol>`;
|
||||||
for (let item of biggest) {
|
for (let item of biggest) {
|
||||||
html += `<li>
|
html += `<li>
|
||||||
@@ -104,7 +105,7 @@ async function main() {
|
|||||||
}
|
}
|
||||||
html += `
|
html += `
|
||||||
</ol>
|
</ol>
|
||||||
<h2>Top Accounts by Follows</h2>
|
<h2>Top 10 Accounts by Follows</h2>
|
||||||
<ol>`;
|
<ol>`;
|
||||||
for (let item of most_follows) {
|
for (let item of most_follows) {
|
||||||
html += `<li>
|
html += `<li>
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "tildefriends-app",
|
|
||||||
"emoji": "📦",
|
|
||||||
"previous": "&mhBOscDHiJ4VNnod27NOdRVC+4cXYZXIdYjsQBfmTYg=.sha256"
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
async function main() {
|
|
||||||
let speedscope_js = await utf8Decode(
|
|
||||||
getFile('speedscope/speedscope-432XE7GS.js')
|
|
||||||
);
|
|
||||||
speedscope_js = speedscope_js.replace(/alert\(`Cannot load.*?return/, '');
|
|
||||||
app.setDocument(`
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<title>speedscope</title>
|
|
||||||
<link rel="stylesheet" href="speedscope/speedscope-GHPHNKXC.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script>
|
|
||||||
delete window.localStorage;
|
|
||||||
window.location.hash = '#profileURL=${core.url}../../trace';
|
|
||||||
</script>
|
|
||||||
<script>${speedscope_js}</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
speedscope@1.24.0
|
|
||||||
Mon Oct 20 18:11:29 PDT 2025
|
|
||||||
fc76932551754a442cd5c4f0afdba28032d14d8a
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "tildefriends-app",
|
|
||||||
"emoji": "🕸",
|
|
||||||
"previous": "&n7hu5b8/TsfiG6FDlCRG5nPCrIdCr96+xpIJ/aQT/uM=.sha256"
|
|
||||||
}
|
|
||||||
100
apps/web/app.js
@@ -1,100 +0,0 @@
|
|||||||
let g_hash;
|
|
||||||
|
|
||||||
async function query(sql, params) {
|
|
||||||
let results = [];
|
|
||||||
await ssb.sqlAsync(sql, params, function (row) {
|
|
||||||
results.push(row);
|
|
||||||
});
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolve(id) {
|
|
||||||
try {
|
|
||||||
let blob = await ssb.blobGet(id);
|
|
||||||
if (blob) {
|
|
||||||
let json;
|
|
||||||
try {
|
|
||||||
json = JSON.parse(utf8Decode(blob));
|
|
||||||
} catch {
|
|
||||||
return {id: utf8Decode(blob)};
|
|
||||||
}
|
|
||||||
if (json?.links) {
|
|
||||||
for (let [key, value] of Object.entries(json.links)) {
|
|
||||||
json.links[key] = await resolve(value);
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
} else {
|
|
||||||
return 'huh?' + json;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return `missing<${id}>`;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return id + ': ' + e.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function get_names(identities) {
|
|
||||||
return Object.fromEntries(
|
|
||||||
(
|
|
||||||
await query(
|
|
||||||
`
|
|
||||||
SELECT author, name FROM (
|
|
||||||
SELECT
|
|
||||||
messages.author,
|
|
||||||
RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank,
|
|
||||||
messages.content ->> 'name' AS name
|
|
||||||
FROM messages
|
|
||||||
JOIN json_each(?) AS identities ON identities.value = messages.author
|
|
||||||
WHERE
|
|
||||||
json_extract(messages.content, '$.type') = 'about' AND
|
|
||||||
content ->> 'about' = messages.author AND name IS NOT NULL)
|
|
||||||
WHERE author_rank = 1
|
|
||||||
`,
|
|
||||||
[JSON.stringify(identities)]
|
|
||||||
)
|
|
||||||
).map((x) => [x.author, x.name])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function render(hash) {
|
|
||||||
g_hash = hash;
|
|
||||||
if (!hash) {
|
|
||||||
let sites = await query(
|
|
||||||
`
|
|
||||||
SELECT site.author, site.id
|
|
||||||
FROM messages site
|
|
||||||
WHERE site.content ->> 'type' = 'web-init'
|
|
||||||
`,
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
let names = await get_names(sites.map((x) => x.author));
|
|
||||||
if (hash === g_hash) {
|
|
||||||
await app.setDocument(
|
|
||||||
`<ul style="background-color: #ddd">${sites.map((x) => `<li><a target="_top" href="#${encodeURIComponent(x.id)}">${names[x.author] ?? x.author} - ${x.id}</a></li>`).join('\n')}</ul>`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let site_id =
|
|
||||||
hash.charAt(0) == '#'
|
|
||||||
? decodeURIComponent(hash.substring(1))
|
|
||||||
: decodeURIComponent(hash);
|
|
||||||
await app.setDocument(`<html style="margin: 0; padding: 0; width: 100vw; height: 100vh; margin: 0; padding: 0">
|
|
||||||
<body style="display: flex; flex-direction: column; width: 100vw; height: 100vh">
|
|
||||||
<iframe src="${encodeURIComponent(site_id)}/index.html" style="flex: 1 1; border: 0; background-color: #fff"></iframe>
|
|
||||||
</body>
|
|
||||||
</html>`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
core.register('message', async function message_handler(message) {
|
|
||||||
if (message.event == 'hashChange') {
|
|
||||||
await render(message.hash);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
render(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
async function query(sql, params) {
|
|
||||||
let results = [];
|
|
||||||
await ssb.sqlAsync(sql, params, function (row) {
|
|
||||||
results.push(row);
|
|
||||||
});
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
function guess_content_type(name) {
|
|
||||||
if (name.endsWith('.html')) {
|
|
||||||
return 'text/html; charset=UTF-8';
|
|
||||||
} else if (name.endsWith('.js') || name.endsWith('.mjs')) {
|
|
||||||
return 'text/javascript; charset=UTF-8';
|
|
||||||
} else if (name.endsWith('.css')) {
|
|
||||||
return 'text/stylesheet; charset=UTF-8';
|
|
||||||
} else {
|
|
||||||
return 'application/binary';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
let path = request.path.replaceAll(/(%[0-9a-fA-F]{2})/g, (x) =>
|
|
||||||
String.fromCharCode(parseInt(x.substring(1), 16))
|
|
||||||
);
|
|
||||||
let match = path.match(/^(%.{44}\.sha256)(?:\/)?(.*)$/);
|
|
||||||
|
|
||||||
let content_type = guess_content_type(request.path);
|
|
||||||
let root = await query(
|
|
||||||
`
|
|
||||||
SELECT root.content ->> 'root' AS root
|
|
||||||
FROM messages site
|
|
||||||
JOIN messages root
|
|
||||||
ON site.id = ? AND root.author = site.author AND root.content ->> 'site' = site.id
|
|
||||||
ORDER BY root.sequence DESC LIMIT 1
|
|
||||||
`,
|
|
||||||
[match[1]]
|
|
||||||
);
|
|
||||||
let root_id = root[0]['root'];
|
|
||||||
let last_id = root_id;
|
|
||||||
let blob = await ssb.blobGet(root_id);
|
|
||||||
try {
|
|
||||||
for (let part of match[2]?.split('/')) {
|
|
||||||
let dir = JSON.parse(utf8Decode(blob));
|
|
||||||
last_id = dir?.links[part];
|
|
||||||
blob = await ssb.blobGet(dir?.links[part]);
|
|
||||||
content_type = guess_content_type(part);
|
|
||||||
}
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
respond({
|
|
||||||
status_code: 200,
|
|
||||||
data: blob ? utf8Decode(blob) : `${last_id} not found`,
|
|
||||||
content_type: content_type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(function (e) {
|
|
||||||
respond({
|
|
||||||
status_code: 200,
|
|
||||||
data: `${e.message}\n${e.stack}`,
|
|
||||||
content_type: 'text/plain',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "👋",
|
"emoji": "👋",
|
||||||
"previous": "&n1QkPkB5JoduFSx8UKOY3IlZqS2GwLiTUZv4ZrEOthQ=.sha256"
|
"previous": "&wAb7J6E35xEXpiXsQ6t1RaWTGIvlatUnyH8ipF6pVic=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
5
apps/welcome/app.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
async function main() {
|
||||||
|
await app.setDocument(utf8Decode(getFile('index.html')));
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 640 640" width="32" height="32"><path d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12" style="fill:#fff"/><path d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6M125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1m300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1" style="fill:#609926"/><path d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8s2 16.3 9.1 20c7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3s17.4 1.7 22.5-5.3c5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8z" style="fill:#609926"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 86 KiB |
@@ -28,39 +28,65 @@
|
|||||||
<b>😎 Tilde Friends</b>
|
<b>😎 Tilde Friends</b>
|
||||||
</h1>
|
</h1>
|
||||||
<h1 class="w3-xxlarge w3-text-green">
|
<h1 class="w3-xxlarge w3-text-green">
|
||||||
<b>a Secure Scuttlebutt decentralized social network client</b>
|
<b
|
||||||
|
>the Secure Scuttlebutt decentralized social network client that's
|
||||||
|
<i>fancy🎩</i></b
|
||||||
|
>
|
||||||
</h1>
|
</h1>
|
||||||
<p>
|
<p>
|
||||||
In addition to participating in Secure Scuttlebutt, Tilde Friends is
|
In addition to participating in Secure Scuttlebutt, Tilde Friends is
|
||||||
a platform for building, running, and sharing applications.
|
a platform for building, running, and sharing applications.
|
||||||
</p>
|
</p>
|
||||||
<a
|
<p>
|
||||||
class="w3-button w3-blue w3-padding-large"
|
Available for lots of devices:
|
||||||
href="https://www.tildefriends.net/~core/ssb/"
|
<i class="fa-brands fa-linux w3-xlarge"></i>
|
||||||
>🦀 Try It</a
|
<i class="fa-brands fa-android w3-xlarge"></i>
|
||||||
>
|
<i class="fa-brands fa-apple w3-xlarge"></i>
|
||||||
|
<i class="fa fa-mobile-screen w3-xlarge"></i>
|
||||||
|
<i class="fa-brands fa-windows w3-xlarge"></i>
|
||||||
|
</p>
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-black w3-padding-large"
|
class="w3-button w3-black w3-padding-large"
|
||||||
href="https://dev.tildefriends.net/cory/tildefriends/releases/latest"
|
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||||
><i class="fa fa-download"></i> Download</a
|
><i class="fa fa-download"></i> Download</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-black w3-padding-large"
|
class="w3-button w3-black w3-padding-large"
|
||||||
href="https://dev.tildefriends.net/cory/tildefriends"
|
href="https://www.tildefriends.net/~core/ssb/"
|
||||||
|
><i class="fa fa-link"></i> Try It</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="w3-button w3-black w3-padding-large"
|
||||||
|
href="https://dev.tildefriends.net/"
|
||||||
|
><i class="fa fa-mug-hot"></i> Development</a
|
||||||
>
|
>
|
||||||
<img src="gitea.svg" style="height: 1em; margin: 0" />
|
|
||||||
Development
|
|
||||||
</a>
|
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-black w3-padding-large"
|
class="w3-button w3-black w3-padding-large"
|
||||||
href="https://docs.tildefriends.net/"
|
href="https://docs.tildefriends.net/"
|
||||||
><i class="fa fa-book"></i> Documentation</a
|
><i class="fa fa-book"></i> Documentation</a
|
||||||
>
|
>
|
||||||
<a
|
<p>
|
||||||
class="w3-button w3-black w3-padding-large"
|
<a
|
||||||
href="https://www.tildefriends.net/~cory/tildeblog/"
|
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||||
><i class="fa fa-solid fa-square-rss"></i> Blog</a
|
href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"
|
||||||
>
|
><img src="f-droid.svg" style="height: 2em; margin: 0" /> Get it
|
||||||
|
on F-Droid</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||||
|
href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
|
||||||
|
>
|
||||||
|
<img src="appimage.svg" style="height: 2em; margin: 0" />
|
||||||
|
Get Linux 64-bit AppImage
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||||
|
href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends"
|
||||||
|
>
|
||||||
|
<img src="googleplay.svg" style="height: 2em; margin: 0" />
|
||||||
|
Get it on Google Play (Open Testing)
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-col l4 m6">
|
<div class="w3-col l4 m6">
|
||||||
<img src="tildefriends.png" class="w3-image w3-right w3-hide-small" />
|
<img src="tildefriends.png" class="w3-image w3-right w3-hide-small" />
|
||||||
@@ -78,119 +104,15 @@
|
|||||||
<h2>First-time user checklist:</h2>
|
<h2>First-time user checklist:</h2>
|
||||||
<ol type="1" style="text-align: left">
|
<ol type="1" style="text-align: left">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||||
href="https://dev.tildefriends.net/cory/tildefriends/releases/latest"
|
|
||||||
>Download</a
|
>Download</a
|
||||||
>
|
>
|
||||||
Tilde Friends or use
|
Tilde Friends or use
|
||||||
<a href="https://www.tildefriends.net/"
|
<a href="https://www.tildefriends.net/"
|
||||||
>https://www.tildefriends.net/</a
|
>https://www.tildefriends.net/</a
|
||||||
>.
|
>.
|
||||||
<div class="w3-cell-row">
|
|
||||||
<div class="w3-container w3-cell w3-mobile">
|
|
||||||
<h3>Mobile</h3>
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
|
||||||
href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"
|
|
||||||
><img src="f-droid.svg" style="height: 2em; margin: 0" />
|
|
||||||
Get it on F-Droid</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
|
||||||
href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="googleplay.svg"
|
|
||||||
style="height: 2em; margin: 0"
|
|
||||||
/>
|
|
||||||
Get it on Google Play
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
|
||||||
href="https://testflight.apple.com/join/tXxgtSpE"
|
|
||||||
>
|
|
||||||
<img src="ios.svg" style="height: 2em; margin: 0" />
|
|
||||||
Get it on iOS (TestFlight)
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p>Just launch the app.</p>
|
|
||||||
</div>
|
|
||||||
<div class="w3-container w3-cell w3-mobile">
|
|
||||||
<h3>Web</h3>
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
class="w3-button w3-round-large w3-blue w3-padding-large"
|
|
||||||
href="https://www.tildefriends.net/~core/ssb/"
|
|
||||||
>🦀 Try It</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a href="/login?return=/~core/intro"
|
|
||||||
>Register an account with tildefriends.net</a
|
|
||||||
>
|
|
||||||
to take it for a spin right away.
|
|
||||||
</p>
|
|
||||||
<h3>PeachCloud</h3>
|
|
||||||
<p>
|
|
||||||
Tilde Friends is also a part of 🍑☁️<a
|
|
||||||
href="https://peach-docs.commoninternet.net/"
|
|
||||||
>PeachCloud</a
|
|
||||||
>, which is available on
|
|
||||||
<a href="https://apps.yunohost.org/app/peachpub"
|
|
||||||
>YunoHost</a
|
|
||||||
>
|
|
||||||
for accessible self-hosting.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="w3-container w3-cell w3-mobile">
|
|
||||||
<h3>Desktop</h3>
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
class="w3-button w3-round-large w3-black w3-padding-large"
|
|
||||||
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
|
||||||
><i class="fa fa-download"></i> Download</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="w3-button w3-round-large w3-padding w3-blue-gray"
|
|
||||||
href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
|
|
||||||
>
|
|
||||||
<img src="appimage.svg" style="height: 2em; margin: 0" />
|
|
||||||
Get Linux 64-bit AppImage
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Tilde Friends is distributed as a single executable file (or
|
|
||||||
source that you can
|
|
||||||
<a href="http://dev.tildefriends.net">build yourself</a>)
|
|
||||||
and stores all of its data in a single
|
|
||||||
file(<code>db.sqlite</code>). You can generally download the
|
|
||||||
latest executable from
|
|
||||||
<a
|
|
||||||
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
|
||||||
>releases</a
|
|
||||||
>
|
|
||||||
for your platform, mark it as executable (<code
|
|
||||||
>chmod +x tildefriends*</code
|
|
||||||
>
|
|
||||||
on macOS and Linux), and run. Run with <code>-h</code> to
|
|
||||||
learn more.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Tilde Friends will run in the console and provide a web
|
|
||||||
interface at
|
|
||||||
<a href="http://localhost:12345/">http://localhost:12345/</a
|
|
||||||
>. You will have to register a username and password to sign
|
|
||||||
into your instance.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
After a <a href="/~core/intro">brief introduction</a>, Tilde
|
|
||||||
Friends will take you to the Secure Scuttlebutt social network
|
|
||||||
app.
|
|
||||||
</p>
|
|
||||||
</li>
|
</li>
|
||||||
|
<li>Create an account to identify yourself with that instance.</li>
|
||||||
<li>
|
<li>
|
||||||
Describe yourself in your profile in the <b>ssb</b> app. Give
|
Describe yourself in your profile in the <b>ssb</b> app. Give
|
||||||
yourself a name and an avatar if you like.
|
yourself a name and an avatar if you like.
|
||||||
@@ -224,11 +146,11 @@
|
|||||||
<!-- SSB Section -->
|
<!-- SSB Section -->
|
||||||
<div class="w3-light-grey">
|
<div class="w3-light-grey">
|
||||||
<div class="w3-row-padding w3-padding-64">
|
<div class="w3-row-padding w3-padding-64">
|
||||||
<div class="w3-col l4 m6 s4 w3-center">
|
<div class="w3-col l4 m6 s4">
|
||||||
<a href="https://scuttlebutt.nz/"
|
<a href="https://scuttlebutt.nz/"
|
||||||
><img
|
><img
|
||||||
class="w3-image"
|
class="w3-image w3-round-large"
|
||||||
src="hermietildefriends.svg"
|
src="ssb.png"
|
||||||
alt="Secure Scuttlebutt"
|
alt="Secure Scuttlebutt"
|
||||||
/></a>
|
/></a>
|
||||||
</div>
|
</div>
|
||||||
@@ -298,7 +220,7 @@
|
|||||||
|
|
||||||
<!-- Technlology Section -->
|
<!-- Technlology Section -->
|
||||||
<div class="w3-container w3-padding-64 w3-light-grey w3-center">
|
<div class="w3-container w3-padding-64 w3-light-grey w3-center">
|
||||||
<h1 class="w3-jumbo"><b>Built to Last</b></h1>
|
<h1 class="w3-jumbo"><b>Built the Old Fashioned Way</b></h1>
|
||||||
<p>
|
<p>
|
||||||
Tilde Friends strives to use only simple and widely adopted dependencies
|
Tilde Friends strives to use only simple and widely adopted dependencies
|
||||||
in order to keep it easy to build for all sorts of platforms and
|
in order to keep it easy to build for all sorts of platforms and
|
||||||
@@ -340,6 +262,10 @@
|
|||||||
<i class="fa fa-lock w3-text-purple w3-jumbo"></i>
|
<i class="fa fa-lock w3-text-purple w3-jumbo"></i>
|
||||||
<p>libsodium</p>
|
<p>libsodium</p>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/openssl/openssl/releases" class="w3-col s3">
|
||||||
|
<i class="fa fa-shield-halved w3-text-green w3-jumbo"></i>
|
||||||
|
<p>OpenSSL</p>
|
||||||
|
</a>
|
||||||
<a
|
<a
|
||||||
href="https://github.com/ianlancetaylor/libbacktrace"
|
href="https://github.com/ianlancetaylor/libbacktrace"
|
||||||
class="w3-col s3"
|
class="w3-col s3"
|
||||||
@@ -347,13 +273,13 @@
|
|||||||
<i class="fa fa-burst w3-text-pink w3-jumbo"></i>
|
<i class="fa fa-burst w3-text-pink w3-jumbo"></i>
|
||||||
<p>libbacktrace</p>
|
<p>libbacktrace</p>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w3-row" style="margin-top: 64px">
|
||||||
<a href="https://codemirror.net/docs/changelog/" class="w3-col s3">
|
<a href="https://codemirror.net/docs/changelog/" class="w3-col s3">
|
||||||
<i class="fa fa-keyboard w3-text-indigo w3-jumbo"></i>
|
<i class="fa fa-keyboard w3-text-indigo w3-jumbo"></i>
|
||||||
<p>CodeMirror</p>
|
<p>CodeMirror</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w3-row" style="margin-top: 64px">
|
|
||||||
<a href="https://github.com/jlfwong/speedscope/" class="w3-col s3">
|
<a href="https://github.com/jlfwong/speedscope/" class="w3-col s3">
|
||||||
<i class="fa fa-microscope w3-text-orange w3-jumbo"></i>
|
<i class="fa fa-microscope w3-text-orange w3-jumbo"></i>
|
||||||
<p>Speedscope</p>
|
<p>Speedscope</p>
|
||||||
@@ -366,6 +292,9 @@
|
|||||||
<i class="fa fa-book-atlas w3-text-purple w3-jumbo"></i>
|
<i class="fa fa-book-atlas w3-text-purple w3-jumbo"></i>
|
||||||
<p>c-ares</p>
|
<p>c-ares</p>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w3-row" style="margin-top: 64px">
|
||||||
<a href="https://www.gnu.org/software/make/" class="w3-col s3">
|
<a href="https://www.gnu.org/software/make/" class="w3-col s3">
|
||||||
<i class="fa fa-hammer w3-text-teal w3-jumbo"></i>
|
<i class="fa fa-hammer w3-text-teal w3-jumbo"></i>
|
||||||
<p>GNU Make</p>
|
<p>GNU Make</p>
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="814" height="1000">
|
|
||||||
<path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 660 B |
BIN
apps/welcome/ssb.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
@@ -1,4 +1,4 @@
|
|||||||
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
@@ -108,8 +108,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
@@ -150,7 +148,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
@@ -178,19 +175,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
|
||||||
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
|
||||||
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
|
||||||
.w3-note{color:#000!important;background-color:#fff599!important}
|
|
||||||
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
|
||||||
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
|
||||||
.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
@@ -248,4 +232,4 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||||
42
apps/wiki/lit-all.min.js
vendored
125
core/app.js
@@ -1,48 +1,53 @@
|
|||||||
/**
|
|
||||||
* \file
|
|
||||||
* \defgroup tfapp Tilde Friends App JS
|
|
||||||
* Tilde Friends server-side app wrapper.
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \cond */
|
|
||||||
import * as core from './core.js';
|
import * as core from './core.js';
|
||||||
|
|
||||||
export {App};
|
let g_next_id = 1;
|
||||||
/** \endcond */
|
let g_calls = {};
|
||||||
|
|
||||||
/** A sequence number of apps. */
|
let gSessionIndex = 0;
|
||||||
let g_session_index = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** App constructor.
|
* TODOC
|
||||||
** @return An app instance.
|
* @returns
|
||||||
|
*/
|
||||||
|
function makeSessionId() {
|
||||||
|
return 'session_' + (gSessionIndex++).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODOC
|
||||||
|
* @returns
|
||||||
*/
|
*/
|
||||||
function App() {
|
function App() {
|
||||||
|
this._on_output = null;
|
||||||
this._send_queue = [];
|
this._send_queue = [];
|
||||||
this.calls = {};
|
|
||||||
this._next_call_id = 1;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Create a function wrapper that when called invokes a function on the app
|
* TODOC
|
||||||
** itself.
|
* @param {*} callback
|
||||||
** @param api The function and argument names.
|
*/
|
||||||
** @return A function.
|
App.prototype.readOutput = function (callback) {
|
||||||
|
this._on_output = callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODOC
|
||||||
|
* @param {*} api
|
||||||
|
* @returns
|
||||||
*/
|
*/
|
||||||
App.prototype.makeFunction = function (api) {
|
App.prototype.makeFunction = function (api) {
|
||||||
let self = this;
|
let self = this;
|
||||||
let result = function () {
|
let result = function () {
|
||||||
let id = self._next_call_id++;
|
let id = g_next_id++;
|
||||||
while (!id || self.calls[id]) {
|
while (!id || g_calls[id]) {
|
||||||
id = self._next_call_id++;
|
id = g_next_id++;
|
||||||
}
|
}
|
||||||
let promise = new Promise(function (resolve, reject) {
|
let promise = new Promise(function (resolve, reject) {
|
||||||
self.calls[id] = {resolve: resolve, reject: reject};
|
g_calls[id] = {resolve: resolve, reject: reject};
|
||||||
});
|
});
|
||||||
let message = {
|
let message = {
|
||||||
action: 'tfrpc',
|
message: 'tfrpc',
|
||||||
method: api[0],
|
method: api[0],
|
||||||
params: [...arguments],
|
params: [...arguments],
|
||||||
id: id,
|
id: id,
|
||||||
@@ -55,8 +60,8 @@ App.prototype.makeFunction = function (api) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Send a message to the app.
|
* TODOC
|
||||||
** @param message The message to send.
|
* @param {*} message
|
||||||
*/
|
*/
|
||||||
App.prototype.send = function (message) {
|
App.prototype.send = function (message) {
|
||||||
if (this._send_queue) {
|
if (this._send_queue) {
|
||||||
@@ -73,9 +78,9 @@ App.prototype.send = function (message) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** App socket handler.
|
* TODOC
|
||||||
** @param request The HTTP request of the WebSocket connection.
|
* @param {*} request
|
||||||
** @param response The HTTP response.
|
* @param {*} response
|
||||||
*/
|
*/
|
||||||
exports.app_socket = async function socket(request, response) {
|
exports.app_socket = async function socket(request, response) {
|
||||||
let process;
|
let process;
|
||||||
@@ -97,16 +102,10 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
try {
|
try {
|
||||||
message = JSON.parse(event.data);
|
message = JSON.parse(event.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
print(
|
print('ERROR', error, event.data, event.data.length, event.opCode);
|
||||||
'WebSocket error:',
|
|
||||||
error,
|
|
||||||
event.data,
|
|
||||||
event.data.length,
|
|
||||||
event.opCode
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!process && message.action == 'hello') {
|
if (message.action == 'hello') {
|
||||||
let packageOwner;
|
let packageOwner;
|
||||||
let packageName;
|
let packageName;
|
||||||
let blobId;
|
let blobId;
|
||||||
@@ -123,7 +122,7 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
if (!blobId) {
|
if (!blobId) {
|
||||||
response.send(
|
response.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
action: 'tfrpc',
|
message: 'tfrpc',
|
||||||
method: 'error',
|
method: 'error',
|
||||||
params: [message.path + ' not found'],
|
params: [message.path + ' not found'],
|
||||||
id: -1,
|
id: -1,
|
||||||
@@ -149,7 +148,7 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
parentApp: parentApp,
|
parentApp: parentApp,
|
||||||
id: blobId,
|
id: blobId,
|
||||||
},
|
},
|
||||||
await ssb_internal.getIdentityInfo(
|
await ssb.getIdentityInfo(
|
||||||
credentials?.session?.name,
|
credentials?.session?.name,
|
||||||
packageOwner,
|
packageOwner,
|
||||||
packageName
|
packageName
|
||||||
@@ -164,7 +163,7 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
options.packageOwner = packageOwner;
|
options.packageOwner = packageOwner;
|
||||||
options.packageName = packageName;
|
options.packageName = packageName;
|
||||||
options.url = message.url;
|
options.url = message.url;
|
||||||
let sessionId = 'session_' + (g_session_index++).toString();
|
let sessionId = makeSessionId();
|
||||||
if (blobId) {
|
if (blobId) {
|
||||||
if (message.edit_only) {
|
if (message.edit_only) {
|
||||||
response.send(
|
response.send(
|
||||||
@@ -176,24 +175,9 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (process) {
|
if (process) {
|
||||||
process.client_api.tfrpc = function (message) {
|
process.app.readOutput(function (message) {
|
||||||
if (message.id) {
|
|
||||||
let calls = process?.app?.calls;
|
|
||||||
if (calls) {
|
|
||||||
let call = calls[message.id];
|
|
||||||
if (call) {
|
|
||||||
if (message.error !== undefined) {
|
|
||||||
call.reject(message.error);
|
|
||||||
} else {
|
|
||||||
call.resolve(message.result);
|
|
||||||
}
|
|
||||||
delete calls[message.id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
process.app._on_output = (message) =>
|
|
||||||
response.send(JSON.stringify(message), 0x1);
|
response.send(JSON.stringify(message), 0x1);
|
||||||
|
});
|
||||||
process.app.send();
|
process.app.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,13 +206,26 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
if (process && process.timeout > 0) {
|
if (process && process.timeout > 0) {
|
||||||
setTimeout(ping, process.timeout);
|
setTimeout(ping, process.timeout);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (message.action == 'resetPermission') {
|
||||||
if (process) {
|
if (process) {
|
||||||
if (process.client_api[message.action]) {
|
process.resetPermission(message.permission);
|
||||||
process.client_api[message.action](message);
|
}
|
||||||
} else if (process.eventHandlers['message']) {
|
} else if (message.action == 'setActiveIdentity') {
|
||||||
await core.invoke(process.eventHandlers['message'], [message]);
|
process.setActiveIdentity(message.identity);
|
||||||
|
} else if (message.action == 'createIdentity') {
|
||||||
|
await process.createIdentity();
|
||||||
|
} else if (message.message == 'tfrpc') {
|
||||||
|
if (message.id && g_calls[message.id]) {
|
||||||
|
if (message.error !== undefined) {
|
||||||
|
g_calls[message.id].reject(message.error);
|
||||||
|
} else {
|
||||||
|
g_calls[message.id].resolve(message.result);
|
||||||
}
|
}
|
||||||
|
delete g_calls[message.id];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (process && process.eventHandlers['message']) {
|
||||||
|
await core.invoke(process.eventHandlers['message'], [message]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (event.opCode == 0x8) {
|
} else if (event.opCode == 0x8) {
|
||||||
@@ -249,4 +246,4 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
response.upgrade(100, {});
|
response.upgrade(100, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
export {App};
|
||||||
|
|||||||
@@ -75,10 +75,6 @@
|
|||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
#code_of_conduct:has(>textarea:empty) {
|
|
||||||
display: none;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<div style="display: flex; flex-direction: column; max-width: 1280px; margin: auto">
|
<div style="display: flex; flex-direction: column; max-width: 1280px; margin: auto">
|
||||||
<h1 ?hidden=${this.name}>Welcome.</h1>
|
<h1 ?hidden=${this.name}>Welcome.</h1>
|
||||||
@@ -130,10 +126,8 @@
|
|||||||
There is currently no administrator. You will be made administrator.
|
There is currently no administrator. You will be made administrator.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="code_of_conduct">
|
<h2>Code of Conduct</h2>
|
||||||
<h2>Code of Conduct</h2>
|
<textarea readonly rows="20" cols="80" style="resize: none">${this.code_of_conduct}</textarea>
|
||||||
<textarea readonly rows="20" style="resize: none; width: 100%">${this.code_of_conduct}</textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
725
core/client.js
369
core/core.js
@@ -1,48 +1,32 @@
|
|||||||
/**
|
|
||||||
* \file
|
|
||||||
* \defgroup tfcore Tilde Friends Core JS
|
|
||||||
* Tilde Friends process management, in JavaScript.
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \cond */
|
|
||||||
import * as app from './app.js';
|
import * as app from './app.js';
|
||||||
|
import * as http from './http.js';
|
||||||
|
|
||||||
export {invoke, getProcessBlob};
|
|
||||||
/** \endcond */
|
|
||||||
|
|
||||||
/** All running processes. */
|
|
||||||
let gProcesses = {};
|
let gProcesses = {};
|
||||||
/** Whether stats are currently being sent. */
|
|
||||||
let gStatsTimer = false;
|
let gStatsTimer = false;
|
||||||
/** Effectively a process ID. */
|
let kPingInterval = 60 * 1000;
|
||||||
let g_handler_index = 0;
|
|
||||||
/** Whether updating accounts information is currently scheduled. */
|
|
||||||
let g_update_accounts_scheduled;
|
|
||||||
/** Time between pings, in milliseconds. */
|
|
||||||
const k_ping_interval = 60 * 1000;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print an error.
|
* TODOC
|
||||||
* @param error The error.
|
* @param {*} out
|
||||||
|
* @param {*} error
|
||||||
*/
|
*/
|
||||||
function printError(error) {
|
function printError(out, error) {
|
||||||
if (error.stackTrace) {
|
if (error.stackTrace) {
|
||||||
print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
out.print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
||||||
print(error.stackTrace);
|
out.print(error.stackTrace);
|
||||||
} else {
|
} else {
|
||||||
for (let [k, v] of Object.entries(error)) {
|
for (let [k, v] of Object.entries(error)) {
|
||||||
print(k, v);
|
out.print(k, v);
|
||||||
}
|
}
|
||||||
print(error.toString());
|
out.print(error.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke a handler.
|
* TODOC
|
||||||
* @param handlers The handlers on which to invoke the callback.
|
* @param {*} handlers
|
||||||
* @param argv Arguments to pass to the handlers.
|
* @param {*} argv
|
||||||
* @return A promise.
|
* @returns
|
||||||
*/
|
*/
|
||||||
function invoke(handlers, argv) {
|
function invoke(handlers, argv) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
@@ -65,10 +49,10 @@ function invoke(handlers, argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast a named event to all registered apps.
|
* TODOC
|
||||||
* @param eventName the name of the event.
|
* @param {*} eventName
|
||||||
* @param argv Arguments to pass to the handlers.
|
* @param {*} argv
|
||||||
* @return A promise.
|
* @returns
|
||||||
*/
|
*/
|
||||||
function broadcastEvent(eventName, argv) {
|
function broadcastEvent(eventName, argv) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
@@ -81,9 +65,9 @@ function broadcastEvent(eventName, argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message to all other instances of the same app.
|
* TODOC
|
||||||
* @param message The message.
|
* @param {*} message
|
||||||
* @return A promise.
|
* @returns
|
||||||
*/
|
*/
|
||||||
function broadcast(message) {
|
function broadcast(message) {
|
||||||
let sender = this;
|
let sender = this;
|
||||||
@@ -102,13 +86,10 @@ function broadcast(message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message to all instances of the same app running as the same user.
|
* TODOC
|
||||||
* @param user The user.
|
* @param {String} eventName
|
||||||
* @param packageOwner The owner of the app.
|
* @param {*} argv
|
||||||
* @param packageName The name of the app.
|
* @returns
|
||||||
* @param eventName The name of the event.
|
|
||||||
* @param argv The arguments to pass.
|
|
||||||
* @return A promise.
|
|
||||||
*/
|
*/
|
||||||
function broadcastAppEventToUser(
|
function broadcastAppEventToUser(
|
||||||
user,
|
user,
|
||||||
@@ -133,9 +114,10 @@ function broadcastAppEventToUser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user context information for a call.
|
* TODOC
|
||||||
* @param caller The calling process.
|
* @param {*} caller
|
||||||
* @param process The receiving process.
|
* @param {*} process
|
||||||
|
* @returns
|
||||||
*/
|
*/
|
||||||
function getUser(caller, process) {
|
function getUser(caller, process) {
|
||||||
return {
|
return {
|
||||||
@@ -148,11 +130,43 @@ function getUser(caller, process) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message.
|
* TODOC
|
||||||
* @param from The calling process.
|
* @param {*} user
|
||||||
* @param to The receiving process.
|
* @param {*} process
|
||||||
* @param message The message.
|
* @returns
|
||||||
* @return A promise.
|
*/
|
||||||
|
async function getApps(user, process) {
|
||||||
|
if (
|
||||||
|
process.credentials &&
|
||||||
|
process.credentials.session &&
|
||||||
|
process.credentials.session.name
|
||||||
|
) {
|
||||||
|
if (user && user !== process.credentials.session.name && user !== 'core') {
|
||||||
|
return {};
|
||||||
|
} else if (!user) {
|
||||||
|
user = process.credentials.session.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (user) {
|
||||||
|
let db = new Database(user);
|
||||||
|
try {
|
||||||
|
let names = JSON.parse(await db.get('apps'));
|
||||||
|
let result = {};
|
||||||
|
for (let name of names) {
|
||||||
|
result[name] = await db.get('path:' + name);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODOC
|
||||||
|
* @param {*} from
|
||||||
|
* @param {*} to
|
||||||
|
* @param {*} message
|
||||||
|
* @returns
|
||||||
*/
|
*/
|
||||||
function postMessageInternal(from, to, message) {
|
function postMessageInternal(from, to, message) {
|
||||||
if (to.eventHandlers['message']) {
|
if (to.eventHandlers['message']) {
|
||||||
@@ -161,13 +175,14 @@ function postMessageInternal(from, to, message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get or create a process for an app blob.
|
* TODOC
|
||||||
* @param blobId The blob identifier.
|
* @param {*} blobId
|
||||||
* @param key A unique key for the invocation.
|
* @param {*} key
|
||||||
* @param options Other options.
|
* @param {*} options
|
||||||
* @return The process.
|
* @returns
|
||||||
*/
|
*/
|
||||||
async function getProcessBlob(blobId, key, options) {
|
async function getProcessBlob(blobId, key, options) {
|
||||||
|
// TODO(tasiaiso): break this down ?
|
||||||
let process = gProcesses[key];
|
let process = gProcesses[key];
|
||||||
if (!process && !(options && 'create' in options && !options.create)) {
|
if (!process && !(options && 'create' in options && !options.create)) {
|
||||||
let resolveReady;
|
let resolveReady;
|
||||||
@@ -180,27 +195,67 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
process.task = new Task();
|
process.task = new Task();
|
||||||
process.packageOwner = options.packageOwner;
|
process.packageOwner = options.packageOwner;
|
||||||
process.packageName = options.packageName;
|
process.packageName = options.packageName;
|
||||||
process.url = options?.url;
|
|
||||||
process.eventHandlers = {};
|
process.eventHandlers = {};
|
||||||
if (!options?.script || options?.script === 'app.js') {
|
if (!options?.script || options?.script === 'app.js') {
|
||||||
process.app = new app.App();
|
process.app = new app.App();
|
||||||
}
|
}
|
||||||
process.lastActive = Date.now();
|
process.lastActive = Date.now();
|
||||||
process.lastPing = null;
|
process.lastPing = null;
|
||||||
process.timeout = k_ping_interval;
|
process.timeout = kPingInterval;
|
||||||
process.ready = new Promise(function (resolve, reject) {
|
process.ready = new Promise(function (resolve, reject) {
|
||||||
resolveReady = resolve;
|
resolveReady = resolve;
|
||||||
rejectReady = reject;
|
rejectReady = reject;
|
||||||
});
|
});
|
||||||
gProcesses[key] = process;
|
gProcesses[key] = process;
|
||||||
process.task.onExit = function (exitCode, terminationSignal) {
|
process.task.onExit = function (exitCode, terminationSignal) {
|
||||||
|
broadcastEvent('onSessionEnd', [getUser(process, process)]);
|
||||||
process.task = null;
|
process.task = null;
|
||||||
delete gProcesses[key];
|
delete gProcesses[key];
|
||||||
};
|
};
|
||||||
let imports = {
|
let imports = {
|
||||||
core: {
|
core: {
|
||||||
broadcast: broadcast.bind(process),
|
broadcast: broadcast.bind(process),
|
||||||
|
register: function (eventName, handler) {
|
||||||
|
if (!process.eventHandlers[eventName]) {
|
||||||
|
process.eventHandlers[eventName] = [];
|
||||||
|
}
|
||||||
|
process.eventHandlers[eventName].push(handler);
|
||||||
|
},
|
||||||
|
unregister: function (eventName, handler) {
|
||||||
|
if (process.eventHandlers[eventName]) {
|
||||||
|
let index = process.eventHandlers[eventName].indexOf(handler);
|
||||||
|
if (index != -1) {
|
||||||
|
process.eventHandlers[eventName].splice(index, 1);
|
||||||
|
}
|
||||||
|
if (process.eventHandlers[eventName].length == 0) {
|
||||||
|
delete process.eventHandlers[eventName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
user: getUser(process, process),
|
user: getUser(process, process),
|
||||||
|
users: async function () {
|
||||||
|
try {
|
||||||
|
return JSON.parse(await new Database('auth').get('users'));
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
permissionsGranted: async function () {
|
||||||
|
let user = process?.credentials?.session?.name;
|
||||||
|
let settings = await loadSettings();
|
||||||
|
if (
|
||||||
|
user &&
|
||||||
|
options?.packageOwner &&
|
||||||
|
options?.packageName &&
|
||||||
|
settings.userPermissions &&
|
||||||
|
settings.userPermissions[user] &&
|
||||||
|
settings.userPermissions[user][options.packageOwner]
|
||||||
|
) {
|
||||||
|
return settings.userPermissions[user][options.packageOwner][
|
||||||
|
options.packageName
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
allPermissionsGranted: async function () {
|
allPermissionsGranted: async function () {
|
||||||
let user = process?.credentials?.session?.name;
|
let user = process?.credentials?.session?.name;
|
||||||
let settings = await loadSettings();
|
let settings = await loadSettings();
|
||||||
@@ -214,7 +269,13 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
return settings.userPermissions[user];
|
return settings.userPermissions[user];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
permissionTest: async function (permission, description) {
|
permissionsForUser: async function (user) {
|
||||||
|
let settings = await loadSettings();
|
||||||
|
return settings?.permissions?.[user] ?? [];
|
||||||
|
},
|
||||||
|
apps: (user) => getApps(user, process),
|
||||||
|
getSockets: getSockets,
|
||||||
|
permissionTest: async function (permission) {
|
||||||
let user = process?.credentials?.session?.name;
|
let user = process?.credentials?.session?.name;
|
||||||
let settings = await loadSettings();
|
let settings = await loadSettings();
|
||||||
if (!user || !options?.packageOwner || !options?.packageName) {
|
if (!user || !options?.packageOwner || !options?.packageName) {
|
||||||
@@ -241,7 +302,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
} else if (process.app) {
|
} else if (process.app) {
|
||||||
return process.app
|
return process.app
|
||||||
.makeFunction(['requestPermission'])(permission, description)
|
.makeFunction(['requestPermission'])(permission)
|
||||||
.then(async function (value) {
|
.then(async function (value) {
|
||||||
if (value == 'allow') {
|
if (value == 'allow') {
|
||||||
await ssb.setUserPermission(
|
await ssb.setUserPermission(
|
||||||
@@ -274,26 +335,26 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
throw Error(`Permission denied: ${permission}.`);
|
throw Error(`Permission denied: ${permission}.`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
app: {
|
||||||
|
owner: options?.packageOwner,
|
||||||
|
name: options?.packageName,
|
||||||
|
},
|
||||||
|
url: options?.url,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
process.sendIdentities = async function () {
|
process.sendIdentities = async function () {
|
||||||
let identities = await ssb_internal.getIdentityInfo(
|
process.app.send(
|
||||||
process?.credentials?.session?.name,
|
Object.assign(
|
||||||
options?.packageOwner,
|
{
|
||||||
options?.packageName
|
action: 'identities',
|
||||||
);
|
},
|
||||||
let json = JSON.stringify(identities);
|
await ssb.getIdentityInfo(
|
||||||
if (process._last_sent_identities !== json) {
|
process?.credentials?.session?.name,
|
||||||
process.app.send(
|
options?.packageOwner,
|
||||||
Object.assign(
|
options?.packageName
|
||||||
{
|
|
||||||
action: 'identities',
|
|
||||||
},
|
|
||||||
identities
|
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
process._last_sent_identities = json;
|
);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
process.setActiveIdentity = async function (identity) {
|
process.setActiveIdentity = async function (identity) {
|
||||||
if (
|
if (
|
||||||
@@ -330,7 +391,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
options.packageName,
|
options.packageName,
|
||||||
'setActiveIdentity',
|
'setActiveIdentity',
|
||||||
[
|
[
|
||||||
await imports.ssb.getActiveIdentity(
|
await ssb.getActiveIdentity(
|
||||||
process.credentials?.session?.name,
|
process.credentials?.session?.name,
|
||||||
options.packageOwner,
|
options.packageOwner,
|
||||||
options.packageName
|
options.packageName
|
||||||
@@ -343,11 +404,21 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (process.credentials?.permissions?.administration) {
|
if (process.credentials?.permissions?.administration) {
|
||||||
|
imports.core.globalSettingsDescriptions = async function () {
|
||||||
|
let settings = Object.assign({}, defaultGlobalSettings());
|
||||||
|
for (let [key, value] of Object.entries(await loadSettings())) {
|
||||||
|
if (settings[key]) {
|
||||||
|
settings[key].value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
};
|
||||||
|
imports.core.globalSettingsGet = async function (key) {
|
||||||
|
let settings = await loadSettings();
|
||||||
|
return settings?.[key];
|
||||||
|
};
|
||||||
imports.core.globalSettingsSet = async function (key, value) {
|
imports.core.globalSettingsSet = async function (key, value) {
|
||||||
await imports.core.permissionTest(
|
await imports.core.permissionTest('set_global_setting');
|
||||||
'set_global_setting',
|
|
||||||
`Set ${JSON.stringify(key)} to ${JSON.stringify(value)}.`
|
|
||||||
);
|
|
||||||
print('Setting', key, value);
|
print('Setting', key, value);
|
||||||
let settings = await loadSettings();
|
let settings = await loadSettings();
|
||||||
settings[key] = value;
|
settings[key] = value;
|
||||||
@@ -390,10 +461,10 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
if (process.app) {
|
if (process.app) {
|
||||||
process.app.makeFunction(['error'])(error);
|
process.app.makeFunction(['error'])(error);
|
||||||
} else {
|
} else {
|
||||||
printError(error);
|
printError({print: print}, error);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
printError(error);
|
printError({print: print}, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
imports.ssb = Object.fromEntries(
|
imports.ssb = Object.fromEntries(
|
||||||
@@ -427,6 +498,26 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
imports.ssb.setActiveIdentity = (id) => process.setActiveIdentity(id);
|
imports.ssb.setActiveIdentity = (id) => process.setActiveIdentity(id);
|
||||||
|
imports.ssb.getActiveIdentity = () =>
|
||||||
|
ssb.getActiveIdentity(
|
||||||
|
process.credentials?.session?.name,
|
||||||
|
options.packageOwner,
|
||||||
|
options.packageName
|
||||||
|
);
|
||||||
|
imports.ssb.getOwnerIdentities = function () {
|
||||||
|
if (options.packageOwner) {
|
||||||
|
return ssb.getIdentities(options.packageOwner);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
imports.ssb.getIdentities = function () {
|
||||||
|
if (
|
||||||
|
process.credentials &&
|
||||||
|
process.credentials.session &&
|
||||||
|
process.credentials.session.name
|
||||||
|
) {
|
||||||
|
return ssb.getIdentities(process.credentials.session.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
imports.ssb.getPrivateKey = function (id) {
|
imports.ssb.getPrivateKey = function (id) {
|
||||||
if (
|
if (
|
||||||
process.credentials &&
|
process.credentials &&
|
||||||
@@ -446,18 +537,8 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
process.credentials.session &&
|
process.credentials.session &&
|
||||||
process.credentials.session.name
|
process.credentials.session.name
|
||||||
) {
|
) {
|
||||||
let action;
|
|
||||||
try {
|
|
||||||
if (message?.type === 'vote' && message?.vote?.expression) {
|
|
||||||
action = `React with ${message?.vote?.expression}.`;
|
|
||||||
} else if (typeof message === 'string') {
|
|
||||||
action = `Post a private message.`;
|
|
||||||
} else {
|
|
||||||
action = `Publish ${'aeiou'.indexOf(message?.type?.toLowerCase()?.substring(0, 1)) != -1 ? 'an' : 'a'} "${message?.type}" message.`;
|
|
||||||
}
|
|
||||||
} catch {}
|
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
imports.core.permissionTest('ssb_append', action)
|
imports.core.permissionTest('ssb_append')
|
||||||
).then(function () {
|
).then(function () {
|
||||||
return ssb.appendMessageWithIdentity(
|
return ssb.appendMessageWithIdentity(
|
||||||
process.credentials.session.name,
|
process.credentials.session.name,
|
||||||
@@ -506,6 +587,13 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
imports.ssb.addEventListener = undefined;
|
||||||
|
imports.ssb.removeEventListener = undefined;
|
||||||
|
imports.ssb.getIdentityInfo = undefined;
|
||||||
|
imports.fetch = async function (url, options) {
|
||||||
|
let settings = await loadSettings();
|
||||||
|
return http.fetch(url, options, settings?.fetch_hosts);
|
||||||
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
process.credentials &&
|
process.credentials &&
|
||||||
@@ -561,26 +649,17 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
permissions: await imports.core.permissionsGranted(),
|
permissions: await imports.core.permissionsGranted(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
process.client_api = {
|
process.resetPermission = async function resetPermission(permission) {
|
||||||
createIdentity: function () {
|
let user = process?.credentials?.session?.name;
|
||||||
return process.createIdentity();
|
await ssb.setUserPermission(
|
||||||
},
|
user,
|
||||||
resetPermission: async function resetPermission(message) {
|
options?.packageOwner,
|
||||||
let user = process?.credentials?.session?.name;
|
options?.packageName,
|
||||||
await ssb.setUserPermission(
|
permission,
|
||||||
user,
|
undefined
|
||||||
options?.packageOwner,
|
);
|
||||||
options?.packageName,
|
return process.sendPermissions();
|
||||||
message.permission,
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
return process.sendPermissions();
|
|
||||||
},
|
|
||||||
setActiveIdentity: function setActiveIdentity(message) {
|
|
||||||
return process.setActiveIdentity(message.identity);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
ssb.registerImports(imports, process);
|
|
||||||
process.task.setImports(imports);
|
process.task.setImports(imports);
|
||||||
process.task.activate();
|
process.task.activate();
|
||||||
let source = await ssb.blobGet(blobId);
|
let source = await ssb.blobGet(blobId);
|
||||||
@@ -607,8 +686,9 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
printError(e);
|
printError({print: print}, e);
|
||||||
}
|
}
|
||||||
|
broadcastEvent('onSessionBegin', [getUser(process, process)]);
|
||||||
if (process.app) {
|
if (process.app) {
|
||||||
process.app.send({action: 'ready', version: version()});
|
process.app.send({action: 'ready', version: version()});
|
||||||
await process.sendPermissions();
|
await process.sendPermissions();
|
||||||
@@ -620,10 +700,14 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
sendStats();
|
sendStats();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (process?.app && process?.task?.onError) {
|
if (process.app) {
|
||||||
process.task.onError(error);
|
if (process?.task?.onError) {
|
||||||
|
process.task.onError(error);
|
||||||
|
} else {
|
||||||
|
printError({print: print}, error);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
printError(error);
|
printError({print: print}, error);
|
||||||
}
|
}
|
||||||
rejectReady(error);
|
rejectReady(error);
|
||||||
}
|
}
|
||||||
@@ -631,45 +715,20 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
ssb.addEventListener('message', function () {
|
||||||
* Send any changed account information.
|
|
||||||
*/
|
|
||||||
function updateAccounts() {
|
|
||||||
g_update_accounts_scheduled = false;
|
|
||||||
let promises = [];
|
|
||||||
for (let process of Object.values(gProcesses)) {
|
|
||||||
promises.push(process.sendIdentities());
|
|
||||||
}
|
|
||||||
return Promise.all(promises);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SSB message added callback.
|
|
||||||
*/
|
|
||||||
ssb_internal.addEventListener('message', function () {
|
|
||||||
broadcastEvent('onMessage', [...arguments]);
|
broadcastEvent('onMessage', [...arguments]);
|
||||||
|
|
||||||
if (!g_update_accounts_scheduled) {
|
|
||||||
setTimeout(updateAccounts, 1000);
|
|
||||||
g_update_accounts_scheduled = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ssb_internal.addEventListener('blob', function () {
|
ssb.addEventListener('broadcasts', function () {
|
||||||
broadcastEvent('onBlob', [...arguments]);
|
|
||||||
});
|
|
||||||
|
|
||||||
ssb_internal.addEventListener('broadcasts', function () {
|
|
||||||
broadcastEvent('onBroadcastsChanged', []);
|
broadcastEvent('onBroadcastsChanged', []);
|
||||||
});
|
});
|
||||||
|
|
||||||
ssb_internal.addEventListener('connections', function () {
|
ssb.addEventListener('connections', function () {
|
||||||
broadcastEvent('onConnectionsChanged', []);
|
broadcastEvent('onConnectionsChanged', []);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load settings from the database.
|
* TODOC
|
||||||
* @return The settings as a key value pairs object.
|
|
||||||
*/
|
*/
|
||||||
async function loadSettings() {
|
async function loadSettings() {
|
||||||
let data = {};
|
let data = {};
|
||||||
@@ -690,7 +749,7 @@ async function loadSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send periodic stats to all clients.
|
* TODOC
|
||||||
*/
|
*/
|
||||||
function sendStats() {
|
function sendStats() {
|
||||||
let apps = Object.values(gProcesses)
|
let apps = Object.values(gProcesses)
|
||||||
@@ -707,16 +766,8 @@ function sendStats() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
let g_handler_index = 0;
|
||||||
* Invoke an app's handler.js.
|
|
||||||
* @param response The response object.
|
|
||||||
* @param app_blob_id The app's blob identifier.
|
|
||||||
* @param path The request path.
|
|
||||||
* @param query The request query string.
|
|
||||||
* @param headers The request headers.
|
|
||||||
* @param package_owner The app's owner.
|
|
||||||
* @param package_name The app's name.
|
|
||||||
*/
|
|
||||||
exports.callAppHandler = async function callAppHandler(
|
exports.callAppHandler = async function callAppHandler(
|
||||||
response,
|
response,
|
||||||
app_blob_id,
|
app_blob_id,
|
||||||
@@ -782,4 +833,4 @@ exports.callAppHandler = async function callAppHandler(
|
|||||||
response.end(answer?.data);
|
response.end(answer?.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @} */
|
export {invoke, getProcessBlob};
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Tilde Friends Usage Agreement</title>
|
|
||||||
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
</head>
|
|
||||||
<body class="w3-container">
|
|
||||||
<h1>Tilde Friends Usage Agreement</h1>
|
|
||||||
<p>
|
|
||||||
Tilde Friends is an app that enables communication with other users
|
|
||||||
through the
|
|
||||||
<a href="https://ssbc.github.io/scuttlebutt-protocol-guide/"
|
|
||||||
>Secure Scuttlebutt</a
|
|
||||||
>
|
|
||||||
protocol.
|
|
||||||
</p>
|
|
||||||
<h2>Your actions are your responsibility</h2>
|
|
||||||
<p>
|
|
||||||
Apple tolerates no objectionable content or abusive users on their
|
|
||||||
platforms.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
You are responsible for your own actions within this app. You are
|
|
||||||
responsible for complying with all applicable rules and laws.
|
|
||||||
</p>
|
|
||||||
<h2>You choose what you see</h2>
|
|
||||||
<p>
|
|
||||||
You are in full control of the content you see in Tilde Friends. The peers
|
|
||||||
to which you choose to connect and the users you choose to follow directly
|
|
||||||
determine the content presented to you. Initially you will be following no
|
|
||||||
one with no connections and as a result see no user-generated content.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If you encounter objectionable content, you can filter it from your view
|
|
||||||
by blocking the user who posted it. This also makes it so that users
|
|
||||||
following you will not see it as a consequence of following you.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
The <code>admin</code> app contains a variety of settings that control the
|
|
||||||
types of connections Tilde Friends will make or accept, including whether
|
|
||||||
the app will even accept or make connections at all.
|
|
||||||
</p>
|
|
||||||
<h2>This app is not a service</h2>
|
|
||||||
<p>
|
|
||||||
Tilde Friends is an app. It relies on no servers. The author of this app
|
|
||||||
has no more ability to see or filter what you post or read than any other
|
|
||||||
user of the network.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
If you believe objectionable content obtained from a service that is
|
|
||||||
running as part of the Secure Scuttlebutt network should be flagged,
|
|
||||||
report it to the operator of the service, generally by contacting the
|
|
||||||
email address listed when visiting the server address in a web browser.
|
|
||||||
</p>
|
|
||||||
<h2>Agreement</h2>
|
|
||||||
<p>
|
|
||||||
If you do not accept these terms, do not use this app. You may close and
|
|
||||||
delete it now.
|
|
||||||
</p>
|
|
||||||
<div class="w3-center w3-margin">
|
|
||||||
<a class="w3-button w3-blue w3-round-large" href="/eula/accept"
|
|
||||||
>Accept Agreement</a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
113
core/http.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* TODOC
|
||||||
|
* TODO: document so we can improve this
|
||||||
|
* @param {*} url
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function parseUrl(url) {
|
||||||
|
// XXX: Hack.
|
||||||
|
let match = url.match(new RegExp('(\\w+)://([^/:]+)(?::(\\d+))?(.*)'));
|
||||||
|
return {
|
||||||
|
protocol: match[1],
|
||||||
|
host: match[2],
|
||||||
|
path: match[4],
|
||||||
|
port: match[3] ? parseInt(match[3]) : match[1] == 'http' ? 80 : 443,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODOC
|
||||||
|
* @param {*} data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function parseResponse(data) {
|
||||||
|
let firstLine;
|
||||||
|
let headers = {};
|
||||||
|
while (true) {
|
||||||
|
let endLine = data.indexOf('\r\n');
|
||||||
|
let line = data.substring(0, endLine);
|
||||||
|
data = data.substring(endLine + 2);
|
||||||
|
if (!line.length) {
|
||||||
|
break;
|
||||||
|
} else if (!firstLine) {
|
||||||
|
firstLine = line;
|
||||||
|
} else {
|
||||||
|
let colon = line.indexOf(':');
|
||||||
|
headers[line.substring(colon)] = line.substring(colon + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {body: data};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODOC
|
||||||
|
* @param {*} url
|
||||||
|
* @param {*} options
|
||||||
|
* @param {*} allowed_hosts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function fetch(url, options, allowed_hosts) {
|
||||||
|
let parsed = parseUrl(url);
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if ((allowed_hosts ?? []).indexOf(parsed.host) == -1) {
|
||||||
|
throw new Error(`fetch() request to host ${parsed.host} is not allowed.`);
|
||||||
|
}
|
||||||
|
let socket = new Socket();
|
||||||
|
let buffer = new Uint8Array(0);
|
||||||
|
|
||||||
|
return socket
|
||||||
|
.connect(parsed.host, parsed.port)
|
||||||
|
.then(function () {
|
||||||
|
socket.read(function (data) {
|
||||||
|
if (data && data.length) {
|
||||||
|
let newBuffer = new Uint8Array(buffer.length + data.length);
|
||||||
|
newBuffer.set(buffer, 0);
|
||||||
|
newBuffer.set(data, buffer.length);
|
||||||
|
buffer = newBuffer;
|
||||||
|
} else {
|
||||||
|
let result = parseHttpResponse(buffer);
|
||||||
|
if (!result) {
|
||||||
|
reject(new Exception('Parse failed.'));
|
||||||
|
}
|
||||||
|
if (typeof result == 'number') {
|
||||||
|
if (result == -2) {
|
||||||
|
reject('Incomplete request.');
|
||||||
|
} else {
|
||||||
|
reject('Bad request.');
|
||||||
|
}
|
||||||
|
} else if (typeof result == 'object') {
|
||||||
|
resolve({
|
||||||
|
body: buffer.slice(result.bytes_parsed),
|
||||||
|
status: result.status,
|
||||||
|
message: result.message,
|
||||||
|
headers: result.headers,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
reject(new Exception('Unexpected parse result.'));
|
||||||
|
}
|
||||||
|
resolve(parseResponse(utf8Decode(buffer)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (parsed.port == 443) {
|
||||||
|
return socket.startTls();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
let body =
|
||||||
|
typeof options?.body == 'string'
|
||||||
|
? utf8Encode(options.body)
|
||||||
|
: options.body || new Uint8Array(0);
|
||||||
|
let headers = utf8Encode(
|
||||||
|
`${options?.method ?? 'GET'} ${parsed.path} HTTP/1.0\r\nHost: ${parsed.host}\r\nConnection: close\r\nContent-Length: ${body.length}\r\n\r\n`
|
||||||
|
);
|
||||||
|
let fullRequest = new Uint8Array(headers.length + body.length);
|
||||||
|
fullRequest.set(headers, 0);
|
||||||
|
fullRequest.set(body, headers.length);
|
||||||
|
socket.write(fullRequest);
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -5,10 +5,7 @@
|
|||||||
<link type="text/css" rel="stylesheet" href="/static/style.css" />
|
<link type="text/css" rel="stylesheet" href="/static/style.css" />
|
||||||
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
||||||
<link type="image/svg+xml" rel="icon" href="/static/tildefriends.svg" />
|
<link type="image/svg+xml" rel="icon" href="/static/tildefriends.svg" />
|
||||||
<meta
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1, maximum-scale=1"
|
|
||||||
/>
|
|
||||||
<meta
|
<meta
|
||||||
name="title"
|
name="title"
|
||||||
content="Tilde Friends - Make friends and apps from your web browser."
|
content="Tilde Friends - Make friends and apps from your web browser."
|
||||||
|
|||||||
@@ -152,5 +152,4 @@ body {
|
|||||||
border-bottom: 4px solid #fff;
|
border-bottom: 4px solid #fff;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 80%;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,11 @@
|
|||||||
/**
|
|
||||||
* \file
|
|
||||||
* \defgroup tfrpc Tilde Friends RPC.
|
|
||||||
* Tilde Friends RPC.
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Whether this module is being run in a web browser. */
|
|
||||||
const k_is_browser = get_is_browser();
|
const k_is_browser = get_is_browser();
|
||||||
/** Registered methods. */
|
|
||||||
let g_api = {};
|
let g_api = {};
|
||||||
/** The next method identifier. */
|
|
||||||
let g_next_id = 1;
|
let g_next_id = 1;
|
||||||
/** Identifiers of pending calls. */
|
|
||||||
let g_calls = {};
|
let g_calls = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if being called from a browser vs. server-side.
|
* TODOC
|
||||||
* @return true if called from a browser.
|
* @returns
|
||||||
*/
|
*/
|
||||||
function get_is_browser() {
|
function get_is_browser() {
|
||||||
try {
|
try {
|
||||||
@@ -26,30 +15,16 @@ function get_is_browser() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \cond */
|
|
||||||
if (k_is_browser) {
|
if (k_is_browser) {
|
||||||
print = console.log;
|
print = console.log;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k_is_browser) {
|
|
||||||
window.addEventListener('message', function (event) {
|
|
||||||
call_rpc(event.data);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
core.register('message', function (message) {
|
|
||||||
call_rpc(message?.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export let rpc = new Proxy({}, {get: make_rpc});
|
|
||||||
/** \endcond */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a function to invoke a remote procedure.
|
* TODOC
|
||||||
* @param target The target.
|
* @param {*} target
|
||||||
* @param prop The name of the function.
|
* @param {*} prop
|
||||||
* @param receiver The receiver.
|
* @param {*} receiver
|
||||||
* @return A function.
|
* @returns
|
||||||
*/
|
*/
|
||||||
function make_rpc(target, prop, receiver) {
|
function make_rpc(target, prop, receiver) {
|
||||||
return function () {
|
return function () {
|
||||||
@@ -80,8 +55,8 @@ function make_rpc(target, prop, receiver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a response.
|
* TODOC
|
||||||
* @param response The response.
|
* @param {*} response
|
||||||
*/
|
*/
|
||||||
function send(response) {
|
function send(response) {
|
||||||
if (k_is_browser) {
|
if (k_is_browser) {
|
||||||
@@ -92,8 +67,8 @@ function send(response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke a remote procedure.
|
* TODOC
|
||||||
* @param message An object describing the call.
|
* @param {*} message
|
||||||
*/
|
*/
|
||||||
function call_rpc(message) {
|
function call_rpc(message) {
|
||||||
if (message && message.message === 'tfrpc') {
|
if (message && message.message === 'tfrpc') {
|
||||||
@@ -137,12 +112,22 @@ function call_rpc(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (k_is_browser) {
|
||||||
|
window.addEventListener('message', function (event) {
|
||||||
|
call_rpc(event.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.register('message', function (message) {
|
||||||
|
call_rpc(message?.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export let rpc = new Proxy({}, {get: make_rpc});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a function that to be called remotely.
|
* TODOC
|
||||||
* @param method The method.
|
* @param {*} method
|
||||||
*/
|
*/
|
||||||
export function register(method) {
|
export function register(method) {
|
||||||
g_api[method.name] = method;
|
g_api[method.name] = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|||||||
20
core/w3.css
@@ -1,4 +1,4 @@
|
|||||||
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
@@ -108,8 +108,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
@@ -150,7 +148,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
@@ -178,19 +175,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
|
||||||
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
|
||||||
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
|
||||||
.w3-note{color:#000!important;background-color:#fff599!important}
|
|
||||||
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
|
||||||
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
|
||||||
.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
@@ -248,4 +232,4 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||||
@@ -25,14 +25,14 @@
|
|||||||
}:
|
}:
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "tildefriends";
|
pname = "tildefriends";
|
||||||
version = "0.2025.9";
|
version = "0.0.28";
|
||||||
|
|
||||||
src = pkgs.fetchFromGitea {
|
src = pkgs.fetchFromGitea {
|
||||||
domain = "dev.tildefriends.net";
|
domain = "dev.tildefriends.net";
|
||||||
owner = "cory";
|
owner = "cory";
|
||||||
repo = "tildefriends";
|
repo = "tildefriends";
|
||||||
rev = "v${version}";
|
rev = "f02423d0846fefd5ab21fa4542fb77ce5714547c";
|
||||||
hash = "sha256-1nhsfhdOO5HIiiTMb+uROB8nDPL/UpOYm52hZ/OpPyk=";
|
hash = "sha256-QyM7wmViXJc4r8uTu4oE/HO3Z9tzNbFIX2+AOTQz9ZY=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
deps/c-ares
vendored
2
deps/codemirror/cm6.js
vendored
499
deps/codemirror_src/package-lock.json
generated
vendored
@@ -19,10 +19,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/autocomplete": {
|
"node_modules/@codemirror/autocomplete": {
|
||||||
"version": "6.20.0",
|
"version": "6.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
||||||
"integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==",
|
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@@ -31,10 +30,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.10.0",
|
"version": "6.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.0.tgz",
|
||||||
"integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==",
|
"integrity": "sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
@@ -46,7 +44,6 @@
|
|||||||
"version": "6.3.1",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
||||||
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
@@ -56,10 +53,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lang-html": {
|
"node_modules/@codemirror/lang-html": {
|
||||||
"version": "6.4.11",
|
"version": "6.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
|
||||||
"integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==",
|
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/lang-css": "^6.0.0",
|
"@codemirror/lang-css": "^6.0.0",
|
||||||
@@ -69,14 +65,13 @@
|
|||||||
"@codemirror/view": "^6.17.0",
|
"@codemirror/view": "^6.17.0",
|
||||||
"@lezer/common": "^1.0.0",
|
"@lezer/common": "^1.0.0",
|
||||||
"@lezer/css": "^1.1.0",
|
"@lezer/css": "^1.1.0",
|
||||||
"@lezer/html": "^1.3.12"
|
"@lezer/html": "^1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lang-javascript": {
|
"node_modules/@codemirror/lang-javascript": {
|
||||||
"version": "6.2.4",
|
"version": "6.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.3.tgz",
|
||||||
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
|
"integrity": "sha512-8PR3vIWg7pSu7ur8A07pGiYHgy3hHj+mRYRCSG8q+mPIrl0F02rgpGv+DsQTHRTc30rydOsf5PZ7yjKFg2Ackw==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.6.0",
|
"@codemirror/language": "^6.6.0",
|
||||||
@@ -88,20 +83,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lang-json": {
|
"node_modules/@codemirror/lang-json": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
|
||||||
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@lezer/json": "^1.0.0"
|
"@lezer/json": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/language": {
|
"node_modules/@codemirror/language": {
|
||||||
"version": "6.11.3",
|
"version": "6.10.8",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.8.tgz",
|
||||||
"integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==",
|
"integrity": "sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.23.0",
|
"@codemirror/view": "^6.23.0",
|
||||||
@@ -112,10 +105,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lint": {
|
"node_modules/@codemirror/lint": {
|
||||||
"version": "6.9.2",
|
"version": "6.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.4.tgz",
|
||||||
"integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==",
|
"integrity": "sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.35.0",
|
"@codemirror/view": "^6.35.0",
|
||||||
@@ -123,10 +115,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/search": {
|
"node_modules/@codemirror/search": {
|
||||||
"version": "6.5.11",
|
"version": "6.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.9.tgz",
|
||||||
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
"integrity": "sha512-7DdQ9aaZMMxuWB1u6IIFWWuK9NocVZwvo4nG8QjJTS6oZGvteoLSiXw3EbVZVlO08Ri2ltO89JVInMpfcJxhtg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.0.0",
|
"@codemirror/view": "^6.0.0",
|
||||||
@@ -137,16 +128,14 @@
|
|||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
||||||
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@marijn/find-cluster-break": "^1.0.0"
|
"@marijn/find-cluster-break": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/theme-one-dark": {
|
"node_modules/@codemirror/theme-one-dark": {
|
||||||
"version": "6.1.3",
|
"version": "6.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
|
||||||
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@@ -155,26 +144,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.38.8",
|
"version": "6.36.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.8.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.3.tgz",
|
||||||
"integrity": "sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==",
|
"integrity": "sha512-N2bilM47QWC8Hnx0rMdDxO2x2ImJ1FvZWXubwKgjeoOrWwEiFrtpA7SFHcuZ+o2Ze2VzbkgbzWVj4+V18LVkeg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
"crelt": "^1.0.6",
|
|
||||||
"style-mod": "^4.1.0",
|
"style-mod": "^4.1.0",
|
||||||
"w3c-keyname": "^2.2.4"
|
"w3c-keyname": "^2.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
||||||
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
"@jridgewell/set-array": "^1.2.1",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||||
"@jridgewell/trace-mapping": "^0.3.24"
|
"@jridgewell/trace-mapping": "^0.3.24"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
"node_modules/@jridgewell/resolve-uri": {
|
||||||
@@ -182,71 +172,72 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jridgewell/set-array": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/source-map": {
|
"node_modules/@jridgewell/source-map": {
|
||||||
"version": "0.3.11",
|
"version": "0.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
||||||
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
|
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
"@jridgewell/trace-mapping": "^0.3.25"
|
"@jridgewell/trace-mapping": "^0.3.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.5.5",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.31",
|
"version": "0.3.25",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||||
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/common": {
|
"node_modules/@lezer/common": {
|
||||||
"version": "1.3.0",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
||||||
"integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==",
|
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/css": {
|
"node_modules/@lezer/css": {
|
||||||
"version": "1.3.0",
|
"version": "1.1.10",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.10.tgz",
|
||||||
"integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==",
|
"integrity": "sha512-V5/89eDapjeAkWPBpWEfQjZ1Hag3aYUUJOL8213X0dFRuXJ4BXa5NKl9USzOnaLod4AOpmVCkduir2oKwZYZtg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
"@lezer/lr": "^1.3.0"
|
"@lezer/lr": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/highlight": {
|
"node_modules/@lezer/highlight": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
||||||
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
|
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.3.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/html": {
|
"node_modules/@lezer/html": {
|
||||||
"version": "1.3.12",
|
"version": "1.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
|
||||||
"integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==",
|
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -254,10 +245,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/javascript": {
|
"node_modules/@lezer/javascript": {
|
||||||
"version": "1.5.4",
|
"version": "1.4.21",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.21.tgz",
|
||||||
"integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
|
"integrity": "sha512-lL+1fcuxWYPURMM/oFZLEDm0XuLN128QPV+VuGtKpeaOGdcl9F2LYC3nh1S9LkPqx9M0mndZFdXCipNAZpzIkQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.1.3",
|
"@lezer/highlight": "^1.1.3",
|
||||||
@@ -268,7 +258,6 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
||||||
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -276,10 +265,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/lr": {
|
"node_modules/@lezer/lr": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||||
"integrity": "sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==",
|
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -287,14 +275,12 @@
|
|||||||
"node_modules/@marijn/find-cluster-break": {
|
"node_modules/@marijn/find-cluster-break": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
||||||
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
|
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-node-resolve": {
|
"node_modules/@rollup/plugin-node-resolve": {
|
||||||
"version": "15.3.1",
|
"version": "15.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
|
||||||
"integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
|
"integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^5.0.1",
|
"@rollup/pluginutils": "^5.0.1",
|
||||||
"@types/resolve": "1.20.2",
|
"@types/resolve": "1.20.2",
|
||||||
@@ -319,7 +305,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
||||||
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"serialize-javascript": "^6.0.1",
|
"serialize-javascript": "^6.0.1",
|
||||||
"smob": "^1.0.0",
|
"smob": "^1.0.0",
|
||||||
@@ -338,10 +323,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/pluginutils": {
|
"node_modules/@rollup/pluginutils": {
|
||||||
"version": "5.3.0",
|
"version": "5.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
|
||||||
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
|
"integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "^1.0.0",
|
"@types/estree": "^1.0.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
@@ -360,309 +344,248 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
|
||||||
"integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
|
"integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
|
"integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
|
"integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz",
|
||||||
"integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
|
"integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
|
"integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz",
|
||||||
"integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
|
"integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz",
|
||||||
"integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
|
"integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz",
|
||||||
"integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
|
"integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
|
"integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz",
|
||||||
"integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
|
"integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
|
"integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
|
"integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
|
"integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
|
||||||
"version": "4.53.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
|
|
||||||
"integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
|
|
||||||
"cpu": [
|
|
||||||
"riscv64"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
|
"integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
|
"integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz",
|
||||||
"integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
|
"integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
|
||||||
"version": "4.53.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
|
|
||||||
"integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"openharmony"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
|
"integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
|
"integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
|
||||||
"version": "4.53.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
|
|
||||||
"integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
|
"integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||||
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
|
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -674,14 +597,12 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/codemirror": {
|
"node_modules/codemirror": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
|
||||||
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/commands": "^6.0.0",
|
"@codemirror/commands": "^6.0.0",
|
||||||
@@ -696,20 +617,17 @@
|
|||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/crelt": {
|
"node_modules/crelt": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -717,15 +635,13 @@
|
|||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@@ -738,7 +654,6 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
"license": "MIT",
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
@@ -747,7 +662,6 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
},
|
},
|
||||||
@@ -759,7 +673,6 @@
|
|||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hasown": "^2.0.2"
|
"hasown": "^2.0.2"
|
||||||
},
|
},
|
||||||
@@ -773,20 +686,17 @@
|
|||||||
"node_modules/is-module": {
|
"node_modules/is-module": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||||
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -799,18 +709,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.11",
|
"version": "1.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||||
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
|
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-core-module": "^2.16.1",
|
"is-core-module": "^2.16.0",
|
||||||
"path-parse": "^1.0.7",
|
"path-parse": "^1.0.7",
|
||||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
},
|
},
|
||||||
@@ -825,12 +733,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.53.3",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
|
||||||
"integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
|
"integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.8"
|
"@types/estree": "1.0.6"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
@@ -840,28 +747,25 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.53.3",
|
"@rollup/rollup-android-arm-eabi": "4.34.8",
|
||||||
"@rollup/rollup-android-arm64": "4.53.3",
|
"@rollup/rollup-android-arm64": "4.34.8",
|
||||||
"@rollup/rollup-darwin-arm64": "4.53.3",
|
"@rollup/rollup-darwin-arm64": "4.34.8",
|
||||||
"@rollup/rollup-darwin-x64": "4.53.3",
|
"@rollup/rollup-darwin-x64": "4.34.8",
|
||||||
"@rollup/rollup-freebsd-arm64": "4.53.3",
|
"@rollup/rollup-freebsd-arm64": "4.34.8",
|
||||||
"@rollup/rollup-freebsd-x64": "4.53.3",
|
"@rollup/rollup-freebsd-x64": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.53.3",
|
"@rollup/rollup-linux-arm-musleabihf": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.53.3",
|
"@rollup/rollup-linux-arm64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.53.3",
|
"@rollup/rollup-linux-arm64-musl": "4.34.8",
|
||||||
"@rollup/rollup-linux-loong64-gnu": "4.53.3",
|
"@rollup/rollup-linux-loongarch64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-ppc64-gnu": "4.53.3",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.53.3",
|
"@rollup/rollup-linux-riscv64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-riscv64-musl": "4.53.3",
|
"@rollup/rollup-linux-s390x-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.53.3",
|
"@rollup/rollup-linux-x64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.53.3",
|
"@rollup/rollup-linux-x64-musl": "4.34.8",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.53.3",
|
"@rollup/rollup-win32-arm64-msvc": "4.34.8",
|
||||||
"@rollup/rollup-openharmony-arm64": "4.53.3",
|
"@rollup/rollup-win32-ia32-msvc": "4.34.8",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.53.3",
|
"@rollup/rollup-win32-x64-msvc": "4.34.8",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.53.3",
|
|
||||||
"@rollup/rollup-win32-x64-gnu": "4.53.3",
|
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.53.3",
|
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -883,15 +787,13 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/serialize-javascript": {
|
"node_modules/serialize-javascript": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||||
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"randombytes": "^2.1.0"
|
"randombytes": "^2.1.0"
|
||||||
}
|
}
|
||||||
@@ -900,15 +802,13 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
||||||
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -918,23 +818,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-from": "^1.0.0",
|
"buffer-from": "^1.0.0",
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/style-mod": {
|
"node_modules/style-mod": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/supports-preserve-symlinks-flag": {
|
"node_modules/supports-preserve-symlinks-flag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
@@ -943,14 +840,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.44.1",
|
"version": "5.39.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
|
||||||
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
|
"integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.3",
|
"@jridgewell/source-map": "^0.3.3",
|
||||||
"acorn": "^8.15.0",
|
"acorn": "^8.8.2",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
"source-map-support": "~0.5.20"
|
"source-map-support": "~0.5.20"
|
||||||
},
|
},
|
||||||
@@ -964,8 +860,7 @@
|
|||||||
"node_modules/w3c-keyname": {
|
"node_modules/w3c-keyname": {
|
||||||
"version": "2.2.8",
|
"version": "2.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
|
||||||
"license": "MIT"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
deps/libbacktrace
vendored
2
deps/libuv
vendored
42
deps/lit/lit-all.min.js
vendored
2
deps/lit/lit-all.min.js.map
vendored
1
deps/openssl_src
vendored
Submodule
2
deps/picohttpparser
vendored
2
deps/quickjs
vendored
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -11,7 +11,7 @@
|
|||||||
<link rel="icon" type="image/x-icon" href="favicon-FOKUP5Y5.ico">
|
<link rel="icon" type="image/x-icon" href="favicon-FOKUP5Y5.ico">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="speedscope-432XE7GS.js"></script>
|
<script src="speedscope-VHEG2FVF.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||