Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@
"expiration"
],
"devDependencies": {
"bumpp": "^9.5.2"
"bumpp": "^9.11.1"
},
"pnpm": {
"overrides": {
"tar": ">=7.5.7",
"esbuild": ">=0.25.0",
"cross-spawn": ">=7.0.5",
"undici": ">=6.23.0",
"@eslint/plugin-kit": ">=0.3.4",
"tmp": ">=0.2.4"
}
}
}
24 changes: 12 additions & 12 deletions packages/app-client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>Enclosed - Send private and secure notes</title>
<title>TWN - Send private and secure notes</title>

<meta name="title" content="Enclosed - Send private and secure notes">
<meta name="description" content="Enclosed is a secure, end-to-end encrypted platform for sending private notes. Set expiration, passwords, and self-destruct options to keep your notes confidential.">
<meta name="title" content="TWN - Send private and secure notes">
<meta name="description" content="TWN is a secure, end-to-end encrypted platform for sending private notes. Set expiration, passwords, and self-destruct options to keep your notes confidential.">

<link rel="author" href="humans.txt" />
<link rel="canonical" href="https://enclosed.cc/" />

<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://enclosed.cc/">
<meta property="og:title" content="Enclosed - Send private and secure notes">
<meta property="og:description" content="Enclosed is a secure, end-to-end encrypted platform for sending private notes. Set expiration, passwords, and self-destruct options to keep your notes confidential.">
<meta property="og:title" content="TWN - Send private and secure notes">
<meta property="og:description" content="TWN is a secure, end-to-end encrypted platform for sending private notes. Set expiration, passwords, and self-destruct options to keep your notes confidential.">
<meta property="og:image" content="https://enclosed.cc/og-image.png">

<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://enclosed.cc/">
<meta property="twitter:title" content="Enclosed - Send private and secure notes">
<meta property="twitter:description" content="Enclosed is a secure, end-to-end encrypted platform for sending private notes. Set expiration, passwords, and self-destruct options to keep your notes confidential.">
<meta property="twitter:title" content="TWN - Send private and secure notes">
<meta property="twitter:description" content="TWN is a secure, end-to-end encrypted platform for sending private notes. Set expiration, passwords, and self-destruct options to keep your notes confidential.">
<meta property="twitter:image" content="https://enclosed.cc/og-image.png">

<!-- Favicon and Icons -->
Expand All @@ -38,25 +38,25 @@
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "Enclosed",
"name": "TWN",
"url": "https://enclosed.cc/",
"description": "Send private and secure notes with end-to-end encryption. Enclosed offers configurable security features like passwords, expiration times, and self-destruction after reading.",
"description": "Send private and secure notes with end-to-end encryption. TWN offers configurable security features like passwords, expiration times, and self-destruction after reading.",
"applicationCategory": "Utilities",
"operatingSystem": "Web",
"browserRequirements": "Requires JavaScript",
"image": "https://enclosed.cc/og-image.png",
"creator": {
"@type": "Organization",
"name": "Enclosed"
"name": "TWN"
}
}
</script>

<style>.sr-only {position: absolute;width: 1px;height: 1px;padding: 0;margin: -1px;overflow: hidden;clip: rect(0, 0, 0, 0);white-space: nowrap;border-width: 0;}</style>
</head>
<body>
<h1 class="sr-only">Enclosed - Send Private and Secure Notes</h1>
<p class="sr-only">Enclosed is a secure platform for sending private notes. All notes are end-to-end encrypted with zero knowledge on the server side.</p>
<h1 class="sr-only">TWN - Send Private and Secure Notes</h1>
<p class="sr-only">TWN is a secure platform for sending private notes. All notes are end-to-end encrypted with zero knowledge on the server side.</p>

