mirror of
https://github.com/driftywinds/driftywinds.github.io.git
synced 2025-12-19 02:53:32 +00:00
Update directory structure
This commit is contained in:
57
common/assets/entitlements.json
Normal file
57
common/assets/entitlements.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"com.apple.security.application-groups": {
|
||||
"name": "App Groups",
|
||||
"description": "Allow app to share files with other apps and app extensions in the same App Group.",
|
||||
"icon": "columns-gap"
|
||||
},
|
||||
"com.apple.developer.associated-domains": {
|
||||
"name": "Associated Domains",
|
||||
"description": "The associated domains for specific services, such as shared web credentials, universal links, and App Clips.",
|
||||
"icon": "globe2"
|
||||
},
|
||||
"com.apple.developer.carplay-audio": {
|
||||
"name": "CarPlay Audio",
|
||||
"description": "Allows the app the provide audio content for CarPlay.",
|
||||
"icon": "car-front-fill"
|
||||
},
|
||||
"get-task-allow": {
|
||||
"name": "Debuggable",
|
||||
"description": "Allow developers to attach a debugger to this app. This permission is required for JIT to work.",
|
||||
"icon": "tools"
|
||||
},
|
||||
"com.apple.developer.device-information.user-assigned-device-name": {
|
||||
"name": "Device Name",
|
||||
"description": "Grants access to the user-assigned device name instead of a generic device name.",
|
||||
"icon": "phone-fill"
|
||||
},
|
||||
"keychain-access-groups": {
|
||||
"name": "Keychain",
|
||||
"description": "Allows app to read and write secure data to the system's keychain.",
|
||||
"icon": "key-fill"
|
||||
},
|
||||
"com.apple.developer.networking.multicast": {
|
||||
"name": "Multicast",
|
||||
"description": "App can send or receive IP multicast traffic.",
|
||||
"icon": "globe2"
|
||||
},
|
||||
"aps-environment": {
|
||||
"name": "Push Notifications",
|
||||
"description": "App can send push notifications.",
|
||||
"icon": "app-indicator"
|
||||
},
|
||||
"com.apple.developer.applesignin": {
|
||||
"name": "Sign in with Apple",
|
||||
"description": "Allows sign in with Apple.",
|
||||
"icon": "apple"
|
||||
},
|
||||
"com.apple.developer.siri": {
|
||||
"name": "Siri",
|
||||
"description": "Allows app to handle Siri requests.",
|
||||
"icon": "mic-fill"
|
||||
},
|
||||
"com.apple.developer.networking.wifi-info": {
|
||||
"name": "Wi-Fi Information Access",
|
||||
"description": "Allows app to access information about the connected Wi-Fi network.",
|
||||
"icon": "wifi"
|
||||
}
|
||||
}
|
||||
BIN
common/assets/img/generic_app.jpeg
Normal file
BIN
common/assets/img/generic_app.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
BIN
common/assets/img/loading.gif
Normal file
BIN
common/assets/img/loading.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
11
common/assets/legacy-permissions.json
Normal file
11
common/assets/legacy-permissions.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"background-audio": {
|
||||
"icon": "volume-up-fill"
|
||||
},
|
||||
"background-fetch": {
|
||||
"icon": "arrow-repeat"
|
||||
},
|
||||
"photos": {
|
||||
"icon": "images"
|
||||
}
|
||||
}
|
||||
44
common/assets/privacy.json
Normal file
44
common/assets/privacy.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"AppleMusic": {
|
||||
"icon": "music-note-beamed"
|
||||
},
|
||||
"BluetoothAlways": {
|
||||
"name": "Bluetooth",
|
||||
"icon": "bluetooth"
|
||||
},
|
||||
"BluetoothPeripheral": {
|
||||
"name": "Bluetooth (Peripherals)",
|
||||
"icon": "bluetooth"
|
||||
},
|
||||
"Contacts": {
|
||||
"icon": "person-circle"
|
||||
},
|
||||
"Camera": {
|
||||
"icon": "camera-fill"
|
||||
},
|
||||
"FaceID": {
|
||||
"name": "Face ID",
|
||||
"icon": "person-bounding-box"
|
||||
},
|
||||
"LocalNetwork": {
|
||||
"icon": "globe2"
|
||||
},
|
||||
"LocationWhenInUse": {
|
||||
"name": "Location (When Using)",
|
||||
"icon": "cursor-fill"
|
||||
},
|
||||
"Microphone": {
|
||||
"icon": "mic-fill"
|
||||
},
|
||||
"PhotoLibrary": {
|
||||
"name": "Photos",
|
||||
"icon": "images"
|
||||
},
|
||||
"PhotoLibraryAdd": {
|
||||
"name": "Photos (Add)",
|
||||
"icon": "image"
|
||||
},
|
||||
"UserTracking": {
|
||||
"icon": "person-vcard-fill"
|
||||
}
|
||||
}
|
||||
9
common/assets/sources.json
Normal file
9
common/assets/sources.json
Normal file
@@ -0,0 +1,9 @@
|
||||
[
|
||||
"https://therealfoxster.github.io/altsource/apps.json",
|
||||
"https://qnblackcat.github.io/AltStore/apps.json",
|
||||
"https://quarksources.github.io/dist/quantumsource.min.json",
|
||||
"https://quarksources.github.io/dist/quantumsource%2B%2B.min.json",
|
||||
"https://alt.getutm.app",
|
||||
"https://flyinghead.github.io/flycast-builds/altstore.json",
|
||||
"https://provenance-emu.com/apps.json"
|
||||
]
|
||||
25
common/components/AltStoreBanner.js
Normal file
25
common/components/AltStoreBanner.js
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// AltStoreBanner.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
import { sourceURL } from "../modules/constants.js";
|
||||
|
||||
export const AltStoreBanner = (sourceName) => `
|
||||
<div class="uibanner">
|
||||
<img src="https://user-images.githubusercontent.com/705880/65270980-1eb96f80-dad1-11e9-9367-78ccd25ceb02.png" alt="altstore-icon" class="icon">
|
||||
<div class="content">
|
||||
<div class="text-container">
|
||||
<p class="title-text">AltStore <span class="small beta badge"></span></p>
|
||||
<p class="detail-text">
|
||||
Add ${sourceName ? "\"" + sourceName + "\"" : "this source"} to AltStore to receive app updates
|
||||
</p>
|
||||
</div>
|
||||
<a href="altstore://source?url=${sourceURL}">
|
||||
<button>Add</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>`;
|
||||
28
common/components/AppHeader.js
Normal file
28
common/components/AppHeader.js
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// AppHeader.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
import { sourceURL } from "../modules/constants.js";
|
||||
|
||||
export const AppHeader = (app, x = ".") => app ? `
|
||||
<div class="item">
|
||||
<div class="app-header">
|
||||
<div class="content">
|
||||
<img id="app-icon" src="${app.iconURL}" alt="">
|
||||
<div class="right">
|
||||
<div class="text">
|
||||
<p class="title">${app.name}</p>
|
||||
<p class="subtitle">${app.developerName}</p>
|
||||
</div>
|
||||
<a href="${x}/app/?source=${sourceURL}&id=${app.bundleIdentifier}">
|
||||
<button class="uibutton" style="background-color: #${app.tintColor.replaceAll("#", "")};">View</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="background" style="background-color: #${app.tintColor.replaceAll("#", "")};"></div>
|
||||
</div>
|
||||
</div>` : undefined;
|
||||
13
common/components/AppPermissionItem.js
Normal file
13
common/components/AppPermissionItem.js
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// AppPermissionItem.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
export const AppPermissionItem = (name, icon, details) => `
|
||||
<a class="permission-item" onclick="alert('${details?.replace(/(['"])/g, "\\$1") ?? "altsource-viewer does not have detailed information about this entitlement."}');">
|
||||
<p><i class="bi-${icon}"></i></p>
|
||||
<p class="title">${name}</p>
|
||||
</a>`;
|
||||
23
common/components/MoreButton.js
Normal file
23
common/components/MoreButton.js
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// MoreButton.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
export const MoreButton = tintColor => `
|
||||
<a id="more" onclick="revealTruncatedText(this);">
|
||||
<button style="color: ${tintColor};">more</button>
|
||||
</a>`;
|
||||
|
||||
window.revealTruncatedText = moreButton => {
|
||||
console.log(moreButton);
|
||||
const textId = moreButton.parentNode.id;
|
||||
const text = document.getElementById(textId);
|
||||
text.style.display = "block";
|
||||
text.style.overflow = "auto";
|
||||
text.style.webkitLineClamp = "none";
|
||||
text.style.lineClamp = "none";
|
||||
text.removeChild(moreButton)
|
||||
};
|
||||
22
common/components/NavigationBar.js
Normal file
22
common/components/NavigationBar.js
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NavigationBar.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
export const NavigationBar = (title) => `
|
||||
<div id="nav-bar">
|
||||
<button id="back" type="button">
|
||||
<i class="bi bi-chevron-left"></i>
|
||||
Back
|
||||
</button>
|
||||
<div id="title">
|
||||
<p>${title ?? ""}</p>
|
||||
</div>
|
||||
<button id="back" class="hidden">
|
||||
<i class="bi bi-chevron-left"></i>
|
||||
Back
|
||||
</button>
|
||||
</div>`;
|
||||
25
common/components/NewsItem.js
Normal file
25
common/components/NewsItem.js
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// NewsItem.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
import { AppHeader } from "./AppHeader.js";
|
||||
|
||||
export const NewsItem = (news, minimal = false) => `
|
||||
<div class="news-item-wrapper"> ${news.url ?
|
||||
"<a href='" + news.url + "'>" : ""}
|
||||
<div class="item" style="background-color: #${news.tintColor.replaceAll("#", "")};">
|
||||
<div class="text">
|
||||
<h3>${news.title}</h3>
|
||||
<p>${news.caption}</p>
|
||||
</div>${news.imageURL && !minimal ?
|
||||
"<div class='image-wrapper'>" +
|
||||
"<img src='" + news.imageURL + "'>" +
|
||||
"</div>" : ""}
|
||||
</div> ${news.url ?
|
||||
"</a>" : ""} ${news.appID && !minimal ?
|
||||
AppHeader(getAppWithBundleId(news.appID), "..") ?? "" : ""}
|
||||
</div>`;
|
||||
20
common/components/VersionHistoryItem.js
Normal file
20
common/components/VersionHistoryItem.js
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// VersionHistoryItem.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
export const VersionHistoryItem = (number, date, description, url, i) => `
|
||||
<div class="version">
|
||||
<div class="version-header">
|
||||
<p class="version-number">${number}</p>
|
||||
<p class="version-date">${date}</p>
|
||||
</div>
|
||||
<div class="version-options">
|
||||
<a class="version-install" href="altstore://install?url=${url}">Install with AltStore</a>
|
||||
<a class="version-download" href="${url}">Download IPA</a>
|
||||
</div>
|
||||
<p class="version-description" id="description${i}">${description}</p>
|
||||
</div>`;
|
||||
129
common/modules/constants.js
Normal file
129
common/modules/constants.js
Normal file
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// constants.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
export const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
|
||||
export const sourceURL = urlSearchParams.get('source')?.replaceAll("+", "%2B");
|
||||
|
||||
// https://stackoverflow.com/a/8943487
|
||||
export const urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
|
||||
|
||||
export const entitlements = {
|
||||
"com.apple.security.application-groups": {
|
||||
name: "App Groups",
|
||||
description: "Allow app to share files with other apps and app extensions in the same App Group.",
|
||||
icon: "columns-gap"
|
||||
},
|
||||
"com.apple.developer.associated-domains": {
|
||||
name: "Associated Domains",
|
||||
description: "The associated domains for specific services, such as shared web credentials, universal links, and App Clips.",
|
||||
icon: "globe2"
|
||||
},
|
||||
"com.apple.developer.carplay-audio": {
|
||||
name: "CarPlay Audio",
|
||||
description: "Allows the app the provide audio content for CarPlay.",
|
||||
icon: "car-front-fill"
|
||||
},
|
||||
"get-task-allow": {
|
||||
name: "Debuggable",
|
||||
description: "Allow developers to attach a debugger to this app. This permission is required for JIT to work.",
|
||||
icon: "tools"
|
||||
},
|
||||
"com.apple.developer.device-information.user-assigned-device-name": {
|
||||
name: "Device Name",
|
||||
description: "Grants access to the user-assigned device name instead of a generic device name.",
|
||||
icon: "phone-fill"
|
||||
},
|
||||
"keychain-access-groups": {
|
||||
name: "Keychain",
|
||||
description: "Allows app to read and write secure data to the system's keychain.",
|
||||
icon: "key-fill"
|
||||
},
|
||||
"com.apple.developer.networking.multicast": {
|
||||
name: "Multicast",
|
||||
description: "App can send or receive IP multicast traffic.",
|
||||
icon: "globe2"
|
||||
},
|
||||
"aps-environment": {
|
||||
name: "Push Notifications",
|
||||
description: "App can send push notifications.",
|
||||
icon: "app-indicator"
|
||||
},
|
||||
"com.apple.developer.applesignin": {
|
||||
name: "Sign in with Apple",
|
||||
description: "Allows sign in with Apple.",
|
||||
icon: "apple"
|
||||
},
|
||||
"com.apple.developer.siri": {
|
||||
name: "Siri",
|
||||
description: "Allows app to handle Siri requests.",
|
||||
icon: "mic-fill"
|
||||
},
|
||||
"com.apple.developer.networking.wifi-info": {
|
||||
name: "Wi-Fi Information Access",
|
||||
description: "Allows app to access information about the connected Wi-Fi network.",
|
||||
icon: "wifi"
|
||||
}
|
||||
};
|
||||
|
||||
export const privacy = {
|
||||
"AppleMusic": {
|
||||
icon: "music-note-beamed"
|
||||
},
|
||||
"BluetoothAlways": {
|
||||
name: "Bluetooth",
|
||||
icon: "bluetooth"
|
||||
},
|
||||
"BluetoothPeripheral": {
|
||||
name: "Bluetooth (Peripherals)",
|
||||
icon: "bluetooth"
|
||||
},
|
||||
"Contacts": {
|
||||
icon: "person-circle"
|
||||
},
|
||||
"Camera": {
|
||||
icon: "camera-fill"
|
||||
},
|
||||
"FaceID": {
|
||||
name: "Face ID",
|
||||
icon: "person-bounding-box"
|
||||
},
|
||||
"LocalNetwork": {
|
||||
icon: "globe2"
|
||||
},
|
||||
"LocationWhenInUse": {
|
||||
name: "Location (When Using)",
|
||||
icon: "cursor-fill"
|
||||
},
|
||||
"Microphone": {
|
||||
icon: "mic-fill"
|
||||
},
|
||||
"PhotoLibrary": {
|
||||
name: "Photos",
|
||||
icon: "images"
|
||||
},
|
||||
"PhotoLibraryAdd": {
|
||||
name: "Photos (Add)",
|
||||
icon: "image"
|
||||
},
|
||||
"UserTracking": {
|
||||
icon: "person-vcard-fill"
|
||||
},
|
||||
};
|
||||
|
||||
export const legacyPermissions = {
|
||||
"background-audio": {
|
||||
icon: "volume-up-fill"
|
||||
},
|
||||
"background-fetch": {
|
||||
icon: "arrow-repeat"
|
||||
},
|
||||
"photos": {
|
||||
icon: "images"
|
||||
}
|
||||
};
|
||||
77
common/modules/main.js
Normal file
77
common/modules/main.js
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// main.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
import { urlSearchParams, sourceURL } from "./constants.js";
|
||||
import { isValidHTTPURL, setTintColor, insertAltStoreBanner, setUpBackButton, open } from "./utilities.js";
|
||||
|
||||
export function main(callback, fallbackURL = "../../") {
|
||||
// If no source
|
||||
if (!urlSearchParams.has('source')) {
|
||||
open(fallbackURL);
|
||||
return;
|
||||
}
|
||||
// If source is not a valid HTTP URL
|
||||
else if (!isValidHTTPURL(sourceURL)) {
|
||||
alert("Invalid HTTP URL.");
|
||||
open(fallbackURL);
|
||||
return;
|
||||
}
|
||||
|
||||
var apps;
|
||||
window.setApps = array =>
|
||||
apps = array;
|
||||
window.getAppWithBundleId = bundleId =>
|
||||
apps?.find(app => app.bundleIdentifier == bundleId) ?? undefined;
|
||||
|
||||
setUpBackButton();
|
||||
|
||||
fetch(sourceURL)
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
// Set tint color
|
||||
const tintColor = json.tintColor?.replaceAll("#", "");
|
||||
if (tintColor) setTintColor(tintColor);
|
||||
|
||||
insertAltStoreBanner(json.name);
|
||||
|
||||
setApps(json.apps);
|
||||
// main(json);
|
||||
callback(json);
|
||||
waitForAllImagesToLoad();
|
||||
})
|
||||
.catch(error => console.error("An error occurred.", error));
|
||||
|
||||
function waitForAllImagesToLoad() {
|
||||
const allImages = document.querySelectorAll("img");
|
||||
var count = 0;
|
||||
|
||||
allImages.forEach(image => {
|
||||
// New img element that won't be rendered to the DOM
|
||||
var newImage = document.createElement("img");
|
||||
// Attach load listener
|
||||
newImage.addEventListener("load", loaded);
|
||||
// Set src
|
||||
newImage.src = image.src;
|
||||
|
||||
// Unable to load image
|
||||
image.addEventListener("error", (event) => {
|
||||
if (event.target.id == "app-icon") {
|
||||
event.target.src = "img/generic_app.jpeg";
|
||||
} else event.target.remove()
|
||||
loaded();
|
||||
});
|
||||
});
|
||||
|
||||
function loaded() {
|
||||
if (++count == allImages.length) {
|
||||
document.querySelector("body").classList.remove("loading");
|
||||
document.getElementById("loading").remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
common/modules/utilities.js
Normal file
96
common/modules/utilities.js
Normal file
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// utilities.js
|
||||
// altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
//
|
||||
// Copyright (c) 2023 Foxster.
|
||||
// MIT License.
|
||||
//
|
||||
|
||||
import { AltStoreBanner } from "../components/AltStoreBanner.js";
|
||||
import { NavigationBar } from "../components/NavigationBar.js";
|
||||
import { urlRegex, sourceURL } from "./constants.js";
|
||||
|
||||
export function formatVersionDate(arg) {
|
||||
const versionDate = new Date(arg),
|
||||
month = versionDate.toUTCString().split(" ")[2],
|
||||
date = versionDate.getDate();
|
||||
const today = new Date();
|
||||
const msPerDay = 60 * 60 * 24 * 1000;
|
||||
const msDifference = today.valueOf() - versionDate.valueOf();
|
||||
|
||||
let dateString = versionDate.valueOf() ? `${month} ${date}, ${versionDate.getFullYear()}` : arg.split("T")[0];
|
||||
if (msDifference <= msPerDay && today.getDate() == versionDate.getDate())
|
||||
dateString = "Today";
|
||||
else if (msDifference <= msPerDay * 2)
|
||||
dateString = "Yesterday";
|
||||
|
||||
return dateString;
|
||||
}
|
||||
|
||||
export function insertSpaceInSnakeString(string) {
|
||||
return string.split(".").slice(-1)[0].split("-").map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
||||
}
|
||||
|
||||
export function insertSpaceInCamelString(string) {
|
||||
// https://stackoverflow.com/a/38388188/19227228
|
||||
return string.match(/[A-Z][a-z]+|[0-9]+/g).join(" ");
|
||||
}
|
||||
|
||||
export function insertAltStoreBanner(sourceName) {
|
||||
document.getElementById("top")?.insertAdjacentHTML("afterbegin", AltStoreBanner(sourceName));
|
||||
}
|
||||
|
||||
export function insertNavigationBar(title) {
|
||||
document.getElementById("top")?.insertAdjacentHTML("beforeend", NavigationBar(title));
|
||||
setUpBackButton();
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/43467144/19227228
|
||||
export function isValidHTTPURL(string) {
|
||||
var url;
|
||||
try {
|
||||
url = new URL(string);
|
||||
} catch (error) {
|
||||
console.error("An error occurred.", error);
|
||||
return false;
|
||||
}
|
||||
return url.protocol == "http:" || url.protocol == "https:";
|
||||
}
|
||||
|
||||
export function formatString(string) {
|
||||
if (!string) return undefined;
|
||||
|
||||
// URLs
|
||||
const urlArray = string.match(urlRegex);
|
||||
// const urlSet = [...new Set(urlArray)]; // Converting to set to remove duplicates
|
||||
var result = "";
|
||||
urlArray?.forEach(url => {
|
||||
string = string.replace(url, `<a href="${url}">${url}</a>`)
|
||||
// Remove formatted substring so it won't get formatted again (prevents <a> tag within the href attribute another <a> tag)
|
||||
let endIndexOfClosingTag = string.indexOf("</a>") + 4;
|
||||
let formattedSubstring = string.substring(0, endIndexOfClosingTag);
|
||||
result += formattedSubstring;
|
||||
string = string.replace(formattedSubstring, "");
|
||||
});
|
||||
|
||||
result += string;
|
||||
|
||||
// New lines
|
||||
return result.replaceAll("\n", "<br>");
|
||||
}
|
||||
|
||||
export function setTintColor(color) {
|
||||
document.querySelector(':root')?.style.setProperty("--accent-color", `#${color}`);
|
||||
}
|
||||
|
||||
export function setUpBackButton() {
|
||||
document.getElementById("back")?.addEventListener("click", () => history.back());
|
||||
}
|
||||
|
||||
export function open(url) {
|
||||
window.open(url, "_self");
|
||||
}
|
||||
|
||||
const $ = selector => selector.startsWith("#") && !selector.includes(".") && !selector.includes(" ")
|
||||
? document.getElementById(selector.substring(1))
|
||||
: document.querySelectorAll(selector);
|
||||
538
common/style.css
Normal file
538
common/style.css
Normal file
@@ -0,0 +1,538 @@
|
||||
/*
|
||||
style.css
|
||||
altsource-viewer (https://github.com/therealFoxster/altsource-viewer)
|
||||
|
||||
Copyright (c) 2023 Foxster.
|
||||
MIT License.
|
||||
*/
|
||||
|
||||
@import url("./vendor/bootstrap-icons-1.11.2/bootstrap-icons.min.css");
|
||||
|
||||
:root {
|
||||
--accent-color: #018084;
|
||||
--app-tint-color: #018084;
|
||||
|
||||
--color-bg: rgba(255, 255, 255, 1);
|
||||
--color-bg-secondary: rgba(235, 235, 235, 1);
|
||||
--color-separator: rgba(0, 0, 0, 0.15);
|
||||
--color-primary: rgba(0, 122, 254, 1);
|
||||
--color-transparent: rgba(255, 255, 255, 0.75);
|
||||
|
||||
--color-bg-dark: rgb(26, 25, 27);
|
||||
--color-bg-dark-secondary: rgb(46, 45, 47);
|
||||
--color-separator-dark: rgba(255, 255, 255, 0.15);
|
||||
--color-primary-dark: rgba(11, 132, 254, 255);
|
||||
--color-transparent-dark: rgba(26, 25, 27, 0.25);
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Dark appearance */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body,
|
||||
.uibanner,
|
||||
#loading {
|
||||
background-color: var(--color-bg-dark) !important;
|
||||
}
|
||||
|
||||
p,
|
||||
h1,
|
||||
h2 {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
#nav-bar {
|
||||
background-color: var(--color-transparent-dark) !important;
|
||||
}
|
||||
|
||||
.uibanner,
|
||||
#nav-bar {
|
||||
border-color: var(--color-separator-dark) !important;
|
||||
}
|
||||
|
||||
.app-header .background {
|
||||
opacity: 0.35 !important;
|
||||
}
|
||||
|
||||
#more button {
|
||||
background: linear-gradient(to right, transparent, var(--color-bg-dark) 35%) !important;
|
||||
}
|
||||
|
||||
#nav-bar #title>img,
|
||||
.app-header img,
|
||||
.screenshot {
|
||||
border-color: rgba(255, 255, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
.secondary-bg {
|
||||
background-color: var(--color-bg-dark-secondary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-bg {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
body.loading {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#loading {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100vh;
|
||||
margin: 0 auto;
|
||||
z-index: 4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
#loading img {
|
||||
width: 24px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#loading p {
|
||||
font-size: 0.75em;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
/* h1#title {
|
||||
padding-left: 1rem;
|
||||
} */
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
@media screen and (min-device-width: 767px) {
|
||||
body {
|
||||
margin: 0 auto;
|
||||
max-width: 414px;
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#top {
|
||||
position: fixed;
|
||||
z-index: 5;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#title {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
#main>p:first-of-type {
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
font-size: 0.9em;
|
||||
opacity: 0.5;
|
||||
padding-left: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Navigation bar */
|
||||
|
||||
#nav-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 0.1px solid var(--color-separator);
|
||||
background-color: var(--color-transparent);
|
||||
-webkit-backdrop-filter: saturate(100%) blur(30px);
|
||||
backdrop-filter: saturate(100%) blur(20px);
|
||||
max-width: 414px;
|
||||
min-width: 0;
|
||||
margin: 0 auto;
|
||||
padding: 0.25em 0.75em;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#nav-bar #title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-height: 2.5em;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#nav-bar #title>p {
|
||||
font-weight: 600;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#nav-bar #title>img {
|
||||
max-height: 2em;
|
||||
border-radius: 0.5em;
|
||||
border: 0.75px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
#nav-bar #back {
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
#nav-bar #back .bi {
|
||||
margin-left: -8px;
|
||||
-webkit-text-stroke: 1px;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
#nav-bar a {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* Main */
|
||||
|
||||
#main {
|
||||
/* padding: 1em; */
|
||||
padding-top: 3.55rem;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
/* Section header */
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
/* News */
|
||||
|
||||
#news-items {
|
||||
display: grid;
|
||||
height: 100%;
|
||||
gap: 1em;
|
||||
grid-auto-columns: 95%;
|
||||
grid-auto-flow: column;
|
||||
overflow-x: scroll;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
#news-items.one {
|
||||
grid-auto-columns: 100% !important;
|
||||
}
|
||||
|
||||
#news .item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
border-radius: 1.5em;
|
||||
overflow: hidden;
|
||||
min-width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#news .item>.text {
|
||||
margin: 1.5em;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#news .item>.text>p {
|
||||
opacity: 0.75;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#news .item .image-wrapper {
|
||||
max-height: 15.15em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#news img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* App header */
|
||||
|
||||
#apps.section .item {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.app-header>.content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.app-header img {
|
||||
display: block;
|
||||
border-radius: 13.5px;
|
||||
max-width: 64px;
|
||||
border: 0.75px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.app-header .background {
|
||||
position: absolute;
|
||||
background-color: var(--accent-color);
|
||||
opacity: 0.2;
|
||||
border-radius: 1.5em;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.app-header>.content>.right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-left: 0.65em;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.app-header>.content .text {
|
||||
margin-right: 0.5em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-header>.content .text>.title {
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.app-header>.content .text>.subtitle {
|
||||
opacity: 0.5;
|
||||
font-size: 0.85em;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
|
||||
/* About */
|
||||
|
||||
#about a:visited {
|
||||
color: var(--accent-color)
|
||||
}
|
||||
|
||||
#about.section .item {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
#about p {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
button.uibutton {
|
||||
min-width: 78px;
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
color: white;
|
||||
background-color: var(--accent-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.uibutton:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Links */
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: var(--accent-color)
|
||||
}
|
||||
|
||||
a>button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (hover:hover) {
|
||||
a:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
#more button {
|
||||
min-width: 0 !important;
|
||||
margin-left: 2px !important;
|
||||
padding: 0;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
text-transform: none;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
background: unset;
|
||||
color: var(--accent-color);
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding-left: 36px;
|
||||
background: linear-gradient(to right, transparent, var(--color-bg) 35%);
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
#more:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.header a,
|
||||
#nav-bar #back {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.05em;
|
||||
font-weight: 450;
|
||||
border: none;
|
||||
background: unset;
|
||||
padding: 0;
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
|
||||
.badge {
|
||||
margin-left: 0.05rem !important;
|
||||
margin-right: 0.05rem !important;
|
||||
padding: 0.5px 6.5px;
|
||||
font-size: 10px;
|
||||
line-height: 1.3333733333;
|
||||
font-weight: 700;
|
||||
border-radius: 12px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
background: transparent;
|
||||
text-transform: uppercase;
|
||||
vertical-align: middle;
|
||||
color: white;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.beta.badge {
|
||||
margin-bottom: 2px;
|
||||
background-color: #f5a10d;
|
||||
}
|
||||
|
||||
.beta.badge::before {
|
||||
content: "Beta";
|
||||
}
|
||||
|
||||
.small.badge {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
/* uibanner */
|
||||
|
||||
.uibanner .icon {
|
||||
max-width: 30px;
|
||||
border-radius: 7px;
|
||||
border: 0.75px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.uibanner {
|
||||
z-index: 5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 1px;
|
||||
border-bottom: 0.1px solid var(--color-separator);
|
||||
}
|
||||
|
||||
.uibanner {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.uibanner>.icon {
|
||||
margin-left: 14px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.uibanner>.content {
|
||||
min-height: 28px;
|
||||
width: 100%;
|
||||
margin-left: 8px;
|
||||
padding: 8px 16px 8px 0px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uibanner>.content>.text-container>.title-text {
|
||||
padding-bottom: 0 !important;
|
||||
font-weight: 600;
|
||||
font-size: 12.95px !important;
|
||||
}
|
||||
|
||||
.uibanner>.content>.text-container>.detail-text {
|
||||
padding-top: 0 !important;
|
||||
font-size: 11px !important;
|
||||
font-weight: 400;
|
||||
line-height: 12px !important;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.uibanner>.content button {
|
||||
min-width: 68px !important;
|
||||
padding: 5px 13px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
color: white;
|
||||
background-color: rgb(0, 122, 254);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.uibanner>.content a {
|
||||
margin-left: 6px;
|
||||
text-decoration: none;
|
||||
color: unset;
|
||||
font-weight: 600;
|
||||
|
||||
color: white;
|
||||
}
|
||||
5
common/vendor/bootstrap-icons-1.11.2/bootstrap-icons.min.css
vendored
Normal file
5
common/vendor/bootstrap-icons-1.11.2/bootstrap-icons.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
common/vendor/bootstrap-icons-1.11.2/fonts/bootstrap-icons.woff
vendored
Normal file
BIN
common/vendor/bootstrap-icons-1.11.2/fonts/bootstrap-icons.woff
vendored
Normal file
Binary file not shown.
BIN
common/vendor/bootstrap-icons-1.11.2/fonts/bootstrap-icons.woff2
vendored
Normal file
BIN
common/vendor/bootstrap-icons-1.11.2/fonts/bootstrap-icons.woff2
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user