diff --git a/.github/workflows/biome.yml b/.github/workflows/biome.yml index 131726b..c2486a7 100644 --- a/.github/workflows/biome.yml +++ b/.github/workflows/biome.yml @@ -14,7 +14,7 @@ jobs: steps: - name: "Checkout code" - uses: "actions/checkout@v4" + uses: "actions/checkout@v5" with: token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d906365..8faac8c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,9 +8,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 'lts/*' - name: Setup pnpm diff --git a/.github/workflows/upk-build.yml b/.github/workflows/upk-build.yml new file mode 100644 index 0000000..36e5c74 --- /dev/null +++ b/.github/workflows/upk-build.yml @@ -0,0 +1,47 @@ +name: Build UPK for Anura +on: + push: + paths: + - 'package.json' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + - name: Set up Node + uses: actions/setup-node@v6 + with: + node-version: 'lts/*' + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: '3.13' + - name: Install dependencies + run: pnpm i + - name: Install BareMux v1 + run: pnpm i @mercuryworkshop/bare-mux@^1.1.4 + - name: Download upk-tools.zip + run: curl -L -o upk-tools.zip https://cdn.terbiumon.top/upk-tools.zip + - name: Extract upk-tools + run: unzip -o upk-tools.zip + - name: replace BCC Client v2 with v1 + run: mv bx1bcc.ts src/sys/liquor/bcc.ts + - name: Add BareMux Script + run: npx replace-in-file "
" " " index.html + - name: Replace BareMux in codebase + run: bash replace.sh + - name: Build TB React + run: pnpm run build-static + - name: "Run UPK Builder" + run: python3 upk.py + - name: Upload UPK + uses: actions/upload-artifact@v4 + with: + name: UPK + path: terbium-upk.app.zip diff --git a/.gitignore b/.gitignore index cc55a45..4fcfaee 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ dist-ssr *.local *.tsbuildinfo .npmrc -pnpm-lock.yaml package-lock.json # Editor directories and files diff --git a/README.md b/README.md index 168a95b..c0380bb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ - [Vite](https://vite.dev) - [React](https://react.dev) - [TailwindCSS](https://tailwindcss.com) -- [FilerJS](https://github.com/filerjs/filer) +- [TFS](https://github.com/terbiumos/tfs) - [Fflate](https://github.com/101arrowz/fflate/) - [BareMux](https://github.com/mercuryworkshop/bare-mux) diff --git a/SECURITY.md b/SECURITY.md index d7eb9b8..7857491 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,6 +15,7 @@ If your version of terbium is unsupported, please do not make a GitHub Issue abo | Version | Supported | | ------- | --------- | +| 2.1.0 (stable) | ❌ | | 2.1.1 (stable) | ✅ | ### Supported Lemonade Versions diff --git a/biome.json b/biome.json index 9c1126c..205b38a 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", "vcs": { "enabled": false, "clientKind": "git", @@ -14,6 +14,11 @@ "indentWidth": 4, "lineWidth": 320 }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, "linter": { "enabled": true, "rules": { diff --git a/docs/README.md b/docs/README.md index 5fd9e5a..a982855 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,6 @@ Welcome to Terbium v2's Documentation. Here is a simple table of contents to help you get where you need to get - [How to Contribute to Terbium v2](./contributions.md) -- [Quick Guide to Filer](./quick-guide-to-filer.md) - [Creating Terminal Commands](./creating-terminal-commands.md) - [Creating Apps](./creating-apps.md) - [Backend Configuration Options](./backend-configuration.md) diff --git a/docs/apis/readme.md b/docs/apis/readme.md index 66f1bba..74d7055 100644 --- a/docs/apis/readme.md +++ b/docs/apis/readme.md @@ -15,6 +15,7 @@ So you're looking to use Terbium APIs. Well, you're in the right place! Terbium - [Platform](#platform) - [Process](#process) - [Screen](#screen) + - [VFS](#vfs) - [System](#system) - [Mediaisland](#mediaisland) - [File](#file) @@ -456,7 +457,7 @@ So you're looking to use Terbium APIs. Well, you're in the right place! Terbium - **FileBrowser** - Description: Simple FileBrowser Dialog - Parameters: - - `props: { title: string, filter: string, onOk: Function }` - FileBrowser dialog properties. + - `props: { title: string, filter: string, onOk: Function, onCancel: Function, local: boolean }` - FileBrowser dialog properties. - Example: ```javascript await tb.dialog.FileBrowser({ @@ -469,7 +470,7 @@ So you're looking to use Terbium APIs. Well, you're in the right place! Terbium - **DirectoryBrowser** - Description: Simple FileBrowser Dialog - Parameters: - - `props: { title: string, filter: string, onOk: Function }` - FileBrowser dialog properties. + - `props: { title: string, filter: string, onOk: Function, onCancel: Function, local: boolean }` - FileBrowser dialog properties. - Example: ```javascript await tb.dialog.DirectoryBrowser({ @@ -482,7 +483,7 @@ So you're looking to use Terbium APIs. Well, you're in the right place! Terbium - **SaveFile** - Description: Simple File Saving Dialog - Parameters: - - `props: { title: string, defualtDir: string, filename: string, onOk: Function }` - SaveFile dialog properties. + - `props: { title: string, defualtDir: string, filename: string, onOk: Function, onCancel: Function, local: boolean }` - SaveFile dialog properties. - Example: ```javascript await tb.dialog.SaveFile({ @@ -583,6 +584,184 @@ So you're looking to use Terbium APIs. Well, you're in the right place! Terbium tb.screen.capture() ``` +### VFS + - **servers** + - Description: A Map of the current users webdav servers + - Returns: `Object` - VFSOperations + - Example: + ```js + for (const instance of tb.vfs.servers) { + const davInfo = instance[1]; + // Use dav instance info here including a already established connection if one is availible + } + ``` + - **currentServer** + - Description: The current WebDav server to use for operations + - Returns: `Object` - VFSOperations + - Example: + ```js + const client = tb.vfs.currentServer.connection.client; + // use webdav methods here or use VFS Operations as a drop in for working between TFS and VFS + ``` + + - **create** + - Description: (async) Returns a new instance of VFS, You will probably not use this function unless your directly modifying terbiums codebase + - Returns: `Promise💡 Tip: If you notice Terbium lagging with this feature enabled, try disabling it to improve performance on older or potato devices.
@@ -386,9 +389,9 @@ async function getWispSrvs() {
getWispSrvs();
async function updateTransport(transport) {
- const st = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ const st = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
st["transport"] = transport;
- await window.parent.tb.fs.promises.writeFile(`/home/${await window.tb.user.username()}/settings.json`, JSON.stringify(st), "utf8");
+ await window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(st), "utf8");
}
const accentPreview = document.querySelector(".accent-preview");
@@ -396,14 +399,14 @@ const accentMousedown = async () => {
const defaultAccent = "#32ae62";
accentPreview.classList.remove("group", "cursor-pointer");
accentPreview.style.setProperty("--accent", defaultAccent);
- let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
settings["accent"] = defaultAccent;
- window.parent.tb.fs.promises.writeFile(`/home/${await window.tb.user.username()}/settings.json`, JSON.stringify(settings));
+ window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(settings));
accentPreview.removeEventListener("mousedown", accentMousedown);
};
const getAccent = async () => {
- const settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ const settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
var accentColor = settings["accent"];
const defaultAccent = "#32ae62";
if (accentColor !== defaultAccent) {
@@ -431,17 +434,18 @@ custom_accent.addEventListener("click", e => {
const g = rgb[1];
const b = rgb[2];
color = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
- let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
settings["accent"] = color;
- window.parent.tb.fs.promises.writeFile(`/home/${await window.tb.user.username()}/settings.json`, JSON.stringify(settings));
+ window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(settings));
} else {
- let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
settings["accent"] = color;
- window.parent.tb.fs.promises.writeFile(`/home/${await window.tb.user.username()}/settings.json`, JSON.stringify(settings));
+ window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(settings));
}
accentPreview.style.setProperty("--accent", color);
accentPreview.classList.add("group", "cursor-pointer");
accentPreview.addEventListener("mousedown", accentMousedown);
+ window.parent.window.dispatchEvent(new Event("upd-accent"));
});
});
@@ -489,7 +493,7 @@ window.parent.tb.fs.readFile(`/home/${sessionStorage.getItem("currAcc")}/user.js
pfpEl.src = data["pfp"];
});
-pfpEl.addEventListener("click", e => {
+pfpEl.addEventListener("click", async e => {
const uploader = document.createElement("input");
uploader.type = "file";
uploader.accept = "img/*";
@@ -502,6 +506,30 @@ pfpEl.addEventListener("click", e => {
title: "Resize your Profile picture",
img: reader.result,
onOk: async img => {
+ if (await window.parent.tb.tauth.isTACC()) {
+ tb.dialog.Select({
+ title: "Do you want to upload this profile picture to your Terbium Account?",
+ options: [
+ {
+ text: "Yes",
+ value: "yes",
+ },
+ {
+ text: "No",
+ value: "no",
+ },
+ ],
+ onOk: async choice => {
+ if (choice === "yes") {
+ await window.parent.tb.tauth.updateInfo({
+ pfp: img,
+ });
+ } else {
+ return;
+ }
+ },
+ });
+ }
const uSettings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${sessionStorage.getItem("currAcc")}/user.json`, "utf8"));
uSettings["pfp"] = img;
pfpEl.src = img;
@@ -590,7 +618,7 @@ permEl.addEventListener("click", async () => {
sudo: true,
title: "Authenticate to change your permissions",
defaultUsername: sessionStorage.getItem("currAcc"),
- onOk: async (username, password) => {
+ onOk: async (_username, password) => {
const pass = await tb.crypto(password);
if (pass === data["password"]) {
await tb.dialog.Select({
@@ -628,6 +656,87 @@ permEl.addEventListener("click", async () => {
}
});
+const actype = document.querySelector(".actype");
+actype.addEventListener("click", async () => {
+ await tb.dialog.Select({
+ title: "Select Option",
+ options: [
+ {
+ text: "Link Terbium Cloud™ Account",
+ value: "cloud",
+ },
+ {
+ text: "Convert to Local Account",
+ value: "local",
+ },
+ ],
+ onOk: async choice => {
+ switch (choice) {
+ case "cloud":
+ const res = await window.parent.tb.tauth.signIn();
+ actype.innerHTML = "Terbium Cloud\u2122 Account";
+ window.parent.tb.fs.readFile(`/home/${sessionStorage.getItem("currAcc")}/user.json`, "utf8", async (err, data) => {
+ if (err) return console.log(err);
+ data = JSON.parse(data);
+ data["username"] = res.data.user.name;
+ await window.parent.tb.fs.promises.writeFile(`/home/${sessionStorage.getItem("currAcc")}/user.json`, JSON.stringify(data));
+ let desktopDat = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${sessionStorage.getItem("currAcc")}/desktop/.desktop.json`, "utf8"));
+ desktopDat = desktopDat.map(entry => {
+ entry.item = entry.item.replace(`/home/${sessionStorage.getItem("currAcc")}/`, `/home/${res.data.user.name}/`);
+ return entry;
+ });
+ await window.parent.tb.fs.promises.rename(`/home/${sessionStorage.getItem("currAcc")}`, `/home/${res.data.user.name}`);
+ await window.parent.tb.fs.promises.writeFile(`/home/${res.data.user.name}/desktop/.desktop.json`, JSON.stringify(desktopDat));
+ await window.parent.tb.fs.promises.rename(`/apps/user/${sessionStorage.getItem("currAcc")}`, `/apps/user/${res.data.user.name}`);
+ window.parent.tb.fs.readFile("/system/etc/terbium/settings.json", "utf8", async (err, data) => {
+ if (err) return console.log(err);
+ data = JSON.parse(data);
+ data["defaultUser"] = res.data.user.name;
+ await window.parent.tb.fs.promises.writeFile("/system/etc/terbium/settings.json", JSON.stringify(data));
+ });
+ const fcfg = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${res.data.user.name}/files/config.json`, "utf8"));
+ fcfg.drives["File System"] = `/home/${res.data.user.name}/`;
+ await window.parent.tb.fs.promises.writeFile(`/apps/user/${res.data.user.name}/files/config.json`, JSON.stringify(fcfg));
+ const qcfg = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${res.data.user.name}/files/quick-center.json`, "utf8"));
+ for (const key in qcfg.paths) {
+ if (Object.prototype.hasOwnProperty.call(qcfg.paths, key)) {
+ qcfg.paths[key] = qcfg.paths[key].replace(sessionStorage.getItem("currAcc"), res.data.user.name);
+ }
+ }
+ await window.parent.tb.fs.promises.writeFile(`/apps/user/${res.data.user.name}/files/quick-center.json`, JSON.stringify(qcfg));
+ sessionStorage.setItem("currAcc", res.data.user.name);
+ });
+ window.parent.tb.system.users.update({
+ username: res.data.user.name,
+ pfp: res.data.user.image,
+ });
+ break;
+ case "local":
+ await window.parent.tb.tauth.signOut();
+ actype.innerHTML = "Local Account";
+ break;
+ }
+ },
+ });
+});
+
+window.parent.tb.fs.readFile(`/system/etc/terbium/taccs.json`, "utf8", (err, data) => {
+ if (err) actype.innerHTML = "Local Account";
+ const entries = JSON.parse(data);
+ const act = sessionStorage.getItem("currAcc");
+ try {
+ let isCloud = false;
+ if (Array.isArray(entries)) {
+ isCloud = entries.some(e => e && e.username === act);
+ } else if (entries && typeof entries === "object") {
+ isCloud = Object.values(entries).some(e => e && e.username === act);
+ }
+ actype.innerHTML = isCloud ? "Terbium Cloud\u2122 Account" : "Local Account";
+ } catch (e) {
+ actype.innerHTML = "Local Account";
+ }
+});
+
window.parent.tb.fs.readFile(`/home/${sessionStorage.getItem("currAcc")}/user.json`, "utf8", (err, data) => {
if (err) return console.log(err);
data = JSON.parse(data);
@@ -701,7 +810,7 @@ accountsButton.addEventListener("mousedown", e => {
const batteryPercentage = document.querySelector(".battery-percentage");
(async () => {
- let showBatteryPercentage = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"))["battery-percent"];
+ let showBatteryPercentage = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"))["battery-percent"];
const realCheckbox = batteryPercentage.querySelector("input[type='checkbox']");
if (showBatteryPercentage) {
realCheckbox.checked = true;
@@ -715,7 +824,7 @@ const batteryPercentage = document.querySelector(".battery-percentage");
})();
batteryPercentage.addEventListener("mousedown", async e => {
- let data = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ let data = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
const realCheckbox = batteryPercentage.querySelector("input[type='checkbox']");
realCheckbox.checked = !realCheckbox.checked;
const checkIcon = batteryPercentage.querySelector(".checkIcon");
@@ -727,11 +836,11 @@ batteryPercentage.addEventListener("mousedown", async e => {
tb.battery.hidePercentage();
}
data["battery-percent"] = realCheckbox.checked;
- window.parent.tb.fs.promises.writeFile(`/home/${await window.tb.user.username()}/settings.json`, JSON.stringify(data));
+ window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(data));
});
const getBat = async () => {
- const battery = await window.tb.battery.canUse();
+ const battery = await window.parent.tb.battery.canUse();
if (!battery) {
document.querySelector(".battery").remove();
}
@@ -751,7 +860,7 @@ showCords.addEventListener("mousedown", async e => {
});
async function exportSettings() {
- let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
let data = JSON.stringify(settings);
let blob = new Blob([data], { type: "application/json" });
let url = URL.createObjectURL(blob);
@@ -761,6 +870,68 @@ async function exportSettings() {
a.click();
}
+const range = document.getElementById("blurRange");
+const pct = document.getElementById("blurPercent");
+async function render(initial) {
+ const settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${sessionStorage.getItem("currAcc")}/settings.json`, "utf8"));
+ const v = initial ? settings.window.blurlevel : Number(range.value);
+ if (initial) range.value = v;
+ const mapped = Math.round((v / 50) * 100);
+ pct.textContent = mapped + "%";
+ const fill = (v / 50) * 100;
+ range.style.background = `linear-gradient(90deg,#60a5fa ${fill}%, rgba(255,255,255,0.12) ${fill}%)`;
+ range.dataset.mappedPercent = mapped;
+ if (initial) return;
+ settings.window.blurlevel = v;
+ window.parent.tb.fs.promises.writeFile(`/home/${sessionStorage.getItem("currAcc")}/settings.json`, JSON.stringify(settings, null, 4), "utf8");
+ window.parent.dispatchEvent(new Event("upd-accent"));
+}
+
+render(true);
+range.addEventListener("input", () => render(false));
+
+const winAccent = document.querySelector(".winaccent-preview");
+const winAccentPrev = async () => {
+ const defaultAccent = "#ffffff";
+ accentPreview.classList.remove("group", "cursor-pointer");
+ accentPreview.style.setProperty("--accent", defaultAccent);
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
+ settings.window.winAccent = defaultAccent;
+ window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(settings));
+ winAccent.removeEventListener("mousedown", winAccentPrev);
+ window.parent.dispatchEvent(new Event("upd-accent"));
+};
+winAccentPrev();
+
+const custom_waccent = document.querySelector(".custom-waccent");
+custom_waccent.addEventListener("click", e => {
+ const color_picker = document.createElement("input");
+ color_picker.type = "color";
+ color_picker.click();
+ color_picker.addEventListener("change", async e => {
+ let color = color_picker.value;
+ if (color.charAt(0) !== "#") {
+ const rgb = color.match(/\d+/g);
+ const r = rgb[0];
+ const g = rgb[1];
+ const b = rgb[2];
+ color = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
+ settings["window"]["winAccent"] = color;
+ window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(settings));
+ window.parent.dispatchEvent(new Event("upd-accent"));
+ } else {
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
+ settings["window"]["winAccent"] = color;
+ window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(settings));
+ window.parent.dispatchEvent(new Event("upd-accent"));
+ }
+ winAccent.style.setProperty("--accent", color);
+ winAccent.classList.add("group", "cursor-pointer");
+ winAccent.addEventListener("mousedown", winAccentPrev);
+ });
+});
+
async function convertTBSIF() {
const input = document.createElement("input");
input.type = "file";
@@ -770,8 +941,8 @@ async function convertTBSIF() {
let reader = new FileReader();
reader.onload = async () => {
let tbs_config = reader.result;
- let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
- let syssettings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.tb.user.username()}/settings.json`, "utf8"));
+ let settings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
+ let syssettings = JSON.parse(await window.parent.tb.fs.promises.readFile(`/home/${await window.parent.tb.user.username()}/settings.json`, "utf8"));
if (tbs_config.theme && tbs_config.theme !== "default") {
syssettings.theme = tbs_config.theme;
}
@@ -784,7 +955,7 @@ async function convertTBSIF() {
if (tbs_config.shadow === "yes") {
settings["system-blur"] = true;
}
- await window.parent.tb.fs.promises.writeFile(`/home/${await window.tb.user.username()}/settings.json`, JSON.stringify(settings, null, 2), "utf8");
+ await window.parent.tb.fs.promises.writeFile(`/home/${await window.parent.tb.user.username()}/settings.json`, JSON.stringify(settings, null, 2), "utf8");
await window.parent.tb.fs.promises.writeFile("/system/etc/terbium/settings.json", JSON.stringify(syssettings, null, 2), "utf8");
parent.window.location.reload();
};
@@ -819,7 +990,7 @@ const setupWindowOptimizations = async () => {
const realCheckbox = windowOptimizationsCheckbox.querySelector("input[type='checkbox']");
const checkIcon = windowOptimizationsCheckbox.querySelector(".checkIcon");
- const setState = async (enabled) => {
+ const setState = async enabled => {
realCheckbox.checked = enabled;
if (enabled) {
checkIcon.classList.remove("opacity-0", "scale-85");
@@ -851,7 +1022,7 @@ const setupFPSCounter = async () => {
const realCheckbox = fpsCounterCheckbox.querySelector("input[type='checkbox']");
const checkIcon = fpsCounterCheckbox.querySelector(".checkIcon");
- const setState = async (enabled) => {
+ const setState = async enabled => {
realCheckbox.checked = enabled;
if (enabled) {
checkIcon.classList.remove("opacity-0", "scale-85");
@@ -863,7 +1034,7 @@ const setupFPSCounter = async () => {
settings.showFPS = enabled;
await window.parent.tb.fs.promises.writeFile(`/home/${await window.tb.user.username()}/settings.json`, JSON.stringify(settings, null, 2), "utf8");
- window.parent.dispatchEvent(new CustomEvent('settings-changed', { detail: { showFPS: enabled } }));
+ window.parent.dispatchEvent(new CustomEvent("settings-changed", { detail: { showFPS: enabled } }));
};
try {
@@ -883,7 +1054,7 @@ setupFPSCounter();
const realCheckbox = animationCheckbox.querySelector("input[type='checkbox']");
realCheckbox.checked = !realCheckbox.checked;
const checkIcon = animationCheckbox.querySelector(".checkIcon");
-if(realCheckbox.checked) {
+if (realCheckbox.checked) {
checkIcon.classList.remove("opacity-0", "scale-85");
} else {
checkIcon.classList.add("opacity-0", "scale-85");
diff --git a/public/apps/settings.tapp/select.js b/public/apps/settings.tapp/select.js
index 77012cf..da38afa 100644
--- a/public/apps/settings.tapp/select.js
+++ b/public/apps/settings.tapp/select.js
@@ -91,6 +91,22 @@ selects.forEach(select => {
window.tb.fs.writeFile("/system/etc/terbium/settings.json", JSON.stringify(settings));
window.parent.dispatchEvent(new Event("updWeather"));
});
+ } else if (select.getAttribute("action-for") === "wmx") {
+ window.tb.fs.readFile(`/home/${sessionStorage.getItem("currAcc")}/settings.json`, "utf8", (err, data) => {
+ if (err) return console.log(err);
+ let settings = JSON.parse(data);
+ settings["window"]["alwaysMaximized"] = option.getAttribute("value").toLowerCase() === "yes" ? true : false;
+ window.tb.fs.writeFile(`/home/${sessionStorage.getItem("currAcc")}/settings.json`, JSON.stringify(settings));
+ window.parent.dispatchEvent(new Event("upd-accent"));
+ });
+ } else if (select.getAttribute("action-for") === "wfs") {
+ window.tb.fs.readFile(`/home/${sessionStorage.getItem("currAcc")}/settings.json`, "utf8", (err, data) => {
+ if (err) return console.log(err);
+ let settings = JSON.parse(data);
+ settings["window"]["alwaysFullscreen"] = option.getAttribute("value").toLowerCase() === "yes" ? true : false;
+ window.tb.fs.writeFile(`/home/${sessionStorage.getItem("currAcc")}/settings.json`, JSON.stringify(settings));
+ window.parent.dispatchEvent(new Event("upd-accent"));
+ });
}
}
});
diff --git a/public/apps/terminal.tapp/index.js b/public/apps/terminal.tapp/index.js
index 641bebb..82887c4 100644
--- a/public/apps/terminal.tapp/index.js
+++ b/public/apps/terminal.tapp/index.js
@@ -1,7 +1,6 @@
import parser from "yargs-parser";
import http from "iso-http";
import git from "git";
-import * as webdav from "/fs/apps/system/files.tapp/webdav.js";
/**
* @typedef {import("yargs-parser").Arguments} argv
@@ -21,7 +20,6 @@ const tb = window.tb || window.parent.tb || {};
window.http = http;
window.gitfetch = git;
-window.webdav = webdav;
/**
* Converts a hex color to an RGB string
@@ -211,8 +209,8 @@ async function handleCommand(name, args) {
}
try {
const script = await scriptRes.text();
- const fn = new Function("args", "displayOutput", "createNewCommandInput", "displayError", "term", "path", "terbium", script);
- fn(args, displayOutput, createNewCommandInput, displayError, term, path, window.parent.tb);
+ const fn = new Function("args", "displayOutput", "createNewCommandInput", "displayError", "term", "path", "terbium", "buffer", script);
+ fn(args, displayOutput, createNewCommandInput, displayError, term, path, window.parent.tb, window.parent.tb.buffer);
} catch (error) {
displayError(`Failed to execute command '${name}': ${error.message}`);
createNewCommandInput();
@@ -220,6 +218,8 @@ async function handleCommand(name, args) {
}
}
+window.handleCommand = handleCommand;
+
window.addEventListener("updPath", e => {
path = e.detail;
});
diff --git a/public/apps/terminal.tapp/scripts/cat.js b/public/apps/terminal.tapp/scripts/cat.js
index fe76270..daf3ef0 100644
--- a/public/apps/terminal.tapp/scripts/cat.js
+++ b/public/apps/terminal.tapp/scripts/cat.js
@@ -9,16 +9,7 @@ async function cat(args) {
try {
const match = path.match(/\/mnt\/([^\/]+)\//);
const davName = match ? match[1].toLowerCase() : "";
- const davInstances = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${sessionStorage.getItem("currAcc")}/files/davs.json`, "utf8"));
- const dav = davInstances.find(d => d.name.toLowerCase() === davName);
- const client = window.webdav.createClient(dav.url, {
- username: dav.username,
- password: dav.password,
- authType: window.webdav.AuthType.Password,
- });
- const np = path.replace(`/mnt/${davName.toLowerCase()}/`, "");
- const content = await client.getFileContents(`${np}/${args._raw}`);
- const text = new TextDecoder().decode(content);
+ const text = await tb.vfs.servers.get(davName).connection.promises.readFile(`${path}/${args._raw}`, "utf8");
displayOutput(text);
createNewCommandInput();
} catch (e) {
diff --git a/public/apps/terminal.tapp/scripts/ls.js b/public/apps/terminal.tapp/scripts/ls.js
index 31dc4f1..908db78 100644
--- a/public/apps/terminal.tapp/scripts/ls.js
+++ b/public/apps/terminal.tapp/scripts/ls.js
@@ -14,24 +14,12 @@ async function ls(args) {
];
const header = "| " + columns.map(col => centerText(col.name, col.width)).join(" | ") + " |";
const separator = "|" + columns.map(col => "-".repeat(col.width + 2)).join("|") + "|";
- displayOutput(centerText(`TerbiumOS Network Storage Manager v1.0.1`, header.length));
+ displayOutput(centerText(`TerbiumOS Network Storage Manager v1.2.0`, header.length));
displayOutput(header);
displayOutput(separator);
- const davInstances = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${sessionStorage.getItem("currAcc")}/files/davs.json`, "utf8"));
- for (const dav of davInstances) {
- let mounted;
- try {
- const client = window.webdav.createClient(dav.url, {
- username: dav.username,
- password: dav.password,
- authType: window.webdav.AuthType.Password,
- });
- await client.getDirectoryContents("/");
- mounted = true;
- } catch {
- mounted = false;
- }
- const row = [centerText(dav.name, columns[0].width), centerText(dav.url, columns[1].width), centerText(mounted ? "Yes" : "No", columns[2].width), centerText(`/mnt/${dav.name.toLowerCase()}`, columns[3].width)];
+ for (const instance of window.parent.tb.vfs.servers) {
+ const dav = instance[1];
+ const row = [centerText(dav.name, columns[0].width), centerText(dav.url, columns[1].width), centerText(dav.connected ? "Yes" : "No", columns[2].width), centerText(`/mnt/${dav.name.toLowerCase()}`, columns[3].width)];
displayOutput("| " + row.join(" | ") + " |");
}
createNewCommandInput();
@@ -39,15 +27,7 @@ async function ls(args) {
try {
const match = args._raw.match(/\/mnt\/([^\/]+)\//) || path.match(/\/mnt\/([^\/]+)\//);
const davName = match ? match[1].toLowerCase() : "";
- const davInstances = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${sessionStorage.getItem("currAcc")}/files/davs.json`, "utf8"));
- const dav = davInstances.find(d => d.name.toLowerCase() === davName);
- const client = window.webdav.createClient(dav.url, {
- username: dav.username,
- password: dav.password,
- authType: window.webdav.AuthType.Password,
- });
- const np = args._raw.replace(`/mnt/${davName.toLowerCase()}/`, "") || path.replace(`/mnt/${davName.toLowerCase()}/`, "");
- const contents = await client.getDirectoryContents(np);
+ const contents = await tb.vfs.servers.get(davName).connection.promises.readdir(`${path}/${args._raw}`);
for (const entry of contents) {
if (entry.type === "directory") {
displayOutput(`${entry.basename}/`);
@@ -63,42 +43,24 @@ async function ls(args) {
createNewCommandInput();
} else if (args._raw) {
try {
- tb.sh.ls(path + args._raw, (err, entries) => {
- if (err) {
- displayError(`ls: ${err.message}`);
- createNewCommandInput();
- } else {
- entries.forEach(entry => {
- displayOutput(entry.name);
- });
- createNewCommandInput();
- }
+ const entries = await tb.sh.promises.ls(path + args._raw);
+ entries.forEach(entry => {
+ displayOutput(entry.name);
});
+ createNewCommandInput();
} catch {
- tb.sh.ls(args._raw, (err, entries) => {
- if (err) {
- displayError(`ls: ${err.message}`);
- createNewCommandInput();
- } else {
- entries.forEach(entry => {
- displayOutput(entry.name);
- });
- createNewCommandInput();
- }
+ const entries = await tb.sh.promises.ls(args._raw);
+ entries.forEach(entry => {
+ displayOutput(entry.name);
});
+ createNewCommandInput();
}
} else {
- tb.sh.ls(path, (err, entries) => {
- if (err) {
- displayError(`ls: ${err.message}`);
- createNewCommandInput();
- } else {
- entries.forEach(entry => {
- displayOutput(entry.name);
- });
- createNewCommandInput();
- }
+ const entries = await tb.sh.promises.ls(path);
+ entries.forEach(entry => {
+ displayOutput(entry.name);
});
+ createNewCommandInput();
}
}
ls(args);
diff --git a/public/apps/terminal.tapp/scripts/mkdir.js b/public/apps/terminal.tapp/scripts/mkdir.js
index 6abed26..3ac27b8 100644
--- a/public/apps/terminal.tapp/scripts/mkdir.js
+++ b/public/apps/terminal.tapp/scripts/mkdir.js
@@ -9,15 +9,8 @@ async function mkdir(args) {
try {
const match = path.match(/\/mnt\/([^\/]+)\//);
const davName = match ? match[1].toLowerCase() : "";
- const davInstances = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${sessionStorage.getItem("currAcc")}/files/davs.json`, "utf8"));
- const dav = davInstances.find(d => d.name.toLowerCase() === davName);
- const client = window.webdav.createClient(dav.url, {
- username: dav.username,
- password: dav.password,
- authType: window.webdav.AuthType.Password,
- });
const np = path.replace(`/mnt/${davName.toLowerCase()}/`, "");
- await client.createDirectory(`${np}/${args._raw}`);
+ await tb.vfs.servers.get(davName).connection.promises.mkdir(`${np}/${args._raw}`);
createNewCommandInput();
} catch (e) {
displayError(`TNSM mkdir: ${e.message}`);
diff --git a/public/apps/terminal.tapp/scripts/rm.js b/public/apps/terminal.tapp/scripts/rm.js
index e630b33..3bd083a 100644
--- a/public/apps/terminal.tapp/scripts/rm.js
+++ b/public/apps/terminal.tapp/scripts/rm.js
@@ -64,15 +64,8 @@ async function rm(args) {
try {
const match = path.match(/\/mnt\/([^\/]+)\//);
const davName = match ? match[1].toLowerCase() : "";
- const davInstances = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${sessionStorage.getItem("currAcc")}/files/davs.json`, "utf8"));
- const dav = davInstances.find(d => d.name.toLowerCase() === davName);
- const client = window.webdav.createClient(dav.url, {
- username: dav.username,
- password: dav.password,
- authType: window.webdav.AuthType.Password,
- });
const np = path.replace(`/mnt/${davName.toLowerCase()}/`, "");
- await client.deleteFile(`${np}/${args._raw}`);
+ await tb.vfs.servers.get(davName).connection.promises.unlink(`${np}/${args._raw}`);
createNewCommandInput();
} catch (e) {
displayError(`TNSM rmdir: ${e.message}`);
diff --git a/public/apps/terminal.tapp/scripts/touch.js b/public/apps/terminal.tapp/scripts/touch.js
index 1657584..93650af 100644
--- a/public/apps/terminal.tapp/scripts/touch.js
+++ b/public/apps/terminal.tapp/scripts/touch.js
@@ -9,15 +9,8 @@ async function touch(args) {
try {
const match = path.match(/\/mnt\/([^\/]+)\//);
const davName = match ? match[1].toLowerCase() : "";
- const davInstances = JSON.parse(await window.parent.tb.fs.promises.readFile(`/apps/user/${sessionStorage.getItem("currAcc")}/files/davs.json`, "utf8"));
- const dav = davInstances.find(d => d.name.toLowerCase() === davName);
- const client = window.webdav.createClient(dav.url, {
- username: dav.username,
- password: dav.password,
- authType: window.webdav.AuthType.Password,
- });
const np = path.replace(`/mnt/${davName.toLowerCase()}/`, "");
- await client.putFileContents(`${np}/${args._raw}`, "", { overwrite: true });
+ await tb.vfs.servers.get(davName).connection.promises.writeFile(`${np}/${args._raw}`, "", "utf8");
createNewCommandInput();
} catch (e) {
displayError(`TNSM touch: ${e.message}`);
diff --git a/public/apps/terminal.tapp/scripts/unzip.js b/public/apps/terminal.tapp/scripts/unzip.js
index 492299c..7bfcddb 100644
--- a/public/apps/terminal.tapp/scripts/unzip.js
+++ b/public/apps/terminal.tapp/scripts/unzip.js
@@ -15,7 +15,7 @@ async function uzip(path, target) {
try {
console.log(`touch ${currentPath.slice(0, -1)}`);
displayOutput(`touch ${currentPath.slice(0, -1)}`);
- await window.parent.tb.fs.promises.writeFile(currentPath.slice(0, -1), Filer.Buffer.from(content));
+ await window.parent.tb.fs.promises.writeFile(currentPath.slice(0, -1), window.parent.tb.buffer.from(content), "arraybuffer");
} catch {
displayOutput(`Cant make ${currentPath.slice(0, -1)}`);
console.log(`Cant make ${currentPath.slice(0, -1)}`);
diff --git a/public/apps/terminal.tapp/terminal_com.js b/public/apps/terminal.tapp/terminal_com.js
index 06dbd7c..6f8f42a 100644
--- a/public/apps/terminal.tapp/terminal_com.js
+++ b/public/apps/terminal.tapp/terminal_com.js
@@ -10,6 +10,6 @@ tb_island.addControl({
id: "terminal-help",
click: async () => {
term.write("help");
- await handleCommand("help");
+ await window.handleCommand("help");
},
});
diff --git a/public/apps/text editor.tapp/text.com.js b/public/apps/text editor.tapp/text.com.js
index a3127ff..e43de5e 100644
--- a/public/apps/text editor.tapp/text.com.js
+++ b/public/apps/text editor.tapp/text.com.js
@@ -24,7 +24,7 @@ tb_island.addControl({
filename: "untitled.txt",
onOk: async file => {
document.body.setAttribute("path", file);
- textarea.value = await tb.fs.promises.readFile(file, "utf8");
+ textarea.value = await tb.vfs.whatFS(file).promises.readFile(file, "utf8");
},
});
},
@@ -40,7 +40,7 @@ tb_island.addControl({
title: "Save Text File",
filename: "untitled.txt",
onOk: async txt => {
- tb.fs.writeFile(`${txt}`, textarea.value, err => {
+ tb.vfs.whatFS(txt).writeFile(`${txt}`, textarea.value, err => {
if (err) return alert(err);
});
},
diff --git a/public/cursor_changer.js b/public/cursor_changer.js
index 6e5abf8..a459e7a 100644
--- a/public/cursor_changer.js
+++ b/public/cursor_changer.js
@@ -1,41 +1,54 @@
const style = document.createElement("style");
console.log("Cursor Engine Injected");
+const anuraSettings = window.parent.parent.parent.anura.ui.theme.settings;
style.textContent = `
- :root {
- --cursor-normal: url("/cursors/dark/normal.svg") 6 0, default !important;
- --cursor-pointer: url("/cursors/dark/pointer.svg") 6 0, pointer !important;
- --cursor-text: url("/cursors/dark/text.svg") 10 0, text !important;
- --cursor-crosshair: url("/cursors/dark/crosshair.svg") 0 0, crosshair !important;
- --cursor-wait: url("/cursors/dark/wait.svg") 0 0, wait !important;
- --cursor-nw-resize: url("/cursors/dark/resize-l.svg") 0 0, nw-resize !important;
- --cursor-ne-resize: url("/cursors/dark/resize-r.svg") 0 0, ne-resize !important;
- --cursor-sw-resize: url("/cursors/dark/resize-r.svg") 0 0, sw-resize !important;
- --cursor-se-resize: url("/cursors/dark/resize-l.svg") 0 0, se-resize !important;
- --cursor-n-resize: url("/cursors/dark/resize-v.svg") 0 0, n-resize !important;
- --cursor-s-resize: url("/cursors/dark/resize-v.svg") 0 0, s-resize !important;
- --cursor-e-resize: url("/cursors/dark/resize-h.svg") 0 0, e-resize !important;
- --cursor-w-resize: url("/cursors/dark/resize-h.svg") 0 0, w-resize !important;
- }
- * {
- cursor: var(--cursor-normal);
- }
- a, a:-webkit-any-link {
- cursor: var(--cursor-pointer) !important;
- }
- input[type="text"], textarea {
- cursor: var(--cursor-text) !important;
- }
- .crosshair {
- cursor: var(--cursor-crosshair) !important;
- }
- .loading {
- cursor: var(--cursor-wait) !important;
- }
- input[disabled], button[disabled] {
- cursor: var(--cursor-normal) !important;
- }
- [contenteditable="true"] {
- cursor: var(--cursor-text) !important;
- }
+ :root {
+ --cursor-normal: url("/cursors/dark/normal.svg") 6 0, default !important;
+ --cursor-pointer: url("/cursors/dark/pointer.svg") 6 0, pointer !important;
+ --cursor-text: url("/cursors/dark/text.svg") 10 0, text !important;
+ --cursor-crosshair: url("/cursors/dark/crosshair.svg") 0 0, crosshair !important;
+ --cursor-wait: url("/cursors/dark/wait.svg") 0 0, wait !important;
+ --cursor-nw-resize: url("/cursors/dark/resize-l.svg") 0 0, nw-resize !important;
+ --cursor-ne-resize: url("/cursors/dark/resize-r.svg") 0 0, ne-resize !important;
+ --cursor-sw-resize: url("/cursors/dark/resize-r.svg") 0 0, sw-resize !important;
+ --cursor-se-resize: url("/cursors/dark/resize-l.svg") 0 0, se-resize !important;
+ --cursor-n-resize: url("/cursors/dark/resize-v.svg") 0 0, n-resize !important;
+ --cursor-s-resize: url("/cursors/dark/resize-v.svg") 0 0, s-resize !important;
+ --cursor-e-resize: url("/cursors/dark/resize-h.svg") 0 0, e-resize !important;
+ --cursor-w-resize: url("/cursors/dark/resize-h.svg") 0 0, w-resize !important;
+ --theme-fg: ${anuraSettings["foreground"] || "#FFFFFF"};
+ --theme-secondary-fg: ${anuraSettings["secondaryForeground"] || "#C1C1C1"};
+ --theme-border: ${anuraSettings["border"] || "#444444"};
+ --material-border: ${anuraSettings["border"] || "#444444"};
+ --theme-dark-border: ${anuraSettings["darkBorder"] || "#000000"};
+ --theme-bg: ${anuraSettings["darkBackground"] || "#202124"};
+ --material-bg: ${anuraSettings["darkBackground"] || "#202124"};
+ --theme-secondary-bg: ${anuraSettings["secondaryBackground"] || "#383838"};
+ --theme-dark-bg: ${anuraSettings["darkBackground"] || "#161616"};
+ --theme-accent: ${anuraSettings["accent"] || "#4285F4"};
+ --matter-helper-theme: ${anuraSettings["accent"] || "#4285F4"};
+ }
+ * {
+ cursor: var(--cursor-normal);
+ }
+ a, a:-webkit-any-link {
+ cursor: var(--cursor-pointer) !important;
+ }
+ input[type="text"], textarea {
+ cursor: var(--cursor-text) !important;
+ }
+ .crosshair {
+ cursor: var(--cursor-crosshair) !important;
+ }
+ .loading {
+ cursor: var(--cursor-wait) !important;
+ }
+ input[disabled], button[disabled] {
+ cursor: var(--cursor-normal) !important;
+ }
+ [contenteditable="true"] {
+ cursor: var(--cursor-text) !important;
+ }
`;
+console.log("Applied TB Styles");
document.head.appendChild(style);
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..c7ecdaf
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,22 @@
+User-agent: *
+Allow: /
+
+User-agent: Googlebot
+Allow: /
+
+User-agent: Bingbot
+Allow: /
+
+User-agent: Slurp
+Allow: /
+
+User-agent: DuckDuckBot
+Allow: /
+
+User-agent: Baiduspider
+Allow: /
+
+User-agent: YandexBot
+Allow: /
+
+Sitemap: https://terbiumon.top/sitemap.xml
\ No newline at end of file
diff --git a/public/sitemap.xml b/public/sitemap.xml
new file mode 100644
index 0000000..d1c3719
--- /dev/null
+++ b/public/sitemap.xml
@@ -0,0 +1,9 @@
+
+Connecting to Authentication servers please wait...
+Upload
+Welcome, {userdata.username}!
+ {hasSettings ? ( +Click next to use this account
+ {
@@ -552,22 +1100,24 @@ export default function Setup() {
{currentStep < 5 && (
)}
-
+ {currentStep > 2 && currentStep < 5 && (
+
+ )}
) : null}
@@ -581,7 +1131,29 @@ export default function Setup() {