T3 is a client-side JavaScript framework for building large-scale web applications

Overview

Build Status Project Status

DEPRECATED

Box has migrated using react, webpack, and the latest version of ECMAScript for our frontend projects as of 2018. We no longer support changes, pull requests, or upgrades to this package. We appreciate all of the user contributions that you have given us over the past few years.

T3 JavaScript Framework

T3 is a client-side JavaScript framework for building large-scale web applications. Its design is based on the principles of Scalable JavaScript Application Architecture, specifically:

  • Enforcing loose coupling between components
  • Making dependencies explicit
  • Providing extension points to allow for unforeseen requirements
  • Abstracting away common pain points
  • Encouraging progressive enhancement

The approaches taken in T3 have been battle-hardened through continuous production use at Box since 2013, where we use T3 along with jQuery, jQuery UI, and several other third-party libraries and frameworks.

Framework Design

T3 is different from most JavaScript frameworks. It's meant to be a small piece of an overall architecture that allows you to build scalable client-side code.

No MVC Here

T3 is explicitly not an MVC framework. It's a framework that allows the creation of loosely-coupled components while letting you decide what other pieces you need for your web application. You can use T3 with other frameworks like Backbone or React, or you can use T3 by itself. If you decide you want model and views, in whatever form, you can still use them with T3.

Unopinionated by Design

T3 is made to be unopinionated while prescribing how some problems might be solved. Our goal here is not to create a single framework that can do everything for you, but rather, to provide some structure to your client-side code that allows you to make good choices. Then, you can add in other libraries and frameworks to suit your needs.

Three Component Types

T3 allows you to define functionality using just three component types:

  1. Services are utility libraries that provide additional capabilities to your application. You can think of services as tools in a toolbox that you use to build an application. They intended to be reusable pieces of code such as cookie parsing, Ajax communication, string utilities, and so on.
  2. Modules represent a particular DOM element on a page and manage the interaction inside of that element. It's a module's job to respond to user interaction within its boundaries. Your application is made up of a series of modules. Modules may not interact directly with other modules, but may do so indirectly.
  3. Behaviors are mixins for modules and are used primarily to allow shared declarative event handling for modules without duplicating code. If, for instance, you use a particular attribute to indicate a link should use Ajax navigation instead of full-page navigation, you can share that functionality amongst multiple modules.

We've found that by using a combination of these three component types, we're able to create compelling, progressively-enhanced user experiences.

Installation

To include T3 in a web page, you can use RawGit.

The last published release:

">











You may also use bower to install t3js:

bower install t3js

Upgrade from 1.5.1 to 2.0.0

T3 2.0.0 was released on November 18th, 2015 with some major changes. To upgrade, please see these instructions.

Getting Started

Your T3 front-end is made up of modules, so the first step is to indicate which modules are responsible for which parts of the page. You can do that by using the data-module attribute and specifying the module ID, such as:

Box

">
<div data-module="header">
    <h1>Boxh1>
    <button data-type="welcome-btn">Show Welcomebutton>
div>

This example specifies the module header should manage this particular part of the page. The module header is then defined as:

Box.Application.addModule('header', function(context) {

    return {

        onclick: function(event, element, elementType) {
            if (elementType === 'welcome-btn') {
                alert('Welcome, T3 user!');
            } else {
                alert('You clicked outside the button.');
            }
        }

    };

});

This is a very simple module that has an onclick handler. T3 automatically wires up specified event handlers so you don't have to worry about using event delegation or removing event handlers when they are no longer needed. The onclick handler receives a DOM-normalized event object that can be used to get event details. When the button is clicked, a message is displayed. Additionally, clicking anywhere inside the module will display a different message. Event handlers are tied to the entire module area, so there's no need to attach multiple handlers of the same type.

The last step is to initialize the T3 application:

Box.Application.init();

This call starts all modules on the page (be sure to include both the T3 library and your module code before calling init()). We recommend calling init() as soon as possible after your JavaScript is loaded. Whether you do that onload, earlier, or later, is completely up to you.

There are more extensive tutorials and examples on our website.

Browser Support

T3 is tested and known to work in the following browsers:

  • Internet Explorer 9 and higher
  • Firefox (latest version)
  • Chrome (latest version)
  • Safari (latest version)