<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
Expand Down
34 changes: 17 additions & 17 deletions packages/app-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,34 @@
"dependencies": {
"@corentinth/chisels": "catalog:",
"@enclosed/lib": "workspace:*",
"@kobalte/core": "^0.13.4",
"@solid-primitives/i18n": "^2.1.1",
"@solid-primitives/storage": "^4.2.1",
"@solidjs/router": "^0.14.3",
"@unocss/reset": "^0.64.0",
"class-variance-authority": "^0.7.0",
"@kobalte/core": "^0.13.11",
"@solid-primitives/i18n": "^2.2.1",
"@solid-primitives/storage": "^4.3.3",
"@solidjs/router": "^0.14.10",
"@unocss/reset": "^0.64.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"jszip": "^3.10.1",
"lodash-es": "^4.17.21",
"solid-js": "^1.9.5",
"lodash-es": "^4.17.23",
"solid-js": "^1.9.11",
"solid-sonner": "^0.2.8",
"tailwind-merge": "^2.5.2",
"unocss-preset-animations": "^1.1.0",
"tailwind-merge": "^2.6.0",
"unocss-preset-animations": "^1.3.0",
"uqr": "^0.1.2"
},
"devDependencies": {
"@antfu/eslint-config": "catalog:",
"@iconify-json/tabler": "^1.2.17",
"@playwright/test": "^1.46.1",
"@iconify-json/tabler": "^1.2.26",
"@playwright/test": "^1.58.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "catalog:",
"eslint": "catalog:",
"jsdom": "^25.0.0",
"tsx": "^4.19.3",
"jsdom": "^25.0.1",
"tsx": "^4.21.0",
"typescript": "catalog:",
"unocss": "^0.64.0",
"vite": "^5.0.11",
"vite-plugin-solid": "^2.11.6",
"unocss": "^0.64.1",
"vite": "^5.4.21",
"vite-plugin-solid": "^2.11.10",
"vitest": "catalog:"
}
}
26 changes: 18 additions & 8 deletions packages/app-client/src/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"app": {
"title": "Enclosed",
"title": "TWN",
"description": "Send private and secure notes"
},
"insecureContextWarning": {
Expand All @@ -23,23 +23,33 @@
"system-mode": "System"
},
"settings": {
"documentation": "Documentation",
"cli": "Enclosed CLI",
"support": "Support Enclosed",
"report-bug": "Report a bug",
"twn-it": "TWN IT",
"learning-platform": "Learning Platform",
"trust-centre": "Trust Centre",
"about": "About",
"privacy": "Privacy",
"terms": "Terms",
"report-bug": "Report Issue",
"logout": "Logout",
"contribute-to-i18n": "Contribute to i18n"
}
},
"footer": {
"crafted-by": "Crafted by",
"hosted-by": "Hosted with Cloudflare Pages + KV By TWN",
"twn-it": "TWN IT",
"learning-platform": "Learning Platform",
"trust-centre": "Trust Centre",
"about": "About",
"privacy": "Privacy",
"terms": "Terms",
"report-issue": "Report Issue",
Comment on lines +26 to +45

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

LOCALE_DIR="packages/app-client/src/locales"

python - <<'PY'
import json, os, glob

dir_path = "packages/app-client/src/locales"
en_path = os.path.join(dir_path, "en.json")

def flatten(obj, prefix=""):
    keys = set()
    if isinstance(obj, dict):
        for k, v in obj.items():
            new = f"{prefix}.{k}" if prefix else k
            keys.add(new)
            keys |= flatten(v, new)
    elif isinstance(obj, list):
        keys.add(prefix)
    return keys

with open(en_path, encoding="utf-8") as f:
    en = json.load(f)

en_keys = flatten(en)
missing_any = False

for path in sorted(glob.glob(os.path.join(dir_path, "*.json"))):
    if os.path.basename(path) == "en.json":
        continue
    with open(path, encoding="utf-8") as f:
        other = json.load(f)
    other_keys = flatten(other)
    missing = sorted(en_keys - other_keys)
    if missing:
        missing_any = True
        print(f"{path} missing {len(missing)} keys:")
        for k in missing[:50]:
            print("  -", k)
        if len(missing) > 50:
            print("  ...")

if not missing_any:
    print("All locale files contain the en.json keys.")
PY

Repository: TWN-Systems/enclosed

Length of output: 11089


All locale files except en.json are missing the new footer and navbar.settings keys.

Every other locale file (ar, de, es, fr, hu, id, it, nl, pl, pt-BR, pt, ru, tr, vi, zh-CN, zh-TW) is missing the new translation keys you've added to en.json at lines 26-45. Specifically, all are missing:

  • footer.about, footer.hosted-by, footer.learning-platform, footer.privacy, footer.report-issue, footer.terms, footer.trust-centre, footer.twn-it
  • navbar.settings.about, navbar.settings.learning-platform, navbar.settings.privacy, navbar.settings.terms, navbar.settings.trust-centre, navbar.settings.twn-it

Update all locale JSON files to include these keys and their translations to prevent untranslated UI strings for non-English users.

🤖 Prompt for AI Agents
In `@packages/app-client/src/locales/en.json` around lines 26 - 45, Multiple
locale JSON files are missing the new translation keys introduced in en.json for
footer and navbar.settings (keys like footer.about, footer.hosted-by,
footer.learning-platform, footer.privacy, footer.report-issue, footer.terms,
footer.trust-centre, footer.twn-it and navbar.settings.about,
navbar.settings.learning-platform, navbar.settings.privacy,
navbar.settings.terms, navbar.settings.trust-centre, navbar.settings.twn-it);
update every non-English locale file (ar, de, es, fr, hu, id, it, nl, pl, pt-BR,
pt, ru, tr, vi, zh-CN, zh-TW) to include these keys under the same JSON nesting
and provide appropriate translations (or temporarily copy the en.json values as
placeholders) so the UI strings are present for all locales.

"source-code": "Source code available on",
"github": "GitHub",
"version": "Version"
},
"login": {
"title": "Login to Enclosed",
"description": "This is a private instance of Enclosed. Enter your credentials to be able to create notes.",
"title": "Login to TWN",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prefer verb form: “Log in to TWN.”

Minor copy fix for grammatical correctness in the title.

✏️ Suggested copy tweak
-    "title": "Login to TWN",
+    "title": "Log in to TWN",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"title": "Login to TWN",
"title": "Log in to TWN",
🤖 Prompt for AI Agents
In `@packages/app-client/src/locales/en.json` at line 51, Change the JSON value
for the "title" key from the imperative noun phrase "Login to TWN" to the verb
form "Log in to TWN." so update the "title" entry in
packages/app-client/src/locales/en.json (the "title" key) to read "Log in to
TWN." ensuring punctuation and capitalization match the suggested copy.

"description": "This is a private instance of TWN. Enter your credentials to be able to create notes.",
"email": "Email",
"password": "Password",
"submit": "Login",
Expand Down
31 changes: 31 additions & 0 deletions packages/app-client/src/modules/ui/components/logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Component, JSX } from 'solid-js';

