Tab cloaking

This commit is contained in:
rift 2023-12-27 10:46:42 -06:00
parent 78635d2671
commit 4d7c8449d8
13 changed files with 150 additions and 36 deletions

View file

@ -2,10 +2,8 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>Nebula</title>
<script src="/uv/uv.bundle.js"></script>
<script src="/uv/uv.config.js"></script>
<script src="/dynamic/dynamic.config.js"></script>

View file

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

View file

@ -44,6 +44,10 @@
"embed": "Embed",
"direct": "Direct",
"aboutblank": "About:Blank"
},
"cloaking": {
"title": "Cloaking",
"subtitle": "Choose how your tab looks"
}
},
"titles": {

View file

@ -44,6 +44,10 @@
"embed": "Incrustar",
"direct": "Directo",
"aboutblank": "About:Blank"
},
"cloaking": {
"title": "Encubrimiento",
"subtitle": "Elige cómo se ve tu pestaña"
}
},
"titles": {

View file

@ -44,6 +44,10 @@
"embed": "埋め込む",
"direct": "直接",
"aboutblank": "About:Blank"
},
"cloaking": {
"title": "クローキング",
"subtitle": "タブの見た目を選択する"
}
},
"titles": {

View file

@ -1,8 +1,7 @@
import { useState } from "preact/hooks";
import { useTranslation } from "react-i18next";
import { HeaderRoute } from "../components/HeaderRoute";
import { Helmet } from "react-helmet";
import CloakedHead from "../util/CloakedHead";
export function Home() {
const [isFocused, setIsFocused] = useState(false);
const [inputValue, setInputValue] = useState("");
@ -15,9 +14,10 @@ export function Home() {
return (
<HeaderRoute>
<Helmet>
<title>{t("titles.home")}</title>
</Helmet>
<CloakedHead
originalTitle={t("titles.home")}
originalFavicon="/logo.png"
/>
<div class="flex h-full flex-col items-center justify-center">
<div class="font-inter absolute bottom-0 left-0 p-4 text-sm italic text-input-text">
Nebula &copy; Nebula Services {new Date().getUTCFullYear()}

View file

@ -3,8 +3,9 @@ import { searchUtil } from "../util/searchUtil";
import { useEffect, useState } from "preact/hooks";
//import our Iframe component
import { Iframe } from "../components/iframe/Iframe";
import CloakedHead from "../util/CloakedHead";
import SiteSupport from "../util/SiteSupport.json";
import { useTranslation } from "react-i18next";
declare global {
interface Window {
@ -14,6 +15,7 @@ declare global {
}
export function ProxyFrame(props: { url: string }) {
const { t } = useTranslation();
// pass the URL encoded with encodeURIcomponent
const localProxy = localStorage.getItem("proxy") || "automatic";
const proxyMode = localStorage.getItem("proxyMode") || "embed";
@ -104,6 +106,10 @@ export function ProxyFrame(props: { url: string }) {
}
return (
<div class="h-screen w-screen bg-primary">
<CloakedHead
originalTitle={t("titles.home")}
originalFavicon="/logo.png"
/>
{proxyMode === "direct" && <h1>Loading {localProxy}...</h1>}
{proxyMode === "aboutblank" && <h1>Loading {localProxy}...</h1>}
{proxyMode === "embed" && <Iframe url={ProxiedUrl} />}

View file

@ -0,0 +1,30 @@
import { useState, useEffect } from "preact/hooks";
interface Props {
faviconUrl: string;
title: string;
}
const CloakPreset = (props: Props) => {
const cloak = (event: any) => {
event.preventDefault();
console.log(props.faviconUrl);
localStorage.setItem("cloakFavicon", props.faviconUrl);
localStorage.setItem("cloakTitle", props.title);
window.location.reload();
};
return (
<div
onClick={cloak}
class="cursor-pointer rounded-full border border-input-border-color bg-lighter"
>
<img
src={props.faviconUrl === "none" ? "/logo.png" : props.faviconUrl}
class="h-16 w-16 p-4"
/>
</div>
);
};
export default CloakPreset;

View file

@ -1,7 +1,12 @@
import { motion } from "framer-motion";
import { tabContentVariant, settingsPageVariant } from "./Variants";
import CloakPreset from "./CloakPreset";
import { useTranslation } from "react-i18next";
const TabSettings = ({ id, active }) => (
const TabSettings = ({ id, active }) => {
const { t } = useTranslation();
return (
<motion.div
role="tabpanel"
id={id}
@ -10,11 +15,33 @@ const TabSettings = ({ id, active }) => (
animate={active ? "active" : "inactive"}
initial="inactive"
>
<motion.div variants={settingsPageVariant} className="content-card text-center w-full flex flex-col justify-center items-center">
<img src="/comingsoonsnake.png" class="h-72 w-72"></img>
<h1 class="font-roboto text-3xl">Coming soon!</h1>
<motion.div
variants={settingsPageVariant}
className="content-card flex w-full flex-col items-center justify-center text-center"
>
<div class="text-3xl">{t("settings.cloaking.title")}</div>
<div class="text-md pb-5">{t("settings.cloaking.subtitle")}</div>
<div class="flex flex-row space-x-4">
<CloakPreset faviconUrl="none" title="none" />
<CloakPreset
faviconUrl="https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://google.com&size=32"
title="Google"
/>
<CloakPreset
faviconUrl="https://www.wikipedia.org/static/favicon/wikipedia.ico"
title="Wikipedia"
/>
<CloakPreset
faviconUrl="https://du11hjcvx0uqb.cloudfront.net/dist/images/favicon-e10d657a73.ico"
title="Dashboard"
/>
<CloakPreset
faviconUrl="https://ssl.gstatic.com/classroom/ic_product_classroom_144.png"
title="Home"
/>
</div>
</motion.div>
</motion.div>
);
};
export default TabSettings;

View file

@ -1,17 +1,18 @@
import TabComponent from "./TabComponent";
import { HeaderRoute } from "../../components/HeaderRoute";
import tabs from "./tabs";
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import CloakedHead from "../../util/CloakedHead";
export function Settings() {
const { t } = useTranslation();
return (
<HeaderRoute>
<Helmet>
<title>{t("titles.settings")}</title>
</Helmet>
<CloakedHead
originalTitle={t("titles.settings")}
originalFavicon="/logo.png"
/>
<TabComponent tabs={tabs} />
</HeaderRoute>
);

View file

@ -1,16 +1,17 @@
import { useTranslation } from "react-i18next";
import { Link } from "preact-router";
import { HeaderRoute } from "../components/HeaderRoute";
import { Helmet } from "react-helmet";
import CloakedHead from "../util/CloakedHead";
export function NotFound() {
const { t } = useTranslation();
return (
<HeaderRoute>
<Helmet>
<title>{t("titles.404")}</title>
</Helmet>
<CloakedHead
originalTitle={t("titles.404")}
originalFavicon="/logo.png"
/>
<section class="h-full">
<div class="flex h-full flex-col items-center justify-center">
<img src="/404.png" class="h-72"></img>

View file

@ -1,18 +1,19 @@
import { useTranslation } from "react-i18next";
import { HeaderRoute } from "../components/HeaderRoute";
import { Helmet } from "react-helmet";
import CloakedHead from "../util/CloakedHead";
export function DiscordPage() {
const { t } = useTranslation();
return (
<HeaderRoute>
<Helmet>
<title>{t("titles.discord")}</title>
</Helmet>
<CloakedHead
originalTitle={t("titles.discord")}
originalFavicon="/logo.png"
/>
<section class="h-full">
<div class="flex h-full flex-col items-center justify-center">
<img src="/discord.png" class="h-72 w-72"></img>
<img src="/services.png" class="h-72 w-72"></img>
<div class="flex flex-col items-center p-6">
<p class="font-roboto text-4xl font-bold">{t("discord.title")}</p>
<span class="font-roboto text-3xl">{t("discord.sub")}</span>

38
src/util/CloakedHead.tsx Normal file
View file

@ -0,0 +1,38 @@
import { Helmet } from "react-helmet";
interface Props {
originalTitle: string;
originalFavicon: string;
}
const CloakedHead = (props: Props) => {
var isTitleCloaked =
localStorage.getItem("cloakTitle") !== null
? localStorage.getItem("cloakTitle") !== "none"
: false;
var isFaviconCloaked =
localStorage.getItem("cloakFavicon") !== null
? localStorage.getItem("cloakFavicon") !== "none"
: false;
return (
<Helmet>
<title>
{isTitleCloaked
? localStorage.getItem("cloakTitle")
: props.originalTitle}
</title>
<link
rel="icon"
href={
isFaviconCloaked
? localStorage.getItem("cloakFavicon")
: props.originalFavicon
}
/>
</Helmet>
);
};
export default CloakedHead;