With the exception of Internet Explorer, T3 will continue to support the current and previous one version of all major browsers.

Contributing

The main purpose of sharing T3 is to continue its development, making it faster, more efficient, and easier to use.

Directory Structure

  • config - configuration files for the project
  • dist - browser bundles (this directory is updated automatically with each release)
  • lib - the source code as individual files
  • tests - the test code

Prerequisites

In order to get started contributing to T3, you'll need to be familiar and have installed:

  1. Git
  2. npm
  3. Node.js or IO.js

Setup

Following the instructions in the contributor guidelines to setup a local copy of the T3 repository.

Once you clone the T3 git repository, run the following inside the t3js directory:

$ npm i

This sets up all the dependencies that the T3 build system needs to function.

Note: You'll need to do this periodically when pulling the latest code from our repository as dependencies might change. If you find unexpected errors, be sure to run npm i again to ensure your dependencies are up-to-date.

Running Tests

After that, you can run all tests by running:

$ npm test

This will start by linting the code and then running all unit tests.

Build Commands

The following build commands are available:

  1. npm test - runs all linting and uni tests
  2. npm run lint - runs all linting
  3. npm run dist - creates the browser bundles and places them in /dist

Frequently Asked Questions

Can I use this with older browsers?

We provide a custom version of T3 built with jQuery that is compatible with older browsers such as IE8.

Why support IE8?

The Box web application currently supports IE8 with a planned end-of-life of December 31, 2015. We will be dropping T3 support for IE8 at the same time.

Support

Need to contact us directly? Email [email protected] with your questions or comments.

Copyright and License

