I18n cleanup (#382)

* #374 rm custom tea-cli notification

* #370 apply i18n to several statements

* #370 remove unused i18n and components

---------

Co-authored-by: neil molina <neil@neils-MacBook-Pro.local>
This commit is contained in:
Neil 2023-04-03 14:50:00 +08:00 committed by GitHub
parent 3acce8ac0c
commit 5fec6e16f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 65 additions and 546 deletions

View file

@ -17,7 +17,7 @@
<PanelHeader {title} {ctaLabel} ctaLink="/" />
{#if courses.length}
<Posts posts={courses} readMoreCta={$t("post.read-more-cta")} linkTarget="_blank" />
<Posts posts={courses} linkTarget="_blank" />
{:else}
<section class="border-gray h-64 border bg-black p-4">
<Preloader />

View file

@ -1,39 +0,0 @@
<script lang="ts">
import '$appcss';
import { t } from '$libs/translations';
import type { GUIPackage } from '$libs/types';
import { PackageStates } from '$libs/types';
import PanelHeader from '@tea/ui/panel-header/panel-header.svelte';
import { packagesStore } from '$libs/stores';
import MiniPackageCard from '@tea/ui/mini-package-card/mini-package-card.svelte';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
let packages: GUIPackage[] = [];
packagesStore.subscribe((v) => {
packages = v.filter((p) => p.state === PackageStates.INSTALLED);
});
</script>
<PanelHeader title={$t("package.my-installs-title")} ctaLabel={`${$t("package.check-for-updates")} >`} ctaLink="#" />
<ul class="border-gray grid grid-cols-3 border border-r-0 bg-black">
{#if packages.length > 0}
{#each packages as pkg}
<div class="border-gray border border-t-0 border-l-0 p-4">
<MiniPackageCard
{pkg}
ctaLabel={$t("package.details").toUpperCase()}
onClickCTA={async () => {
console.log('do something with:', pkg.full_name);
}}
/>
</div>
{/each}
{:else}
{#each Array(12) as _}
<section class="h-50 border-gray border p-4">
<Preloader />
</section>
{/each}
{/if}
</ul>

View file

@ -12,7 +12,7 @@
postsStore.subscribeByTag('news', (posts) => (news = posts));
</script>
<PanelHeader title={$t("home.os-news-title")} ctaLabel={`${$t("post.article-more-cta")} >`} ctaLink="/" />
<PanelHeader title="OPEN-SOURCE NEWS" ctaLabel="Read more articles" ctaLink="/" />
{#if news.length}
<Posts posts={news} linkTarget="_blank" />
{:else}

View file

@ -1,6 +1,7 @@
<script lang="ts">
import "$appcss";
import "@tea/ui/icons/icons.css";
import { t } from '$libs/translations';
import Button from "@tea/ui/button/button.svelte";
import { installPackage } from "@native";
@ -50,7 +51,7 @@
color="black"
onClick={() => {
shellOpenExternal(`https://github.com/${pkg.github}`);
}}>View on github</Button
}}>{$t("common.view-on-github")}</Button
>
{/if}
</menu>

View file

@ -1,58 +0,0 @@
<script lang="ts">
import '$appcss';
import { t } from '$libs/translations';
import { postsStore } from '$libs/stores';
import type { AirtablePost } from '@tea/ui/types';
import Posts from '@tea/ui/posts/posts.svelte';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
let posts: AirtablePost[] = [];
let tab: "ALL" | "ARTICLE" | "WORKSHOP" = "ALL";
const setPosts = (newPosts: AirtablePost[]) => {
posts = tab === "ALL" ? newPosts : newPosts.filter((p) => p.tags.includes(tab));
}
const switchTab = (nextTab: "ALL" | "ARTICLE" | "WORKSHOP") => {
tab = nextTab;
setPosts($postsStore);
}
postsStore.subscribe(setPosts);
</script>
<header class="flex items-center justify-between border border-gray bg-black p-4 text-primary">
<div>{$t("home.resources")}</div>
<section class="border border-gray mr-2 rounded-sm h-10 text-gray font-thin flex">
<button on:click={() => switchTab("ALL")} class={`px-2 ${tab === "ALL" && "active"}`}>{$t("common.all")}</button>
<button on:click={() => switchTab("ARTICLE")} class={`px-2 ${tab === "ARTICLE" && "active"}`}>{$t("common.articles")}</button>
<button on:click={() => switchTab("WORKSHOP")} class={`px-2 ${tab === "WORKSHOP" && "active"}`}>{$t("common.workshops")}</button>
</section>
</header>
{#if posts.length}
<Posts {posts} linkTarget="_blank" />
{:else}
<section class="border-gray h-64 border bg-black p-4">
<Preloader />
</section>
{/if}
<style>
button {
height: 100%;
text-decoration: none;
min-width: 120px;
transition: 0.1s linear;
}
button:hover, button.active {
color: white;
background-color: #8000ff;
box-shadow: inset 0vw 0vw 0vw 0.223vw #1a1a1a !important;
box-sizing: border-box;
}
</style>

View file

@ -1,93 +0,0 @@
<script lang="ts">
import '$appcss';
import { t } from '$libs/translations';
import { packagesStore } from '$libs/stores';
import SortingButtons from './sorting-buttons.svelte';
import type { GUIPackage } from '$libs/types';
import { PackageStates } from '$libs/types';
import Package from "$components/packages/package.svelte";
import SearchInput from '@tea/ui/search-input/search-input.svelte';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
import { installPackage } from '@native';
let packages: GUIPackage[] = [];
let sortBy = 'popularity';
let sortDirection: 'asc' | 'desc' = 'desc';
const searchLimit = 10;
const setPackages = (pkgs: GUIPackage[], isSearch?: boolean) => {
packages = isSearch
? pkgs
: pkgs.sort((a, b) => {
if (sortBy === 'popularity') {
const aPop = +a.dl_count + a.installs;
const bPop = +b.dl_count + b.installs;
return sortDirection === 'asc' ? aPop - bPop : bPop - aPop;
} else {
// most recent
const aDate = new Date(a.last_modified);
const bDate = new Date(b.last_modified);
return sortDirection === 'asc' ? +aDate - +bDate : +bDate - +aDate;
}
});
};
const onSearch = async (term: string) => {
if (term !== '' && term.length > 1) {
const matchingPackages: GUIPackage[] = await packagesStore.search(term, searchLimit);
setPackages(matchingPackages, true);
} else {
setPackages(packagesStore.packages, false);
}
};
const onSort = (opt: string, dir: 'asc' | 'desc') => {
sortBy = opt;
sortDirection = dir;
setPackages(packages);
};
packagesStore.subscribe(setPackages);
</script>
<div class="border-gray border bg-black">
<section class="flex items-center justify-between">
<div>
<SearchInput size="medium" {onSearch} placeholder={`${$t("search")}_`} />
</div>
<div class="pr-4">
<section class="border-gray h-12 w-48 border">
<SortingButtons {onSort} />
</section>
</div>
</section>
<ul class="grid grid-cols-3">
{#if packages.length > 0}
{#each packages as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<Package
{pkg}
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg);
pkg.state = PackageStates.INSTALLED;
} catch (error) {
console.error(error);
}
}}
/>
</div>
{/each}
{:else}
{#each Array(12) as _}
<section class="h-50 border-gray border p-4">
<Preloader />
</section>
{/each}
{/if}
</ul>
</div>

View file

@ -1,101 +0,0 @@
<script lang="ts">
import { t } from '$libs/translations';
import Button from '@tea/ui/button/button.svelte';
import { openTerminal } from '@native';
import { packagesStore } from '$libs/stores';
import { PackageStates, type GUIPackage } from '$libs/types';
type CliUpdateState = 'unknown' | 'not_installed' | 'update_required' | 'up_to_date' | 'updated';
$: updateState = 'unknown' as CliUpdateState;
const getCliUpdateState = (pkg: GUIPackage | null): CliUpdateState => {
if (!pkg) {
return 'unknown';
}
if (pkg.state != PackageStates.INSTALLED){
return 'not_installed';
}
if (!pkg.installed_versions?.includes(pkg.version)) {
return 'update_required';
}
return 'up_to_date';
}
packagesStore.subscribeToPackage("tea_xyz", (pkg) => {
if (updateState !== 'updated' ) {
updateState = getCliUpdateState(pkg);
}
});
const onOpenTerminal = async () => {
console.log("installing tea...")
try {
openTerminal(`sh <(curl https://tea.xyz)`);
} catch (error) {
console.log("install failed")
}
updateState = 'updated';
}
</script>
{#if updateState === 'not_installed'}
<div class="banner flex items-center justify-center text-primary">
<span class="text-white mr-4">{$t('package.install-tea-cli')}</span>
<button class="button" on:click={onOpenTerminal}>{$t("package.install-tea-label")}</button>
</div>
{/if}
{#if updateState === 'update_required'}
<div class="banner flex items-center justify-center text-primary">
<span class="text-white mr-4">{$t('package.update-tea-cli')}</span>
<button class="button" on:click={onOpenTerminal}>{$t("package.update-tea-label")}</button>
</div>
{/if}
<style>
.banner {
background-color: #FF4100;
margin-bottom: 16px;
border-radius: 4px;
padding: 6px;
z-index: 1;
position: relative;
padding-top: 12px;
padding-bottom: 12px;
}
.button {
color: white;
border: 1px solid white;
padding: 6px 24px;
position: relative;
}
.button::before {
position: absolute;
content: "";
background: #e1e1e1;
transition-duration: 0.2s;
z-index: -1;
inset: 0px auto auto 0px;
width: 0px;
height: 100%;
opacity: 1;
}
.button:hover::before {
width: 100%;
height: 100%;
opacity: 1;
}
.button:hover {
color: #1a1a1a;
background: #e1e1e1;
transition: color 0.3s ease 0s, background 0s ease 0.3s;
}
</style>

View file

@ -1,33 +0,0 @@
<!-- home / discover / welcome page -->
<script lang="ts">
import '$appcss';
import { t } from '$libs/translations';
import ListAction from '@tea/ui/list-action/list-action.svelte';
import type { ListActionItem } from '@tea/ui/types';
import { packagesStore } from '$libs/stores';
let items: ListActionItem[];
packagesStore.subscribe((ps) => {
items = ps
.filter((p) => (p.categories || []).includes('top_packages'))
.map((pkg) => ({
title: pkg.full_name,
sub_title: pkg.version,
action_label: $t("package.install-label").toUpperCase(),
image_url: pkg.thumb_image_url,
detail_url: `/packages/${pkg.slug}`
}));
});
const onSelectPackage = async (item:ListActionItem) => {
console.log(item);
}
</script>
<ListAction
title={$t("package.top-list-title")}
mainCtaTitle={$t("package.view-all-cta").toUpperCase()}
items={items}
onSelectItem={onSelectPackage}
/>

View file

@ -1,51 +0,0 @@
<!-- home / discover / welcome page -->
<script lang="ts">
import '$appcss';
import { t } from '$libs/translations';
import type { ListActionItem } from '@tea/ui/types';
import ListAction from '@tea/ui/list-action/list-action.svelte';
const action_label = $t("script.use-label");
const items: ListActionItem[] = [
{
title: 'Script A',
sub_title: 'v 0.0.1',
image_url: '/images/bored-ape.png',
action_label
},
{
title: 'Script B',
sub_title: 'v 0.1.1',
image_url: '/images/bored-ape.png',
action_label
},
{
title: 'Script C',
sub_title: 'v 2.0.1',
image_url: '/images/bored-ape.png',
action_label
},
{
title: 'Script D',
sub_title: 'v 0.1.1',
image_url: '/images/bored-ape.png',
action_label
},
{
title: 'Script E',
sub_title: 'v 0.1.1',
image_url: '/images/bored-ape.png',
action_label
},
];
</script>
<ListAction
title={$t("script.top-list-title")}
mainCtaTitle={$t("script.view-all-cta").toUpperCase()}
items={items}
onSelectItem={async (script) => {
console.log(script)
}}
/>

View file

@ -5,29 +5,17 @@ import Fuse from "fuse.js";
import {
getPackage,
getDistPackages,
openTerminal,
getInstalledPackages,
installPackage,
getPackageBottles
} from "@native";
import { getReadme, getContributors, getRepoAsPackage } from "$libs/github";
import { notificationStore } from "../stores";
import { NotificationType } from "@tea/ui/types";
import type { Package } from "@tea/ui/types";
import { trackInstall, trackInstallFailed } from "$libs/analytics";
const log = window.require("electron-log");
const installTea = async () => {
log.info("installing tea...");
try {
openTerminal(`sh <(curl https://tea.xyz)`);
} catch (error) {
log.error("install failed", error);
}
};
export default function initPackagesStore() {
let initialized = false;
const syncProgress = writable<number>(0); // TODO: maybe use this in the UI someday
@ -49,8 +37,8 @@ export default function initPackagesStore() {
});
};
const syncPackageData = async (guiPkg: Partial<GUIPackage>) => {
if (guiPkg.synced) return;
const syncPackageData = async (guiPkg: Partial<GUIPackage> | undefined) => {
if (!guiPkg || guiPkg.synced) return;
const pkg = await getPackage(guiPkg.full_name!); // ATM: pkg only bottles and github:string
const readmeMd = `# ${guiPkg.full_name} #
@ -87,16 +75,6 @@ To read more about this package go to [${guiPkg.homepage}](${guiPkg.homepage}).
const isUpToDate = teaPkg.version === installedPkg?.installed_versions[0];
log.info("check if Tea-CLI is up to date:", isUpToDate);
//TODO: Is there where we handle the case of tea not being installed at all?
if (!isUpToDate) {
notificationStore.add({
message: "install cli",
i18n_key: "package.update-tea-cli",
type: NotificationType.ACTION_BANNER,
callback: installTea,
callback_label: "UPDATE"
});
}
};
const init = async function () {
@ -202,7 +180,8 @@ To read more about this package go to [${guiPkg.homepage}](${guiPkg.homepage}).
fetchPackageBottles,
updatePackage,
init,
installPkg
installPkg,
syncPackageData
};
}

View file

@ -3,39 +3,9 @@
"lang": {
"en": "English"
},
"cli": {
"install": "install tea"
},
"store-search-placeholder": "type to search",
"search": "search",
"home": {
"all-packages": "All packages",
"discover-title": "DISCOVER",
"asset-title": "ASSET TYPE",
"tutorials-title": "TUTORIALS",
"os-news-title": "OPEN-SOURCE NEWS",
"resources": "Resources"
},
"package": {
"update-all": "UPDATE ALL",
"top-list-title": "Top packages this week",
"browse-cta": "Browse packages",
"what-title": "What are packages?",
"short-description": "Collections of files aggregated to form larger frameworks & functions. Think Python or Node.js.",
"foundation-essentials-title": "FOUNDATION ESSENTIALS",
"view-all-cta": "View all packages",
"install-label": "install",
"installed-label": "installed",
"installing-label": "installing",
"reinstall-label": "re-install",
"needs-update-label": "update",
"my-installs-title": "my installs",
"check-for-updates": "check for updates",
"details": "details",
"install-tea-label": "Install tea cli",
"update-tea-label": "Update now",
"install-tea-cli": "This app requires our command-line interface",
"update-tea-cli": "An update is available for tea cli",
"cta-AVAILABLE": "INSTALL",
"cta-INSTALLED": "INSTALLED",
"cta-INSTALLING": "INSTALLING",
@ -43,19 +13,6 @@
"cta-NEEDS_UPDATE": "UPDATE",
"cta-UPDATING": "UPDATING"
},
"script": {
"top-list-title": "Top scripts this week",
"view-all-cta": "View all scripts",
"use-label": "use",
"browse-cta": "Browse scripts",
"what-title": "What are scripts?",
"short-description": "Invisible applications that chain packages together in order to perform cool actions on your computer."
},
"post": {
"workshops-title": "workshops to get started",
"article-more-cta": "Read more articles",
"read-more-cta": "read more"
},
"footer": {
"quick-links-title": "quick links",
"about-tea-store": "about the tea store",
@ -79,7 +36,15 @@
"home": "home",
"all": "All",
"articles": "Articles",
"workshops": "Workshops"
"workshops": "Workshops",
"details": "details",
"versions": "versions",
"metadata": "Metadata",
"homepage": "Homepage",
"documentation": "Documentation",
"github-repository": "Github Repository",
"contributors": "Contributors",
"view-on-github": "View on github"
},
"notification": {
"gui-downloading": "A new tea gui({{version}}) is being downloaded. Please don't close the app.",
@ -99,6 +64,7 @@
},
"tags": {
"all": "all",
"installed": "installed",
"updates_available": "Updates available",
"recently_updated": "Recently updated",
"new_packages": "New packages",

View file

@ -1,22 +0,0 @@
<script>
import '$appcss';
import { t } from '$libs/translations';
import PageHeader from '$components/page-header/page-header.svelte';
import CliBanner from '$components/cli-banner/cli-banner.svelte';
import BigBlackSpace from '$components/big-black-space/big-black-space.svelte';
</script>
<div>
<PageHeader>{$t('cli.install')}</PageHeader>
<section>
<CliBanner />
</section>
<section class="mt-8">
<BigBlackSpace />
</section>
</div>

View file

@ -1,10 +1,8 @@
<script>
import '$appcss';
import PageHeader from '$components/page-header/page-header.svelte';
import SearchPackages from '$components/search-packages/search-packages.svelte';
</script>
<div>
<PageHeader>Packages</PageHeader>
<SearchPackages />
</div>

View file

@ -5,7 +5,6 @@
import { page } from '$app/stores';
// import PageHeader from '$components/page-header/page-header.svelte';
import PackageBanner from '$components/package-banner/package-banner.svelte';
import type { Bottle } from '@tea/ui/types';
// import SuggestedPackages from '$components/suggested-packages/suggested-packages.svelte';
import Tabs from '@tea/ui/tabs/tabs.svelte';
import type { Tab } from '@tea/ui/types';
@ -13,57 +12,45 @@
import PackageMetas from '@tea/ui/package-metas/package-metas.svelte';
import Markdown from '@tea/ui/markdown/markdown.svelte';
// import PackageSnippets from '@tea/ui/package-snippets/package-snippets.svelte';
import type { GUIPackage } from '$libs/types';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
/** @type {import('./$types').PageData} */
export let data: { slug:string, content:string, title:string };
import { packagesStore } from '$libs/stores';
import { onMount } from 'svelte';
let pkg: GUIPackage;
const { packages } = packagesStore;
$: pkg = $packages.find((p) => p.slug === data?.slug);
// let reviews: Review[];
let bottles: Bottle[] = [];
let versions: string[] = [];
let readme: string;
$: bottles = pkg?.bottles || [];
$: versions = [...new Set(bottles.map((b) => b.version))];
$: readme = pkg?.readme_md || '';
let tabs: Tab[] = [];
packagesStore.subscribeToPackage(data?.slug, (p) => {
pkg = p;
if (!bottles.length && pkg.bottles) {
const newVersion = pkg.bottles.map((b) => b.version);
versions = [...new Set(newVersion)];
bottles.push(...pkg.bottles);
tabs = [
...tabs,
{
label: `versions (${versions.length || 0})`,
$: tabs = [
readme !== '' && {
label: $t("common.details"),
component: Markdown,
props: { pkg, source: readme }
},
bottles?.length && {
label: `${$t("common.versions")} (${versions.length || 0})`,
component: Bottles,
props: {
bottles
}
}
];
}
].filter((t) => t && t?.label) as unknown as Tab[];
if (!readme && pkg.readme_md) {
readme = pkg.readme_md;
tabs = [
{
label: 'details',
component: Markdown,
props: { pkg, source: readme }
},
...tabs,
];
}
});
const url = $page.url;
const tab = url.searchParams.get("tab");
onMount(() => {
packagesStore.syncPackageData(pkg);
})
</script>
<header class="mx-16 py-5 mb-10 text-gray border border-x-0 border-t-0">
<a class="hover:text-white hover:opacity-80 cursor-default" href="/">{$t("common.home")}</a>
@ -72,7 +59,7 @@
<a class="hover:text-white hover:opacity-80 cursor-default" href={`/?tab=${tab || "all"}`}>{$t(`tags.${tab}`) || "all"}</a>
>
{/if}
<span class="text-white">{pkg.full_name}</span>
<span class="text-white">{pkg?.full_name}</span>
</header>
{#if pkg}
<div class="px-16">
@ -82,7 +69,7 @@
<section class="mt-8 flex gap-8">
<div class="w-2/3">
<Tabs {tabs} />
<Tabs {tabs} defaultTab={$t("common.details")} />
</div>
<div class="w-1/3">
{#if pkg}

View file

@ -1,28 +0,0 @@
<script>
import '$appcss';
import PageHeader from '$components/page-header/page-header.svelte';
import ProfileBanner from '$components/profile-banner/profile-banner.svelte';
import Preflight from '$components/preflight/preflight.svelte';
import Badges from '$components/badges/badges.svelte';
import InstalledPackages from '$components/installed-packages/installed-packages.svelte';
</script>
<div>
<PageHeader>PROFILE</PageHeader>
<section>
<ProfileBanner />
</section>
<section class="mt-8 grid grid-cols-2 gap-8">
<div>
<Preflight />
</div>
<div>
<Badges />
</div>
</section>
<section class="mt-8">
<InstalledPackages />
</section>
</div>

View file

@ -1,5 +1,6 @@
<script lang="ts">
import type { Package } from "../types";
import { t } from "$libs/translations";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { shellOpenExternal } from "@native";
@ -29,7 +30,7 @@
</script>
<section class="bg-black pt-2">
<h1 class="text-primary">Metadata</h1>
<h1 class="text-primary">{$t("common.metadata")}</h1>
<ul class="mb-10 flex flex-col gap-2">
{#if pkg?.bottles}
<li>
@ -47,7 +48,7 @@
</li>
{/if}
</ul>
<h1 class="text-primary">Homepage</h1>
<h1 class="text-primary">{$t("common.homepage")}</h1>
<ul class="mb-10 flex flex-col gap-2">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<li on:click={() => shellOpenExternal(pkg.homepage)}>
@ -55,7 +56,7 @@
</li>
</ul>
{#if pkg.documentation_url}
<h1 class="text-primary">Documentation</h1>
<h1 class="text-primary">{$t("common.documentation")}</h1>
<ul class="mb-10 flex flex-col gap-2">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<li on:click={() => shellOpenExternal(pkg.documentation_url)}>
@ -64,7 +65,7 @@
</ul>
{/if}
{#if pkg.github}
<h1 class="text-primary">Github Repository</h1>
<h1 class="text-primary">{$t("common.github-repository")}</h1>
<ul class="mb-10 flex flex-col gap-2">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<li on:click={() => shellOpenExternal(`https://github.com/${pkg.github}`)}>
@ -73,7 +74,7 @@
</ul>
{/if}
{#if pkg.contributors?.length}
<h1 class="text-primary">Contributors</h1>
<h1 class="text-primary">{$t("common.contributors")}</h1>
<ul class="mb-10 flex flex-col gap-2">
{#each pkg.contributors as contributor}
<!-- svelte-ignore a11y-click-events-have-key-events -->

View file

@ -9,12 +9,19 @@
import Button from "../button/button.svelte";
export let tabs: Tab[] = [];
export let defaultTab: string;
let active: string;
let dirty = false;
afterUpdate(() => {
if (tabs.length && !active) {
if (!defaultTab) {
active = tabs[0].label;
} else if (!dirty) {
active = defaultTab;
}
}
});
</script>
@ -23,8 +30,13 @@
<menu class="flex gap-1">
{#each tabs as tab}
<div class="border border-x-0 border-t-0 border-gray text-white">
<Button onClick={() => (active = tab.label)}>
<span class={tab.label === active ? "text-white" : ""}>{tab.label}</span>
<Button
onClick={() => {
dirty = true;
active = tab.label;
}}
>
<span class:text-white={tab.label === active}>{tab.label}</span>
</Button>
</div>
{/each}