Tamarack
A framework for building rich, cross-platform apps in pure JavaScript.
One codebase, multiple platforms
Tamarack provides a solid base that adapts to the platform it's running on and provides out of the box support for:
let colorChooser = new TkColorChooser({ parent: "#someExistingElement", color: "blue" });
/* The default setting */
h1 { color: orange; }
/* For iPhones, either in Cordova or in the browser */
[iphone] h1 { color: red; }
/* For Androids, only in Cordova */
[cordova][android] h1 { color: blue; }
/* For Electron apps, running on macOS */
[electron][macos] h1 { color: green; }
Structure
Tamarack has no external dependencies and is made up of these scripts:
- core.js: Functionality used by all of the other scripts.
- color.js: A class to manage nearly every type of CSS color and easily convert between them.
- font.js: A class to simplify the management and manipulation of fonts.
- view.js: Contains a collection of views, which are wrappers around HTML elements inheriting from a class called TkView and can be manipulated entirely through JavaScript, with no HTML boilerplate.
- app.js: Sets up the environment for building cross-platform apps.
- And many more...
Demos
Hello world
A simple hello world demo in Tamarack.
new TkText("h1", { parent: "body", text: "Hello World!" });
Coin toss
Create a button that tosses a coin and prints the result to the screen.
let tossCoinButton = new TkButton({ parent: "body", text: "Toss Coin" });
let results = new TkStack({ parent: "body", direction: TkStackDirection.VERTICAL });
tossCoinButton.on("click", () => {
let result = TkArray.random("Heads", "Tails");
let resultColor = (result == "Heads") ? "maroon" : "midnightblue";
let resultText = new TkText("h2", {
parent: results,
text: result,
style: `color: ${resultColor};`
});
});
Tabs
Managing a notebook with tabs is a fairly common task when developing an application, but it can quickly become a hassle using only plain HTML and JavaScript. With Tamarack, it can be done entirely in JavaScript, without any boilerplate.
A TkNotebook is a view containing pages that contains useful functions and properties for managing pages. It also includes events such as activechanged, addpage, and removepage that you can add event handlers to in order to deal with changes in the notebook.
Each page in a notebook is represented by a TkPage, which includes a tab button and a content panel.
// Declare views
let buttonStack = new TkStack({ parent: "body", direction: TkStackDirection.FLOW });
let previousPageButton = new TkButton({ parent: buttonStack, text: "<" });
let nextPageButton = new TkButton({ parent: buttonStack, text: ">" });
let addPageButton = new TkButton({ parent: buttonStack, text: "Add" });
let removePageButton = new TkButton({ parent: buttonStack, text: "Remove" });
let selectedPageText = new TkText("h2", { parent: "body", style: "margin: 1rem 0;" });
let notebook = new TkNotebook({ parent: "body" });
// Keep track of the pages added
let pageCount = 0;
// Attach button event handlers
previousPageButton.on("click", () => notebook.goToPrevious());
nextPageButton.on("click", () => notebook.goToNext());
addPageButton.on("click", () => {
notebook.add(new TkPage({
title: `Tab ${++pageCount}`,
content: [new TkText("h2", { text: `Content ${pageCount}` })]
}));
});
removePageButton.on("click", () => {
if (notebook.active !== null)
notebook.remove(notebook.active);
});
// Update the selected page text when the current page is changed
notebook.on("activechanged", () => {
selectedPageText.text = (notebook.active != null) ? notebook.active.title : "";
});
Detect dark mode
Easily add event handlers to watch for switches between light and dark mode.
// Insert a text element into <body>
let modeText = new TkText("h1", { parent: "body" });
// Update the text and document colors when the system is
// switched between dark and light mode
function updateMode() {
if (TkDocument.isInDarkMode()) {
document.body.style.backgroundColor = "black";
document.body.style.color = "white";
modeText.text = "Dark Mode";
} else {
document.body.style.backgroundColor = "white";
document.body.style.color = "black";
modeText.text = "Light Mode";
}
}
// Attach the handler to watch for the change
TkDocument.onChangeDarkMode(updateMode);
// Call to update for the current mode
updateMode();
Stacks
Layout views in a stack.
A fundamental view in Tamarack is the TkStack view, which is a flexbox container that exposes useful functionality for laying out child views.
It creates two stacks, buttonStack and colorStack, adds a button to buttonStack for each TkStackDirection to change the stack direction of colorStack, then loops through each hue (0-360), and adds a TkText view representing it to the color stack.
// Declare the layout button stack and add it to the body
let buttonStack = new TkStack({
parent: "body",
direction: TkStackDirection.FLOW
});
// Declare the color stack and add it to the body
let colorStack = new TkStack({
parent: "body",
direction: TkStackDirection.VERTICAL
});
// Add a button for each stack direction
for (let direction in TkStackDirection) {
let button = new TkButton({
parent: buttonStack,
text: direction,
style: "margin: 0.25rem;"
});
button.on("click", () => colorStack.direction = TkStackDirection[direction]);
}
// Loop through hues and add text for each one to the colorStack
for (let i = 0; i <= 360; i++) {
let itemColor = new TkColor(`hsl(${i}, 100%, 50%)`);
let stackItem = new TkText("span", {
parent: colorStack,
style: "font-weight: bold; padding: 0.25rem;"
});
stackItem.style.backgroundColor = itemColor.asHex();
stackItem.style.color = itemColor.isLight() ? "black" : "white";
stackItem.text = itemColor.asHex();
}