export const Logo: Component<{ class?: string } & JSX.SvgSVGAttributes<SVGSVGElement>> = (props) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 180 40"
class={props.class}
fill="currentColor"
{...props}
>
{/* 3D House base */}
<polygon points="8,35 8,20 22,20 22,35" />
<polygon points="22,20 22,35 32,30 32,15" />
{/* Roof */}
<polygon points="5,20 15,8 25,20" />
<polygon points="25,20 15,8 35,15 32,15" />
{/* Chimney */}
<rect x="8" y="6" width="4" height="8" />
{/* Front windows */}
<rect x="10" y="22" width="4" height="4" class="fill-background" />
<rect x="16" y="22" width="4" height="4" class="fill-background" />
{/* Door */}
<rect x="24" y="23" width="4" height="7" class="fill-background" />
{/* Side window */}
<rect x="26" y="18" width="3" height="3" class="fill-background" />
{/* TWN Text */}
<text x="50" y="30" font-family="Arial Black, sans-serif" font-weight="900" font-size="24">TWN</text>
</svg>
);
};
117 changes: 80 additions & 37 deletions packages/app-client/src/modules/ui/layouts/app.layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useNoteContext } from '@/modules/notes/notes.context';
import { cn } from '@/modules/shared/style/cn';
import { useThemeStore } from '@/modules/theme/theme.store';
import { Button } from '@/modules/ui/components/button';
import { Logo } from '@/modules/ui/components/logo';
import { DropdownMenu } from '@kobalte/core/dropdown-menu';