Copyright 2015 Box, Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Comments
  • Abstract out DOM methods and event handling

    Abstract out DOM methods and event handling

    A few people have commented that since we use jQuery just for event handling, then it's possible to extract that out so jQuery is no longer a hard dependency. This is a great idea!

    In the discussions within our team, we talked a bit about the preferred approach to doing so. #17 was proposed, but the general feeling was that we don't want to bake jQuery detection into the core of T3. So, we'd like to consider another option where we created something like this:

    Box.Events = {
        on: function(element, type, listener) {},
        off: function(element, type, listenter) {}
    };
    

    Then, we can have both a jQuery version and a native version, while the core of T3 relies on Box.Events.on/off instead of either native or jQuery.

    The remaining question is how best to work that into the bundled version in /dist.

    enhancement 
    opened by nzakas 16
  • Make T3 throw or warn when attempting to retrieve a service that doesn't exist in debug mode

    Make T3 throw or warn when attempting to retrieve a service that doesn't exist in debug mode

    Recently we discovered a ~6mo old bug in our system that was able to persist because T3 silently allowed a features flip service that didn't exist to be retrieved and used as a falsey value in subsequent logic. This could have been identified if T3 had thrown upon attempting to fetch the service, or at least dumped to conosle.warn when in debug mode to at least let a developer know they're attempting to access a service that does not exist.

    For code cleanliness console statements can then later be stripped out during our build process with the drop_console flag when the code is minified for production use.

    enhancement 
    opened by jdivock 13
  • Need a Yeoman generator?

    Need a Yeoman generator?

    Hi there,

    Do you think that T3 needs a Yeoman generator to generate some modules, services and behaviors?

    Looking for some interesting ideas,

    Thanks,

    Barış Güler

    opened by hwclass 12
  • How well does T3 work with ReactJS?

    How well does T3 work with ReactJS?

    I love ReactJS but it basically only renders View and I still need the other things like event handling, etc. It seems T3 has very simple and elegant idea. I tried a bit tonight with T3 + ReactJS. One thing I did notice is that when I run Box.Application.init, it expects that all the elements with data-module attributes are already added to Box.Application.

    It seems I've found that componentWillMount is a good place to write Box.Application.addModule and in componentDidMount, you can run Box.Application.init.

    I attached my code below. Do you think this is the proper way to use T3 and ReactJS? Thank you!

               var CommentBox = React.createClass({
                    getInitialState: function() {
                        return {
                            showSubmit: true
                        };
                    },
    
                    componentWillMount: function() {
                        var r = this;
                        Box.Application.addModule('comment-box', function(context) {
    
                            // private methods here
                            return {
    
                                init: function() {
                                    // capture the reference when the module is started
                                    moduleEl = context.getElement();
                                    console.log(moduleEl);
                                },
    
                                onclick: function(event, element, elementType) {
                                    if (elementType == 'submit-btn') {
                                        r.setState({showSubmit: false});
                                        context.broadcast('submit', 'Submitted!');
                                    } else if (elementType == 'close-btn') {
                                        r.setState({showSubmit: true});
                                        context.broadcast('close', 'Closed!');
                                    }
                                }
    
                            };
                        });
                    },
    
                    render: function() {
                        return (
                            <div className="commentBox" data-module="comment-box">
                                <input type="text" />
                                {this.state.showSubmit ? <button data-type="submit-btn">Submit</button> : <button type="button" data-type="close-btn">Close</button>}
                            </div>
                        );
                    }
                });
    
                var Article = React.createClass({
                    getInitialState: function() {
                        return {text: ''};
                    },
    
                    componentWillMount: function() {
                        var r = this;
                        Box.Application.addModule('article', function(context) {
                            return {
                                messages: ['submit', 'close'],
    
                                onmessage: function(name, data) {
                                    if (name == 'submit') {
                                        r.setState({text: 'submit: ' + data});
                                    } else if (name == 'close') {
                                        r.setState({text: 'close: ' + data});
                                    }
                                }
                            };
                        });
                    },
    
                    render: function() {
                        return (
                            <div data-module="article">
                                <p>{this.state.text}</p>
                            </div>
                        );
                    }
                });
    
                var UI = React.createClass({
                    componentDidMount: function() {
                        Box.Application.init({debug: true});
                    },
    
                    render: function() {
                        return (
                            <div>
                                <CommentBox />
                                <Article />
                            </div>
                        );
                    }
                });
    
                React.render(
                    <UI />,
                    document.getElementById('content')
                );
    
    opened by ktei 12
  • Event listener refactor

    Event listener refactor

    Address issues raised in #12, especially strong jQuery dependency.

    Box team might have bigger fish to fry, so open a pull request here to signal someone is working on it.


    Now it works, I end up doing following changes:

    1. Abstract event system into addListener and removeListener, still prefer jQuery over native add/removeEventListener, but allow seamless fallback.
    2. Update karma config and use mocha reporter instead of progress, this is good because progress does not show which test fails when you do sandbox.verifyAndRestore in afterEach; though generally one should avoid assert (sandbox.verify is implied assert) in afterEach because it cause mocha to abort all subsequent tests.
    3. Update test cases so that it no longer depends on jQuery in global space, by jQuery.noConflict at the start. Note that we still test for jQuery global, see tests for on[event]()
    4. Update travis to include node v0.12 and latest iojs
    opened by bitinn 12
  • Share JSDoc configs?

    Share JSDoc configs?

    Hi guys! I miss working with you, but I'm still using T3 on a daily basis with my clients!! :)

    I'm wondering if there is a way you can share some of your JSDoc configurations for Modules, Services, and Behaviors. I'm having a really hard time trying to setup the proper tags so that all of my modules, services, and behaviors get grouped together in the documentation.

    Can you offer any guidance for tools, configs, and jsdoc tags that would allow me to have namespaces for "Modules", "Services", and "Behaviors", and then have those contain all of the classes of those types?

    Thanks! Adam

    question 
    opened by aplatti 11
  • Use CommonJS in lib files and export new bundle

    Use CommonJS in lib files and export new bundle

    • adding proxyquire for testing browserified source files
    • modified tests to use CommonJS
    • modified build process to account for browserification
    • downgraded karma-coverage to 0.2.6 to support browserify-istanbul
    • updated ESLint rules to account for CommonJS changes

    fixes #24

    enhancement 
    opened by j3tan 10
  • Optimize circular dependencies check

    Optimize circular dependencies check

    I think that may be more effective to check on circular dependencies only during instantiation of service. When an instance of service already exists we should immediately return it.

    P.S. Changes only in lib/application.js file

    opened by rodenis 9
  • Question: why jQuery dependency?

    Question: why jQuery dependency?

    I understand Box.com might be using jQuery features extensively, but if T3's idea is to stay modular, then why not decouple jQuery as well.

    Looking at the documents (apologize if I missed something), it seems jQuery would be used for data-binding, but there can be lots of approach to data-binding, not to mention virtual-dom approach (where binding is handled differently)

    Seems like T3 can be done without jQuery, or at least with alternatives like DOMtastic.

    Either way, I am just very excited to see a framework that takes progressive enhancement into account and I am very interested in using it for my current project.

    opened by bitinn 9
  • Provide a better way with dealing with missing modules in debug mode

    Provide a better way with dealing with missing modules in debug mode

    Currently when a module is missing in debug mode an exception is thrown. That's all well and good, but it prevents T3 from continuing its initialization. We have a situation where multiple engineers will be working on one environment and sometimes they use a proxy to make a local version of their script to the page which may not have a module that the dom for that environment has listed. This is fine in non-debug mode, but when debug is enabled it completely borks the process.

    Granted I realize our development process at the moment may be more at fault then how T3 functions, but it would be nice to be able to see the error but not have T3 stop the initialization process when that error occurs.

    opened by zephraph 8
  • Better message handling

    Better message handling

    Currently when one wants to handle messages or events they add something like the following

    return {
      onmessage: function(name, data) {
         switch(name) {
            case 'test-message': test(data);
            break;
            // ...
         }
      }
    }
    

    Something like that, right? Well, maybe instead of a switch an if else statements is used. Regardless, that breakdown is up to the individual who implements the module/behavior/service in question.

    I pulled this straight from the docs:

    Don't include application logic in the event handler. Everything the module is capable of doing should be represented as a method on the object and the event handler should call out to those methods.

    This interface doesn't naturally support that. On the contrary, I feel like it encourages the bad practice of handling all cases directly inside that method.

    I'm proposing an improvement to message/event handling where an object can be passed to on* as an alternative to passing a function.

    Example

    return {
      onmessage: {
        'test-message': function(name, data) {
         }
      }
    }
    

    This interface ensures that there's a function that handles every message instead of a single function that handles all messages. There's no noisy if or switch statements to deal with. The other thing this setup makes me think is, now that it's known what messages are being handled by the T3 construct, it's not necessary to specify messages at all because that'd just be redundant. T3 can just scrape the messages off the onmessage object.

    My current proposal isn't to get rid of messages or the fact that onmessage or onclick can be a function. It's really just the addition for something like onmessage to be an object. Though, I will say that given the next "major" release, which might be a while from now, it would be good to consider the former points.

    Thoughts?

    opened by zephraph 8