import { A, useNavigate } from '@solidjs/router';
Expand Down Expand Up @@ -61,7 +62,7 @@ const LanguageSwitcher: Component = () => {

<DropdownMenuSeparator />

<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" rel="noopener noreferrer" href="https://github.com/CorentinTh/enclosed/tree/main/packages/app-client/src/locales">
<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" rel="noopener noreferrer" href="https://github.com/TWN-Systems/enclosed/tree/main/packages/app-client/src/locales">
{t('navbar.settings.contribute-to-i18n')}
<div class="i-tabler-external-link text-lg text-muted-foreground"></div>
</DropdownMenuItem>
Expand Down Expand Up @@ -89,8 +90,8 @@ export const Navbar: Component = () => {
<div class="border-b border-border bg-surface">
<div class="flex items-center justify-between px-6 py-3 mx-auto max-w-1200px">
<div class="flex items-baseline gap-4">
<Button variant="link" class="text-lg font-semibold border-b border-transparent hover:(no-underline !border-border) h-auto py-0 px-1 ml--1 rounded-none !transition-border-color-250" onClick={newNoteClicked}>
{t('app.title')}
<Button variant="link" class="text-lg font-semibold border-b border-transparent hover:(no-underline !border-border) h-auto py-0 px-1 ml--1 rounded-none !transition-border-color-250" onClick={newNoteClicked} aria-label={t('app.title')}>
<Logo class="h-6 w-auto" />
</Button>

<span class="text-muted-foreground hidden sm:block">
Expand All @@ -107,7 +108,7 @@ export const Navbar: Component = () => {
</Button>
)}

<Button variant="ghost" class="text-lg px-0 size-9 hidden md:inline-flex" as={A} href="https://github.com/CorentinTh/enclosed" target="_blank" rel="noopener noreferrer" aria-label={t('navbar.github-repository')}>
<Button variant="ghost" class="text-lg px-0 size-9 hidden md:inline-flex" as={A} href="https://github.com/TWN-Systems/enclosed" target="_blank" rel="noopener noreferrer" aria-label={t('navbar.github-repository')}>
<div class="i-tabler-brand-github"></div>
</Button>

Expand Down Expand Up @@ -139,7 +140,7 @@ export const Navbar: Component = () => {
<DropdownMenuContent class="w-46">

{/* Mobile only items */}
<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer md:hidden" target="_blank" href="https://github.com/CorentinTh/enclosed" rel="noopener noreferrer">
<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer md:hidden" target="_blank" href="https://github.com/TWN-Systems/enclosed" rel="noopener noreferrer">
<div class="i-tabler-brand-github text-lg"></div>
{t('navbar.github')}
</DropdownMenuItem>
Expand Down Expand Up @@ -167,24 +168,43 @@ export const Navbar: Component = () => {
</DropdownMenuSub>

{/* Default items */}
<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href={buildDocUrl({ path: '/' })}>
<div class="i-tabler-file-text text-lg"></div>
{t('navbar.settings.documentation')}
<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href="https://www.twn.it.com/" rel="noopener noreferrer">
<div class="i-tabler-building text-lg"></div>
{t('navbar.settings.twn-it')}
</DropdownMenuItem>

<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href={buildDocUrl({ path: '/integrations/cli' })}>
<div class="i-tabler-terminal text-lg"></div>
{t('navbar.settings.cli')}
<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href="https://learning.twn.systems/" rel="noopener noreferrer">
<div class="i-tabler-school text-lg"></div>
{t('navbar.settings.learning-platform')}
</DropdownMenuItem>

<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href="https://github.com/CorentinTh/enclosed/issues/new/choose" rel="noopener noreferrer">
<div class="i-tabler-bug text-lg"></div>
{t('navbar.settings.report-bug')}
<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href="https://twn.trustshare.com/home" rel="noopener noreferrer">
<div class="i-tabler-shield-check text-lg"></div>
{t('navbar.settings.trust-centre')}
</DropdownMenuItem>

<DropdownMenuSeparator />

<DropdownMenuItem as={A} class="flex items-center gap-2 cursor-pointer" href="/about">
<div class="i-tabler-info-circle text-lg"></div>
{t('navbar.settings.about')}
</DropdownMenuItem>

<DropdownMenuItem as={A} class="flex items-center gap-2 cursor-pointer" href="/privacy">
<div class="i-tabler-lock text-lg"></div>
{t('navbar.settings.privacy')}
</DropdownMenuItem>

<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href="https://buymeacoffee.com/cthmsst" rel="noopener noreferrer">
<div class="i-tabler-pig-money text-lg"></div>
{t('navbar.settings.support')}
<DropdownMenuItem as={A} class="flex items-center gap-2 cursor-pointer" href="/terms">
<div class="i-tabler-file-certificate text-lg"></div>
{t('navbar.settings.terms')}
</DropdownMenuItem>

<DropdownMenuSeparator />

<DropdownMenuItem as="a" class="flex items-center gap-2 cursor-pointer" target="_blank" href="https://github.com/TWN-Systems/enclosed/issues/new/choose" rel="noopener noreferrer">
<div class="i-tabler-bug text-lg"></div>
{t('navbar.settings.report-bug')}
</DropdownMenuItem>

{config.isAuthenticationRequired && authStore.getIsAuthenticated() && (
Expand All @@ -210,28 +230,51 @@ export const Footer: Component = () => {
const { t } = useI18n();

return (
<div class="bg-surface border-t border-border py-6 px-6 text-center text-muted-foreground flex flex-col sm:flex-row items-center justify-center gap-1">
<div>
{t('footer.crafted-by')}
{' '}
<Button variant="link" as="a" href="https://corentin.tech" target="_blank" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">Corentin Thomasset</Button>
.
</div>
<div>
{t('footer.source-code')}
{' '}
<Button variant="link" as="a" href="https://github.com/CorentinTh/enclosed" target="_blank" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">{t('footer.github')}</Button>
.
</div>
<div class="bg-surface border-t border-border py-6 px-6 text-muted-foreground">
<div class="max-w-1200px mx-auto">
<div class="text-center mb-4">
{t('footer.hosted-by')}
</div>

<div>
{t('footer.version')}
{' '}
<Button variant="link" as="a" href={`https://github.com/CorentinTh/enclosed/tree/v${buildTimeConfig.enclosedVersion}`} target="_blank" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
v
{buildTimeConfig.enclosedVersion}
</Button>
<div class="flex flex-wrap justify-center gap-x-4 gap-y-2 mb-4">
<Button variant="link" as="a" href="https://www.twn.it.com/" target="_blank" rel="noopener noreferrer" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{t('footer.twn-it')}
</Button>
<Button variant="link" as="a" href="https://learning.twn.systems/" target="_blank" rel="noopener noreferrer" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{t('footer.learning-platform')}
</Button>
<Button variant="link" as="a" href="https://twn.trustshare.com/home" target="_blank" rel="noopener noreferrer" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{t('footer.trust-centre')}
</Button>
<Button variant="link" as="a" href="/about" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{t('footer.about')}
</Button>
<Button variant="link" as="a" href="/privacy" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{t('footer.privacy')}
</Button>
<Button variant="link" as="a" href="/terms" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{t('footer.terms')}
</Button>
<Button variant="link" as="a" href="https://github.com/TWN-Systems/enclosed/issues/new/choose" target="_blank" rel="noopener noreferrer" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{t('footer.report-issue')}
</Button>
</div>

<div class="flex flex-col sm:flex-row items-center justify-center gap-1 text-center">
<div>
{t('footer.source-code')}
{' '}
<Button variant="link" as="a" href="https://github.com/TWN-Systems/enclosed" target="_blank" rel="noopener noreferrer" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">{t('footer.github')}</Button>
.
</div>
<div>
{t('footer.version')}
{' '}
<Button variant="link" as="a" href={`https://github.com/TWN-Systems/enclosed/releases/tag/v${buildTimeConfig.enclosedVersion}`} target="_blank" rel="noopener noreferrer" class="p-0 text-muted-foreground underline hover:text-primary transition font-normal h-auto">
{buildTimeConfig.enclosedVersion}
</Button>
</div>
</div>
</div>
</div>
);
Expand Down
Loading