Releases(v2.7.0)
  • v2.7.0(Aug 26, 2016)

  • v2.6.0(Jul 13, 2016)

  • v2.5.0(May 21, 2016)

  • v2.4.0(Mar 23, 2016)

    • Add reportWarning to test service provider (Jeff Tan)
    • Add custom event types (Jeff Tan)
    • Add reportWarning to Box.Application (Jeff Tan)
    • Include the data-module element when finding event targets (Jeff Tan)
    Source code(tar.gz)
    Source code(zip)
  • v2.3.0(Mar 16, 2016)

  • v2.2.0(Mar 15, 2016)

  • v2.1.0(Feb 1, 2016)

  • v2.0.2(Nov 19, 2015)

  • v2.0.1(Nov 18, 2015)

  • v2.0.0(Nov 18, 2015)

    Warning: This version had issues with the release script, please use v2.0.1

    • Add separate file header for testing package (Jeff Tan)
    • Fixing spaces in build script (Jeff Tan)
    • Return singleton service instance when getService is called on pre-registered services (Jeff Tan)
    • Add mousemove to allowed event types (Jeff Tan)
    • Update README.md (Jeff Tan)
    • Remove service exports from T3 (Jeff Tan)
    • Update Readme for 2.0.0 release and add auto-version updating (Jeff Tan)
    • Add hasService() to context object (Jeff Tan)
    • [Breaking] Add allowedServiceList to TestServiceProvider (Jeff Tan)
    • Use jQuery instead of $ for dom event delegation (Jeff Tan)
    • Add linting to test directory (Jeff Tan)
    • Breaking: Initialize behaviors before module (Jeff Tan)
    • Change getService() to throw error when requesting non-existent service. Add hasService() method. (Jeff Tan)
    • Bind event handlers after init() is called (Jeff Tan)
    • Throw error when duplicate behaviors are included (Jeff Tan)
    • Revert "Check for circular dependencies only during instantiation of service" (Denis Rodin)
    • Check for circular dependencies only during instantiation of service (Denis Rodin)
    • Check for circular dependencies only during instantiation of service (Denis Rodin)
    • Breaking: Use NativeDOM by default (fixes #76) (Nicholas C. Zakas)
    • Build: Upgrade ESLint (fixes #90) (Nicholas C. Zakas)
    Source code(tar.gz)
    Source code(zip)
  • v1.5.1(Oct 27, 2015)

  • v1.5.0(Aug 5, 2015)

    • Update: Make Box.Application chainable (fixes #65) (Nicholas C. Zakas)
    • New: Add Box.DOMEventDelegate (fixes #47, fixes #63) (Nicholas C. Zakas)
    • Update email address for support (Nicholas C. Zakas)
    Source code(tar.gz)
    Source code(zip)
  • v1.4.1(Aug 5, 2015)

  • v1.4.0(Jun 11, 2015)

  • v1.3.0(Jun 9, 2015)

    • Breaking out dom events into an abstraction layer, building different versions of t3 accordingly (Jason Divock)
    • Add AMD support. Fixes #50 (Priyajeet Hora)
    • Fix release script (Nicholas C. Zakas)
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Apr 24, 2015)

    • Change karma to use mocha reporter (Jeff Tan)
    • Fix embedded sourcemap URL (fixes #31) (Nicholas C. Zakas)
    • Add wrapper to T3 for CommonJS (Jeff Tan)
    • Remove event delegation on detached nodes (Jeff Tan)
    • Update: Fire event when broadcast() is called (fixes #43) (Nicholas C. Zakas)
    • Reverting dist changes (Priyajeet Hora)
    • Prevent event-target.js duplicate handlers. Fixes #35. (Priyajeet Hora)
    • Clean up duplicated assign code (fixes #29) (azu)
    • Todo example fails to update completed items. Fixes #25 (Priyajeet Hora)
    • Firefox innerText fixes as well as switching the select all checkbox logic to use the model data instead of view elements Fixes #21 (Priyajeet Hora)
    • readme grammar (Matthew Hadley)
    • Apply or remove completed class when select all is clicked. Fixes #18. (Priyajeet Hora)
    • Adding missing doctype Fixes #14 (Priyajeet Hora)
    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Apr 24, 2015)

    • Update build script to publish to npm and update site (Nicholas C. Zakas)
    • Add Travis configuration (Nicholas C. Zakas)
    • Add sourcemap generation (Nicholas C. Zakas)
    • Update README with badges and more info (Nicholas C. Zakas)
    • Missing semicolon in application-stub.js Fixes #4 (Priyajeet Hora)
    • Create t3-testing bundle (Jeff Tan)
    • Updating Karam coverage dir and adding it to gitignore (Tarrence van As)
    • Add ESLint to package.json (Jeff Tan)
    • Add license and contribution guide (Nicholas C. Zakas)
    • Rename t3 to t3js (Jeff Tan)
    • Adding items to .npmignore. Fixes #60. (Priyajeet Hora)
    • Adding items to .npmignore. Fixes #60. (Priyajeet Hora)
    • Adding npmignore. Fixes #60 (Priyajeet Hora)
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Apr 24, 2015)

    • Fix release task (Nicholas C. Zakas)
    • Add changelog generation (Nicholas C. Zakas)
    • Update README for open sourcing (Nicholas C. Zakas)
    • Remove most jQuery references (Nicholas C. Zakas)
    • Switch to ShellJS and create dist files (Nicholas C. Zakas)
    • Add focusin and focusout events (Jeff Tan)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.2(Apr 24, 2015)

Owner
Box
Box, Inc.
Box
A large scale simulation which pits millions of space ships against each other in a virtual universe all running directly in SingleStore.

Wasm Space Program In this demo we simulate a fake universe full of thousands of solar systems. In each solar system there are many space ships and en

SingleStore Labs 11 Nov 2, 2022
🗃️ An in-memory JS database optimized for large scale storage on the frontend.

BlinkDB is a in-memory JS database optimized for large scale storage on the frontend. import { many } from 'blinkdb'; const items = await many(userTa

BlinkDB 64 Dec 23, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Fast and minimal JS server-side writer and client-side manager.

unihead Fast and minimal JS <head> server-side writer and client-side manager. Nearly every SSR framework out there relies on server-side components t

Jonas Galvez 24 Sep 4, 2022
Easy server-side and client-side validation for FormData, URLSearchParams and JSON data in your Fresh app 🍋

Fresh Validation ??     Easily validate FormData, URLSearchParams and JSON data in your Fresh app server-side or client-side! Validation Fresh Validat

Steven Yung 20 Dec 23, 2022
Toolkit for building scalable web applications with TypeScript, React, Redux and Apollo-Client

TsToolbox Toolkit for building scalable web applications with TypeScript, React, Redux and Apollo-Client (inspired by ReKit) ⚠ ⚠ ⚠ Work in Progress ⚠

Daniel Nikravesh 7 Apr 14, 2022
⚛ A comprehensive framework for server-side applications

⚛ A comprehensive framework for server-side applications. Being built on top of TypeScript, it surprisingly supports native Web APIs. It can also be used for REST/GraphQL and many others.

null 4 Jul 4, 2022
Web Scale™ Anarchy SponsorBlock Server

Web Scale SponsorBlock Server Joke Fork of ajayyy/SponsorBlockServer Now backed by Web Scale MangoDB (thanks @grub for the native nc port) Now with no

Michael M. Chang 6 Sep 28, 2022
College project done for the CG Artwork lecture in 2022. Used HTML for the indexes and mainly JavaScript (using to THREE.js). Ended with the final A grade (17.3 in scale grade).

CG Artwork Project 2022 This project was done by a group of 3 in 2022 with an educational purpose for the CG Artwork lecture in Instituto Superior Téc

filipe_neves 3 Sep 19, 2022
Fnon is a client-side JavaScript library for models, loading indicators, notifications, and alerts which makes your web projects much better.

???????? Fnon is the name of my late mother, It's an Arabic word which means Art, I created this library in honor of her name. Fnon is a client-side J

Adel N Al-Awdy 5 Sep 11, 2022
Make drag-and-drop easier using DropPoint. Drag content without having to open side-by-side windows

Make drag-and-drop easier using DropPoint! DropPoint helps you drag content without having to open side-by-side windows Works on Windows, Linux and Ma

Sudev Suresh Sreedevi 391 Dec 29, 2022
This is an application that entered the market with a mobile application in real life. We wrote the backend side with node.js and the mobile side with flutter.

HAUSE TAXI API Get Started Must be installed on your computer Git Node Firebase Database Config You should read this easy documentation Firebase-Fires

Muhammet Çokyaman 4 Nov 4, 2021
This plugin allows side-by-side notetaking with videos. Annotate your notes with timestamps to directly control the video and remember where each note comes from.

Obsidian Timestamp Notes Use Case Hello Obsidian users! Like all of you, I love using Obsidian for taking notes. My usual workflow is a video in my br

null 74 Jan 2, 2023
This Plugin is For Logseq. If you're using wide monitors, you can place journals, linked references, and journal queries side by side.

Logseq Column-Layout Plugin Journals, linked references, and journal queries can be placed side by side if the minimum screen width is "1850px" or mor

YU 14 Dec 14, 2022
A fast, feature rich and simple framework for building dynamic browser applications.

hyperdom A simple, fast, feature rich framework for building dynamic browser applications. Hyperdom supports a simple event-update-render cycle, promi

Featurist 163 Nov 11, 2022
A easy-to-use framework for building immersive decentralized applications

A easy-to-use framework for building immersive decentralized applications

Sonr 624 Dec 27, 2022
aka Scaletor, take screenshots of a piece of a map and scale/compare with other parts of the map

scale-a-tron A quick-and-dirty map that lets you compare one area to another. Draw a shape around a region, zoom in to another place on the map, and c

Stamen Design 24 Nov 7, 2022