mirror of
https://github.com/LemmyNet/joinlemmy-site.git
synced 2024-11-26 06:11:21 +00:00
Adding most of instances page.
This commit is contained in:
parent
14d463464d
commit
7f92343921
14 changed files with 547 additions and 319 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit b5b5981499854a7e25f128a5c8cc541b258e7e09
|
Subproject commit f96ec38a927aa2477d9a1d21f6a637ed8838b913
|
|
@ -1 +1 @@
|
||||||
Subproject commit de9de2c53bee034d3824ecaa9a2104f8f341332e
|
Subproject commit 18da10858d8c63750beb06247947f25d91944741
|
|
@ -7,6 +7,7 @@ import { NoMatch } from "./no-match";
|
||||||
import { Symbols } from "./symbols";
|
import { Symbols } from "./symbols";
|
||||||
import { Navbar } from "./navbar";
|
import { Navbar } from "./navbar";
|
||||||
import { Footer } from "./footer";
|
import { Footer } from "./footer";
|
||||||
|
import { BACKGROUND_GRADIENT_1, BACKGROUND_GRADIENT_2 } from "./common";
|
||||||
|
|
||||||
export class App extends Component<any, any> {
|
export class App extends Component<any, any> {
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
|
@ -14,8 +15,8 @@ export class App extends Component<any, any> {
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={BACKGROUND_GRADIENT_1}>
|
||||||
<div>
|
<div className={BACKGROUND_GRADIENT_2}>
|
||||||
<Provider i18next={i18n}>
|
<Provider i18next={i18n}>
|
||||||
{/* <Navbar /> */}
|
{/* <Navbar /> */}
|
||||||
<Switch>
|
<Switch>
|
||||||
|
@ -33,7 +34,7 @@ export class App extends Component<any, any> {
|
||||||
<Symbols />
|
<Symbols />
|
||||||
</Provider>
|
</Provider>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Component } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { i18n } from "../i18next";
|
import { i18n } from "../i18next";
|
||||||
import { gradientTextClasses } from "./common";
|
import { TEXT_GRADIENT } from "./common";
|
||||||
import {
|
import {
|
||||||
ANDROID_APPS,
|
ANDROID_APPS,
|
||||||
API_LIBRARIES,
|
API_LIBRARIES,
|
||||||
|
@ -14,10 +14,8 @@ import {
|
||||||
import { Icon } from "./icon";
|
import { Icon } from "./icon";
|
||||||
|
|
||||||
const TitleBlock = () => (
|
const TitleBlock = () => (
|
||||||
<div className="flex flex-col items-center mt-16 mb-8">
|
<div className="flex flex-col items-center pt-16 mb-8">
|
||||||
<p className={`text-4xl ${gradientTextClasses} mb-3`}>
|
<p className={`text-4xl ${TEXT_GRADIENT} mb-3`}>{i18n.t("lemmy_apps")}</p>
|
||||||
{i18n.t("lemmy_apps")}
|
|
||||||
</p>
|
|
||||||
<p className="text-2xl text-gray-300 text-center">
|
<p className="text-2xl text-gray-300 text-center">
|
||||||
{i18n.t("choose_from_apps")}
|
{i18n.t("choose_from_apps")}
|
||||||
</p>
|
</p>
|
||||||
|
@ -34,7 +32,7 @@ const AppDetailsTitle = ({ app }: AppDetailsCardProps) => (
|
||||||
src={app.icon || "/static/assets/images/lemmy.svg"}
|
src={app.icon || "/static/assets/images/lemmy.svg"}
|
||||||
className="rounded-xl w-7 h-7"
|
className="rounded-xl w-7 h-7"
|
||||||
/>
|
/>
|
||||||
<a href={app.link} className={`card-title text-2xl ${gradientTextClasses}`}>
|
<a href={app.link} className={`card-title text-2xl ${TEXT_GRADIENT}`}>
|
||||||
{app.name}
|
{app.name}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,7 +53,7 @@ const AppDetailsButtons = ({ links }: AppDetailsButtonsProps) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
const AppDetailsCard = ({ app }: AppDetailsCardProps) => (
|
const AppDetailsCard = ({ app }: AppDetailsCardProps) => (
|
||||||
<div className="card card-bordered bg-neutral-800 shadow-xl">
|
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||||
<div className="card-body items-center">
|
<div className="card-body items-center">
|
||||||
<AppDetailsTitle app={app} />
|
<AppDetailsTitle app={app} />
|
||||||
<img
|
<img
|
||||||
|
@ -106,14 +104,14 @@ const AppGrid = ({ apps }: AppGridProps) => (
|
||||||
const ApiLibrariesBlock = () => (
|
const ApiLibrariesBlock = () => (
|
||||||
<div>
|
<div>
|
||||||
<AppTitle title={i18n.t("api_libraries")} />
|
<AppTitle title={i18n.t("api_libraries")} />
|
||||||
<div className="card card-bordered bg-neutral-800 shadow-xl md:w-1/2">
|
<div className="card card-bordered bg-neutral-900 shadow-xl md:w-1/2">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<ul>
|
<ul>
|
||||||
{API_LIBRARIES.map(a => (
|
{API_LIBRARIES.map(a => (
|
||||||
<li>
|
<li>
|
||||||
<span className={`${gradientTextClasses} mr-2`}>●</span>
|
<span className={`${TEXT_GRADIENT} mr-2`}>●</span>
|
||||||
<span>
|
<span>
|
||||||
<a href={a.link} className={`${gradientTextClasses}`}>
|
<a href={a.link} className={`${TEXT_GRADIENT}`}>
|
||||||
{a.name}
|
{a.name}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
import { Link } from "inferno-router";
|
import { Link } from "inferno-router";
|
||||||
import { i18n } from "../i18next";
|
import { i18n } from "../i18next";
|
||||||
import { T } from "inferno-i18next";
|
import { T } from "inferno-i18next";
|
||||||
import { Icon } from "./icon";
|
import classNames from "classnames";
|
||||||
|
|
||||||
export const gradientTextClasses =
|
export const TEXT_GRADIENT =
|
||||||
"bg-gradient-to-r bg-clip-text text-transparent from-[#69D066] to-[#03A80E]";
|
"bg-gradient-to-r bg-clip-text text-transparent from-[#69D066] to-[#03A80E]";
|
||||||
|
|
||||||
export const Badge = ({ content }) => (
|
export const BACKGROUND_GRADIENT_1 =
|
||||||
<div className="p-2 rounded-xl bg-neutral-800 text-gray-300 w-fit">
|
"min-h-full bg-gradient-to-r from-transparent via-[#12D10E]/[.15] to-transparent";
|
||||||
|
|
||||||
|
export const BACKGROUND_GRADIENT_2 =
|
||||||
|
"min-h-full bg-gradient-to-b from-transparent to-black/[.30] to-20%";
|
||||||
|
|
||||||
|
export const Badge = ({ content, outline = false }) => (
|
||||||
|
<div
|
||||||
|
className={classNames("p-2 rounded-xl bg-neutral-800 text-gray-300 w-fit", {
|
||||||
|
"outline outline-primary": outline,
|
||||||
|
})}
|
||||||
|
>
|
||||||
{content}
|
{content}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -16,7 +26,7 @@ export const DonateDesc = () => (
|
||||||
<p className="text-sm text-gray-300 mb-6">
|
<p className="text-sm text-gray-300 mb-6">
|
||||||
<T i18nKey="donate_desc">
|
<T i18nKey="donate_desc">
|
||||||
#
|
#
|
||||||
<Link className="link" to="/donate">
|
<Link className="link link-primary" to="/donate">
|
||||||
#
|
#
|
||||||
</Link>
|
</Link>
|
||||||
#
|
#
|
||||||
|
@ -25,18 +35,21 @@ export const DonateDesc = () => (
|
||||||
);
|
);
|
||||||
|
|
||||||
export const DonateButtons = () => (
|
export const DonateButtons = () => (
|
||||||
<div class="flex flex-row justify-between gap-2">
|
<div class="flex flex-row flex-wrap justify-between gap-2">
|
||||||
<a class="btn btn-primary text-white" href="https://liberapay.com/Lemmy">
|
<a
|
||||||
|
class="btn btn-primary text-white sm:max-md:btn-block"
|
||||||
|
href="https://liberapay.com/Lemmy"
|
||||||
|
>
|
||||||
{i18n.t("support_on_liberapay")}
|
{i18n.t("support_on_liberapay")}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="btn btn-secondary text-white"
|
class="btn btn-secondary text-white sm:max-md:btn-block"
|
||||||
href="https://www.patreon.com/dessalines"
|
href="https://www.patreon.com/dessalines"
|
||||||
>
|
>
|
||||||
{i18n.t("support_on_patreon")}
|
{i18n.t("support_on_patreon")}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="btn btn-primary text-white"
|
class="btn btn-primary text-white sm:max-md:btn-block"
|
||||||
href="https://opencollective.com/lemmy"
|
href="https://opencollective.com/lemmy"
|
||||||
>
|
>
|
||||||
{i18n.t("support_on_opencollective")}
|
{i18n.t("support_on_opencollective")}
|
||||||
|
@ -45,10 +58,10 @@ export const DonateButtons = () => (
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SupportDonateBlock = () => (
|
export const SupportDonateBlock = () => (
|
||||||
<div className="flex flex-col items-center mt-16">
|
<div className="flex flex-col items-center pt-16">
|
||||||
<div className="card card-bordered bg-neutral-800 shadow-xl">
|
<div className="card card-bordered bg-neutral-800 shadow-xl">
|
||||||
<div className="card-body px-32 py-16">
|
<div className="card-body px-32 py-16">
|
||||||
<p class={`card-title text-4xl mb-3 ${gradientTextClasses}`}>
|
<p class={`card-title text-4xl mb-3 ${TEXT_GRADIENT}`}>
|
||||||
{i18n.t("support_donate")}
|
{i18n.t("support_donate")}
|
||||||
</p>
|
</p>
|
||||||
<DonateDesc />
|
<DonateDesc />
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { Component } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { i18n } from "../i18next";
|
import { i18n } from "../i18next";
|
||||||
import { gradientTextClasses } from "./common";
|
import { TEXT_GRADIENT } from "./common";
|
||||||
import { Icon } from "./icon";
|
import { Icon } from "./icon";
|
||||||
|
|
||||||
const TitleBlock = () => (
|
const TitleBlock = () => (
|
||||||
<div className={`mt-16 text-center text-4xl mb-8 ${gradientTextClasses}`}>
|
<div className={`pt-16 text-center text-4xl mb-8 ${TEXT_GRADIENT}`}>
|
||||||
{i18n.t("contact")}
|
{i18n.t("contact")}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -13,7 +13,7 @@ const TitleBlock = () => (
|
||||||
const ContactBlock = () => (
|
const ContactBlock = () => (
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<div className="card w-96 card-bordered bg-neutral-900 shadow-xl">
|
<div className="card w-96 card-bordered bg-neutral-900 shadow-xl">
|
||||||
<div className="card-body items-center p-16">
|
<div className="card-body items-center p-8">
|
||||||
<ContactBtn
|
<ContactBtn
|
||||||
title="/c/lemmy_support"
|
title="/c/lemmy_support"
|
||||||
url="https://lemmy.ml/c/lemmy_support"
|
url="https://lemmy.ml/c/lemmy_support"
|
||||||
|
|
93
src/shared/components/donate-definitions.ts
Normal file
93
src/shared/components/donate-definitions.ts
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
export interface LinkedSponsor {
|
||||||
|
name: string;
|
||||||
|
link: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GoldSponsor {
|
||||||
|
name: string;
|
||||||
|
link: string;
|
||||||
|
avatar: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GOLD_SPONSORS: GoldSponsor[] = [];
|
||||||
|
|
||||||
|
export const LATINUM_SPONSORS: GoldSponsor[] = [
|
||||||
|
{
|
||||||
|
name: "NLnet",
|
||||||
|
link: "https://nlnet.nl",
|
||||||
|
avatar: "https://nlnet.nl/image/logo_nlnet.svg",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const SILVER_SPONSORS: LinkedSponsor[] = [];
|
||||||
|
|
||||||
|
export const HIGHLIGHTED_SPONSORS = ["DQW", "John Knapp"];
|
||||||
|
export const GENERAL_SPONSORS = [
|
||||||
|
"Anthony",
|
||||||
|
"Remi Rampin",
|
||||||
|
"Cameron C",
|
||||||
|
"Vegard",
|
||||||
|
"0ti.me",
|
||||||
|
"Brendan",
|
||||||
|
"mexicanhalloween .",
|
||||||
|
"Arthur Nieuwland",
|
||||||
|
"Forrest Weghorst",
|
||||||
|
"Luke Black",
|
||||||
|
"Brandon Abbott",
|
||||||
|
"Eon Gattignolo",
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface Coder {
|
||||||
|
name: string;
|
||||||
|
link?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CODERS: Coder[] = [
|
||||||
|
{ name: "dessalines", link: "https://mastodon.social/@dessalines" },
|
||||||
|
{ name: "Nutomic", link: "https://lemmy.ml/u/nutomic" },
|
||||||
|
{ name: "asonix", link: "https://github.com/asonix" },
|
||||||
|
{ name: "krawieck", link: "https://github.com/krawieck" },
|
||||||
|
{ name: "shilangyu", link: "https://github.com/shilangyu" },
|
||||||
|
{ name: "uuttff8", link: "https://github.com/uuttff8" },
|
||||||
|
{ name: "eiknat", link: "https://github.com/eiknat" },
|
||||||
|
{ name: "ernestwisniewski", link: "https://github.com/ernestwisniewski" },
|
||||||
|
{ name: "zacanger", link: "https://github.com/zacanger" },
|
||||||
|
{ name: "iav", link: "https://github.com/iav" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface Translation {
|
||||||
|
lang: string;
|
||||||
|
country?: string;
|
||||||
|
translators: Translator[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Translator {
|
||||||
|
name: string;
|
||||||
|
link?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Crypto {
|
||||||
|
name: string;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CRYPTOS: Crypto[] = [
|
||||||
|
{
|
||||||
|
name: "bitcoin",
|
||||||
|
address: "1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ethereum",
|
||||||
|
address: "0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "monero",
|
||||||
|
address:
|
||||||
|
"41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cardano",
|
||||||
|
address:
|
||||||
|
"addr1q858t89l2ym6xmrugjs0af9cslfwvnvsh2xxp6x4dcez7pf5tushkp4wl7zxfhm2djp6gq60dk4cmc7seaza5p3slx0sakjutm",
|
||||||
|
},
|
||||||
|
];
|
|
@ -5,29 +5,26 @@ import { T } from "inferno-i18next";
|
||||||
import { translators } from "../translations/translators";
|
import { translators } from "../translations/translators";
|
||||||
import { languagesAll, countries } from "countries-list";
|
import { languagesAll, countries } from "countries-list";
|
||||||
import { isBrowser } from "../utils";
|
import { isBrowser } from "../utils";
|
||||||
import { Badge, SupportDonateBlock, gradientTextClasses } from "./common";
|
import { Badge, SupportDonateBlock, TEXT_GRADIENT } from "./common";
|
||||||
import {
|
import {
|
||||||
CODERS,
|
CODERS,
|
||||||
GOLD_SPONSORS,
|
GOLD_SPONSORS,
|
||||||
|
GoldSponsor,
|
||||||
HIGHLIGHTED_SPONSORS,
|
HIGHLIGHTED_SPONSORS,
|
||||||
LATINUM_SPONSORS,
|
LATINUM_SPONSORS,
|
||||||
SILVER_SPONSORS,
|
GENERAL_SPONSORS,
|
||||||
SPONSORS,
|
|
||||||
Translation,
|
Translation,
|
||||||
|
CRYPTOS,
|
||||||
} from "./donate-definitions";
|
} from "./donate-definitions";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Icon } from "./icon";
|
import { Icon } from "./icon";
|
||||||
|
|
||||||
const avatarSize = 40;
|
|
||||||
const bannerWidth = 240;
|
|
||||||
const bannerHeight = 101;
|
|
||||||
|
|
||||||
const SectionTitle = ({ title }) => (
|
const SectionTitle = ({ title }) => (
|
||||||
<div className="text-2xl mb-3">{title}</div>
|
<div className="text-2xl mb-3">{title}</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const ContributorsBlock = () => (
|
const ContributorsBlock = () => (
|
||||||
<div>
|
<div className="my-16">
|
||||||
<SectionTitle title={i18n.t("contributers")} />
|
<SectionTitle title={i18n.t("contributers")} />
|
||||||
<p class="text-sm text-gray-300 mb-3">{i18n.t("thanks_coders")}</p>
|
<p class="text-sm text-gray-300 mb-3">{i18n.t("thanks_coders")}</p>
|
||||||
<CodersBlock />
|
<CodersBlock />
|
||||||
|
@ -35,6 +32,21 @@ const ContributorsBlock = () => (
|
||||||
{i18n.t("thanks_translators")}
|
{i18n.t("thanks_translators")}
|
||||||
</p>
|
</p>
|
||||||
<TranslatorsBlock />
|
<TranslatorsBlock />
|
||||||
|
<div className="card card-bordered bg-neutral-900 shadow-xl text-center text-secondary">
|
||||||
|
<div className="card-body p-4">
|
||||||
|
<p>
|
||||||
|
<T i18nKey="add_weblate">
|
||||||
|
#
|
||||||
|
<a
|
||||||
|
className="link link-primary"
|
||||||
|
href="https://weblate.join-lemmy.org/projects/lemmy/"
|
||||||
|
>
|
||||||
|
#
|
||||||
|
</a>
|
||||||
|
</T>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -46,11 +58,36 @@ const CodersBlock = () => (
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const TranslatorsBlock = () => (
|
const TranslatorsBlock = () => {
|
||||||
|
// Split these into two cards for md
|
||||||
|
const transArr = convertTranslators();
|
||||||
|
const halfway = Math.floor(transArr.length / 2);
|
||||||
|
|
||||||
|
const first = transArr.slice(0, halfway);
|
||||||
|
const second = transArr.slice(halfway, transArr.length);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-8">
|
||||||
|
<div className="md:hidden">
|
||||||
|
<TranslatorsCard translations={transArr} />
|
||||||
|
</div>
|
||||||
|
<div className="sm:max-md:hidden grid grid-cols-2 gap-4">
|
||||||
|
<TranslatorsCard translations={first} />
|
||||||
|
<TranslatorsCard translations={second} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface TranslatorsCardProps {
|
||||||
|
translations: Translation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const TranslatorsCard = ({ translations }: TranslatorsCardProps) => (
|
||||||
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||||
<div className="card-body p-4">
|
<div className="card-body p-4">
|
||||||
<table>
|
<table>
|
||||||
{convertTranslators().map(t => (
|
{translations.map(t => (
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<div className="text-secondary">
|
<div className="text-secondary">
|
||||||
|
@ -69,11 +106,96 @@ const TranslatorsBlock = () => (
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const SponsorsBlock = () => (
|
||||||
|
<div className="mb-16">
|
||||||
|
<SectionTitle title={i18n.t("sponsors")} />
|
||||||
|
<GoldSponsorCards
|
||||||
|
title={i18n.t("gold_pressed_latinum_sponsors_desc")}
|
||||||
|
sponsors={LATINUM_SPONSORS}
|
||||||
|
/>
|
||||||
|
<GoldSponsorCards
|
||||||
|
title={i18n.t("gold_sponsors_desc")}
|
||||||
|
sponsors={GOLD_SPONSORS}
|
||||||
|
/>
|
||||||
|
<GeneralSponsorCard />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
interface GoldSponsorCardsProps {
|
||||||
|
title: string;
|
||||||
|
sponsors: GoldSponsor[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const GoldSponsorCards = ({ title, sponsors }: GoldSponsorCardsProps) =>
|
||||||
|
sponsors.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-300 mb-3">{title}</p>
|
||||||
|
<div class="flex flex-row flex-wrap gap-2 mb-2">
|
||||||
|
{sponsors.map(s => (
|
||||||
|
<a class="btn btn-primary btn-outline w-32 h-16" href={s.link}>
|
||||||
|
<img src={s.avatar} />
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const GeneralSponsorCard = () => {
|
||||||
|
const highlighted: PersonBadgeData[] = HIGHLIGHTED_SPONSORS.map(name => {
|
||||||
|
return { name, primaryOutline: true, primaryAt: true };
|
||||||
|
});
|
||||||
|
|
||||||
|
const general: PersonBadgeData[] = GENERAL_SPONSORS.map(name => {
|
||||||
|
return { name, primaryAt: true };
|
||||||
|
});
|
||||||
|
|
||||||
|
const combined = highlighted.concat(general);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-300 mt-6 mb-3">
|
||||||
|
{i18n.t("general_sponsors_desc")}
|
||||||
|
</p>
|
||||||
|
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||||
|
<div className="card-body p-4">
|
||||||
|
<PersonBadges persons={combined} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CryptoBlock = () => (
|
||||||
|
<div className="pb-16">
|
||||||
|
<SectionTitle title={"Crypto"} />
|
||||||
|
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||||
|
<div className="card-body p-4">
|
||||||
|
<table className="table table-sm">
|
||||||
|
{CRYPTOS.map(c => (
|
||||||
|
<tr>
|
||||||
|
<td className="text-sm text-gray-300">{c.name}</td>
|
||||||
|
<td>
|
||||||
|
<Badge
|
||||||
|
content={
|
||||||
|
<code className="text-sm text-secondary break-all">
|
||||||
|
{c.address}
|
||||||
|
</code>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
interface PersonBadgeData {
|
interface PersonBadgeData {
|
||||||
name: string;
|
name: string;
|
||||||
link?: string;
|
link?: string;
|
||||||
greenOutline?: boolean;
|
primaryOutline?: boolean;
|
||||||
greenAt?: boolean;
|
primaryAt?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PersonBadgeProps {
|
interface PersonBadgeProps {
|
||||||
|
@ -96,18 +218,19 @@ const PersonBadgeInternal = ({ person }: PersonBadgeProps) => (
|
||||||
<Icon
|
<Icon
|
||||||
icon="at-sign"
|
icon="at-sign"
|
||||||
classes={classNames("fill-current text-gray-600", {
|
classes={classNames("fill-current text-gray-600", {
|
||||||
"text-primary": person.greenAt,
|
"text-primary": person.primaryAt,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={classNames("ml-1", {
|
className={classNames("ml-1", {
|
||||||
[`${gradientTextClasses}`]: person.link,
|
[`${TEXT_GRADIENT}`]: person.link,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{person.name}
|
{person.name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
outline={person.primaryOutline}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -142,181 +265,9 @@ export class Donate extends Component<any, any> {
|
||||||
<meta property={"title"} content={title} />
|
<meta property={"title"} content={title} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<SupportDonateBlock />
|
<SupportDonateBlock />
|
||||||
<div className="mb-16" />
|
|
||||||
<ContributorsBlock />
|
<ContributorsBlock />
|
||||||
|
<SponsorsBlock />
|
||||||
<div class="container">
|
<CryptoBlock />
|
||||||
<div class="text-center">
|
|
||||||
<h1>{i18n.t("support_lemmy")}</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
<div class="text-center">
|
|
||||||
<h2>{i18n.t("contributers")}</h2>
|
|
||||||
{this.codersLine()}
|
|
||||||
{this.translatorsLine()}
|
|
||||||
</div>
|
|
||||||
<div class="text-center">
|
|
||||||
<h2>{i18n.t("sponsors")}</h2>
|
|
||||||
{LATINUM_SPONSORS.length > 0 && (
|
|
||||||
<div>
|
|
||||||
<p>{i18n.t("gold_pressed_latinum_sponsors_desc")}</p>
|
|
||||||
<div class="row is-horizontal-align">
|
|
||||||
{LATINUM_SPONSORS.map(s => (
|
|
||||||
<div class="col-6">
|
|
||||||
<a class="button outline" href={s.link}>
|
|
||||||
<img
|
|
||||||
src={s.avatar}
|
|
||||||
width={bannerWidth}
|
|
||||||
height={bannerHeight}
|
|
||||||
/>
|
|
||||||
<div>{s.name}</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{GOLD_SPONSORS.length > 0 && (
|
|
||||||
<div>
|
|
||||||
<p>{i18n.t("gold_sponsors_desc")}</p>
|
|
||||||
<div class="row is-horizontal-align">
|
|
||||||
{GOLD_SPONSORS.map(s => (
|
|
||||||
<div class="col">
|
|
||||||
<a class="button outline gold" href={s.link}>
|
|
||||||
<img
|
|
||||||
class="is-rounded"
|
|
||||||
src={s.avatar}
|
|
||||||
width={avatarSize}
|
|
||||||
height={avatarSize}
|
|
||||||
/>
|
|
||||||
<div>{s.name}</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{SILVER_SPONSORS.length > 0 && (
|
|
||||||
<div>
|
|
||||||
<p>{i18n.t("silver_sponsors_desc")}</p>
|
|
||||||
<div class="row is-horizontal-align">
|
|
||||||
{SILVER_SPONSORS.map(s => (
|
|
||||||
<div class="col">
|
|
||||||
<a class="button outline primary" href={s.link}>
|
|
||||||
💎 {s.name}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<p>{i18n.t("general_sponsors_desc")}</p>
|
|
||||||
<div class="row is-horizontal-align">
|
|
||||||
{HIGHLIGHTED_SPONSORS.map(s => (
|
|
||||||
<div class="col">
|
|
||||||
<div class="button outline primary">{s}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{SPONSORS.map(s => (
|
|
||||||
<div class="col">
|
|
||||||
<div class="button outline">{s}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-center">
|
|
||||||
<h1>Crypto</h1>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>bitcoin</td>
|
|
||||||
<td>
|
|
||||||
<code>1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK</code>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>ethereum</td>
|
|
||||||
<td>
|
|
||||||
<code>0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01</code>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>monero</td>
|
|
||||||
<td>
|
|
||||||
<code>
|
|
||||||
41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV
|
|
||||||
</code>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>cardano</td>
|
|
||||||
<td>
|
|
||||||
<code>
|
|
||||||
addr1q858t89l2ym6xmrugjs0af9cslfwvnvsh2xxp6x4dcez7pf5tushkp4wl7zxfhm2djp6gq60dk4cmc7seaza5p3slx0sakjutm
|
|
||||||
</code>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
translatorsLine() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<span>{i18n.t("thanks_translators")}</span>
|
|
||||||
{convertTranslators().map(t => (
|
|
||||||
<span>
|
|
||||||
<span class="text-error">{languagesAll[t.lang].native}</span>
|
|
||||||
{t.country && (
|
|
||||||
<span class="text-error"> {countries[t.country].native}</span>
|
|
||||||
)}
|
|
||||||
<span>: </span>
|
|
||||||
{t.translators.map((translator, i) => (
|
|
||||||
<span>
|
|
||||||
{translator.link ? (
|
|
||||||
<a href={translator.link}>{translator.name}</a>
|
|
||||||
) : (
|
|
||||||
<span>{translator.name}</span>
|
|
||||||
)}
|
|
||||||
<span>{i != t.translators.length - 1 ? ", " : " "}</span>
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<T i18nKey="add_weblate">
|
|
||||||
#<a href="https://weblate.join-lemmy.org/projects/lemmy/">#</a>
|
|
||||||
</T>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
codersLine() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<span>{i18n.t("thanks_coders")}</span>
|
|
||||||
{CODERS.map((coder, i) => (
|
|
||||||
<span>
|
|
||||||
{coder.link ? (
|
|
||||||
<a href={coder.link}>{coder.name}</a>
|
|
||||||
) : (
|
|
||||||
<span>{coder.name}</span>
|
|
||||||
)}
|
|
||||||
<span>{i != CODERS.length - 1 ? ", " : " "}</span>
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
31
src/shared/components/instances-definitions.ts
Normal file
31
src/shared/components/instances-definitions.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
export interface InstanceHelper {
|
||||||
|
name: string;
|
||||||
|
link: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const INSTANCE_HELPERS: InstanceHelper[] = [
|
||||||
|
{
|
||||||
|
name: "Lemmy Community Explorer",
|
||||||
|
link: "https://lemmyverse.net/communities",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lemmy.fediverse.observer",
|
||||||
|
link: "https://lemmy.fediverse.observer/list",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Awesome-Lemmy-Instances on GitHub",
|
||||||
|
link: "https://github.com/maltfield/awesome-lemmy-instances",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "The-Federation.info Lemmy Instances Page",
|
||||||
|
link: "https://the-federation.info/platform/73",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Feddit's Lemmymap",
|
||||||
|
link: "https://lemmymap.feddit.de/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Feddit's Lemmy Community Browser",
|
||||||
|
link: "https://browse.feddit.de/",
|
||||||
|
},
|
||||||
|
];
|
|
@ -3,60 +3,209 @@ import { Helmet } from "inferno-helmet";
|
||||||
import { i18n } from "../i18next";
|
import { i18n } from "../i18next";
|
||||||
import { instance_stats } from "../instance_stats";
|
import { instance_stats } from "../instance_stats";
|
||||||
import { numToSI } from "../utils";
|
import { numToSI } from "../utils";
|
||||||
|
import { Badge, TEXT_GRADIENT } from "./common";
|
||||||
|
import { INSTANCE_HELPERS } from "./instances-definitions";
|
||||||
|
import { Icon } from "./icon";
|
||||||
|
|
||||||
export class Instances extends Component<any, any> {
|
const TitleBlock = () => (
|
||||||
constructor(props: any, context: any) {
|
<div className="flex flex-col items-center pt-16 mb-16">
|
||||||
super(props, context);
|
<p className={`text-4xl ${TEXT_GRADIENT} mb-3`}>
|
||||||
|
{i18n.t("lemmy_servers")}
|
||||||
|
</p>
|
||||||
|
<p className="text-xl text-gray-300 text-center max-w-xl">
|
||||||
|
{i18n.t("instance_totals", {
|
||||||
|
instances: numToSI(instance_stats.stats.crawled_instances),
|
||||||
|
users: numToSI(instance_stats.stats.users_active_month),
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ComparisonBlock = () => (
|
||||||
|
<div>
|
||||||
|
<div className="text-md text-gray-300 mb-3">
|
||||||
|
{i18n.t("instance_comparison")}:
|
||||||
|
</div>
|
||||||
|
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||||
|
<div className="card-body p-4">
|
||||||
|
<div className="flex flex-row flex-wrap gap-4 mb-2">
|
||||||
|
{INSTANCE_HELPERS.map(i => (
|
||||||
|
<Badge
|
||||||
|
content={
|
||||||
|
<a href={i.link}>
|
||||||
|
<Icon
|
||||||
|
icon="embed"
|
||||||
|
classes={`fill-current text-primary mr-2`}
|
||||||
|
/>
|
||||||
|
<span className="text-gray-300">{i.name}</span>
|
||||||
|
</a>
|
||||||
}
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
biasedRandom(active_users, avg, max) {
|
const SectionTitle = ({ title }) => (
|
||||||
|
<div className="text-2xl mb-3">{title}</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
interface InstanceCardGridProps {
|
||||||
|
title: string;
|
||||||
|
instances: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const InstanceCardGrid = ({ title, instances }: InstanceCardGridProps) => (
|
||||||
|
<div className="my-16">
|
||||||
|
<SectionTitle title={title} />
|
||||||
|
<div className="grid md:grid-cols-3 grid-cols-1 gap-4">
|
||||||
|
{instances.map(i => (
|
||||||
|
<InstanceCard instance={i} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
interface InstanceCardProps {
|
||||||
|
instance: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InstanceCard = ({ instance }: InstanceCardProps) => {
|
||||||
|
const domain = instance.domain;
|
||||||
|
const description = instance.site_info.site_view.site.description;
|
||||||
|
const icon =
|
||||||
|
instance.site_info.site_view.site.icon || "/static/assets/images/lemmy.svg";
|
||||||
|
|
||||||
|
const users = instance.site_info.site_view.counts.users;
|
||||||
|
const comments = instance.site_info.site_view.counts.comments;
|
||||||
|
const monthlyUsers = instance.site_info.site_view.counts.users_active_month;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||||
|
<div className="card-body p-4">
|
||||||
|
<div className="flex flex-row flex-wrap gap-4">
|
||||||
|
<InstanceIcon icon={icon} />
|
||||||
|
<InstanceStats
|
||||||
|
users={users}
|
||||||
|
comments={comments}
|
||||||
|
monthlyUsers={monthlyUsers}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={`text-2xl font-bold ${TEXT_GRADIENT}`}>{domain}</div>
|
||||||
|
<p className="text-sm text-gray-300 mb-2">{description}</p>
|
||||||
|
<div class="flex flex-row flex-wrap justify-between gap-2">
|
||||||
|
<a
|
||||||
|
class="btn btn-primary text-white sm:max-md:btn-block bg-gradient-to-r from-[#69D066] to-[#03A80E]"
|
||||||
|
href="https://liberapay.com/Lemmy"
|
||||||
|
>
|
||||||
|
{i18n.t("join_a_server")}
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="btn btn-secondary btn-outline text-white sm:max-md:btn-block"
|
||||||
|
href="https://www.patreon.com/dessalines"
|
||||||
|
>
|
||||||
|
{/* TODO add more information */}
|
||||||
|
{i18n.t("more_features")}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const InstanceIcon = ({ icon }) => (
|
||||||
|
<div className="rounded-xl bg-neutral-800 p-4">
|
||||||
|
<img className="w-24 h-24" src={icon} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const InstanceStats = ({ users, comments, monthlyUsers }) => (
|
||||||
|
<div className="flex flex-col flex-wrap justify-between">
|
||||||
|
<Badge
|
||||||
|
content={
|
||||||
|
<div className="text-sm text-gray-500">
|
||||||
|
<Icon icon="users" classes="mr-2" />
|
||||||
|
<span>{users.toLocaleString()}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Badge
|
||||||
|
content={
|
||||||
|
<div className="text-sm text-gray-500">
|
||||||
|
<Icon icon="message-circle" classes="mr-2" />
|
||||||
|
<span>{comments.toLocaleString()}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Badge
|
||||||
|
content={
|
||||||
|
<div className="text-sm text-gray-500">
|
||||||
|
<Icon icon="user-check" classes="mr-2" />
|
||||||
|
<span>
|
||||||
|
{i18n.t("users_active_per_month", {
|
||||||
|
formattedCount: monthlyUsers.toLocaleString(),
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
function biasedRandom(activeUsers: number, avg: number, max: number): number {
|
||||||
// Lets introduce a better bias to random shuffle instances list
|
// Lets introduce a better bias to random shuffle instances list
|
||||||
var influence = 1.25;
|
const influence = 1.25;
|
||||||
var rnd = Math.random() * (max / influence) + active_users;
|
const rnd = Math.random() * (max / influence) + activeUsers;
|
||||||
var mix = Math.random() * influence;
|
const mix = Math.random() * influence;
|
||||||
return rnd * (1 - mix) + avg * mix;
|
return rnd * (1 - mix) + avg * mix;
|
||||||
}
|
}
|
||||||
|
|
||||||
averageFunc(values: any) {
|
function average(arr: number[]): number {
|
||||||
return values.reduce((a, b) => a + b) / values.length;
|
return arr.reduce((a, b) => a + b, 0) / arr.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
interface InstanceList {
|
||||||
const title = i18n.t("join_title");
|
recommended: any[];
|
||||||
|
popular: any[];
|
||||||
|
}
|
||||||
|
|
||||||
var recommended_instances = instance_stats.recommended[i18n.language];
|
function buildInstanceList(): InstanceList {
|
||||||
if (!recommended_instances) {
|
const recommendedList =
|
||||||
recommended_instances = instance_stats.recommended["en"];
|
instance_stats.recommended[i18n.language] ??
|
||||||
}
|
instance_stats.recommended["en"];
|
||||||
|
|
||||||
var recommended = [];
|
let recommended = [];
|
||||||
var remaining = [];
|
let popular = [];
|
||||||
var values = [];
|
let usersActiveMonth = [];
|
||||||
|
|
||||||
for (var i of instance_stats.stats.instance_details) {
|
// Loop over all the instances, and add them to the two lists
|
||||||
if (recommended_instances.indexOf(i.domain) > -1) {
|
for (const i of instance_stats.stats.instance_details) {
|
||||||
|
if (recommendedList.indexOf(i.domain) > -1) {
|
||||||
recommended.push(i);
|
recommended.push(i);
|
||||||
} else {
|
} else {
|
||||||
remaining.push(i);
|
popular.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
values.push(i.site_info.site_view.counts.users_active_month);
|
usersActiveMonth.push(i.site_info.site_view.counts.users_active_month);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use these values for the shuffle
|
// Use these values for the shuffle
|
||||||
const avgMonthlyUsers = this.averageFunc(values);
|
const avgMonthlyUsers = average(usersActiveMonth);
|
||||||
const maxMonthlyUsers = Math.max(...values);
|
const maxMonthlyUsers = Math.max(...usersActiveMonth);
|
||||||
|
|
||||||
let recommended2 = recommended
|
// Randomize the recommended
|
||||||
|
recommended = recommended
|
||||||
.map(value => ({ value, sort: Math.random() }))
|
.map(value => ({ value, sort: Math.random() }))
|
||||||
.sort((a, b) => a.sort - b.sort)
|
.sort((a, b) => a.sort - b.sort)
|
||||||
.map(({ value }) => value);
|
.map(({ value }) => value);
|
||||||
|
|
||||||
// BIASED sorting for instances, based on the min/max of users_active_month
|
// BIASED sorting for instances, based on the min/max of users_active_month
|
||||||
let remaining2 = remaining
|
popular = popular
|
||||||
.map(i => ({
|
.map(i => ({
|
||||||
instance: i,
|
instance: i,
|
||||||
sort: this.biasedRandom(
|
sort: biasedRandom(
|
||||||
i.site_info.site_view.counts.users_active_month,
|
i.site_info.site_view.counts.users_active_month,
|
||||||
avgMonthlyUsers,
|
avgMonthlyUsers,
|
||||||
maxMonthlyUsers,
|
maxMonthlyUsers,
|
||||||
|
@ -65,54 +214,37 @@ export class Instances extends Component<any, any> {
|
||||||
.sort((a, b) => b.sort - a.sort)
|
.sort((a, b) => b.sort - a.sort)
|
||||||
.map(({ instance }) => instance);
|
.map(({ instance }) => instance);
|
||||||
|
|
||||||
|
return { recommended, popular };
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Instances extends Component<any, any> {
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const title = i18n.t("join_title");
|
||||||
|
const instances = buildInstanceList();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="container">
|
<div className="container mx-auto">
|
||||||
<Helmet title={title}>
|
<Helmet title={title}>
|
||||||
<meta property={"title"} content={title} />
|
<meta property={"title"} content={title} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<h1 class="is-marginless">{i18n.t("lemmy_servers")}</h1>
|
<TitleBlock />
|
||||||
{this.header()}
|
<ComparisonBlock />
|
||||||
<br />
|
<InstanceCardGrid
|
||||||
<br />
|
title={i18n.t("recommended_instances")}
|
||||||
{this.renderList(i18n.t("recommended_instances"), recommended2)}
|
instances={instances.recommended}
|
||||||
{this.renderList(i18n.t("popular_instances"), remaining2)}
|
/>
|
||||||
|
<InstanceCardGrid
|
||||||
|
title={i18n.t("popular_instances")}
|
||||||
|
instances={instances.popular}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
header() {
|
|
||||||
return (
|
|
||||||
<i>
|
|
||||||
{i18n.t("instance_totals", {
|
|
||||||
instances: numToSI(instance_stats.stats.crawled_instances),
|
|
||||||
users: numToSI(instance_stats.stats.users_active_month),
|
|
||||||
})}
|
|
||||||
<p>
|
|
||||||
{i18n.t("instance_comparison")}:
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/maltfield/awesome-lemmy-instances">
|
|
||||||
Awesome-Lemmy-Instances on GitHub
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://the-federation.info/platform/73">
|
|
||||||
the-federation.info Lemmy Instances Page
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://lemmymap.feddit.de/">Feddit's Lemmymap</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{i18n.t("instance_browser")}{" "}
|
|
||||||
<a href="https://browse.feddit.de/">
|
|
||||||
Feddit's Lemmy Community Browser
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</i>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderList(header: string, instances: any[]) {
|
renderList(header: string, instances: any[]) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -5,12 +5,12 @@ import { i18n } from "../i18next";
|
||||||
import { T } from "inferno-i18next";
|
import { T } from "inferno-i18next";
|
||||||
import { isBrowser } from "../utils";
|
import { isBrowser } from "../utils";
|
||||||
import { Icon } from "./icon";
|
import { Icon } from "./icon";
|
||||||
import { SupportDonateBlock, gradientTextClasses } from "./common";
|
import { SupportDonateBlock, TEXT_GRADIENT } from "./common";
|
||||||
|
|
||||||
const TitleBlock = () => (
|
const TitleBlock = () => (
|
||||||
<div className="flex flex-col items-center">
|
<div className="pt-16 flex flex-col items-center">
|
||||||
<div className="flex flex-col items-center mb-2">
|
<div className="flex flex-col items-center mb-2">
|
||||||
<p className={`text-6xl font-bold ${gradientTextClasses}`}>Lemmy</p>
|
<p className={`text-6xl font-bold ${TEXT_GRADIENT}`}>Lemmy</p>
|
||||||
<p className="text-3xl font-medium text-center">{i18n.t("lemmy_desc")}</p>
|
<p className="text-3xl font-medium text-center">{i18n.t("lemmy_desc")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row justify-around gap-2">
|
<div className="flex flex-row justify-around gap-2">
|
||||||
|
@ -178,7 +178,7 @@ const DiscussionPlatformBlock = () => (
|
||||||
// TODO add all of these ones
|
// TODO add all of these ones
|
||||||
const MoreFeaturesBlock = () => (
|
const MoreFeaturesBlock = () => (
|
||||||
<div className="mt-16">
|
<div className="mt-16">
|
||||||
<div className={`text-center text-4xl mb-8 ${gradientTextClasses}`}>
|
<div className={`text-center text-4xl mb-8 ${TEXT_GRADIENT}`}>
|
||||||
{i18n.t("more_features")}
|
{i18n.t("more_features")}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid md:grid-cols-5 grid-cols-1 gap-4">
|
<div className="grid md:grid-cols-5 grid-cols-1 gap-4">
|
||||||
|
@ -368,7 +368,7 @@ export class Main extends Component<any, any> {
|
||||||
render() {
|
render() {
|
||||||
const title = i18n.t("lemmy_title");
|
const title = i18n.t("lemmy_title");
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto">
|
<div className="container mx-auto bg-blue">
|
||||||
<Helmet title={title}>
|
<Helmet title={title}>
|
||||||
<meta property={"title"} content={title} />
|
<meta property={"title"} content={title} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class NewsItem extends Component<any, any> {
|
||||||
<Helmet title={title}>
|
<Helmet title={title}>
|
||||||
<meta property={"title"} content={title} />
|
<meta property={"title"} content={title} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<div className="flex flex-col items-center mt-8">
|
<div className="flex flex-col items-center pt-16">
|
||||||
<article className="prose prose-a:text-primary prose-h1:text-primary">
|
<article className="prose prose-a:text-primary prose-h1:text-primary">
|
||||||
<div dangerouslySetInnerHTML={mdToHtml(this.markdown)} />
|
<div dangerouslySetInnerHTML={mdToHtml(this.markdown)} />
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Helmet } from "inferno-helmet";
|
||||||
import { i18n } from "../i18next";
|
import { i18n } from "../i18next";
|
||||||
import { isBrowser } from "../utils";
|
import { isBrowser } from "../utils";
|
||||||
import { news_md } from "../translations/news";
|
import { news_md } from "../translations/news";
|
||||||
import { Badge, gradientTextClasses } from "./common";
|
import { Badge, TEXT_GRADIENT } from "./common";
|
||||||
import { Icon } from "./icon";
|
import { Icon } from "./icon";
|
||||||
|
|
||||||
const title = i18n.t("news");
|
const title = i18n.t("news");
|
||||||
|
@ -42,7 +42,7 @@ function previewMarkdown(markdown: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const TitleBlock = () => (
|
const TitleBlock = () => (
|
||||||
<div className="mt-16 text-center text-4xl mb-8">{title}</div>
|
<div className="pt-16 text-center text-4xl mb-8">{title}</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const NewsCards = () => buildNewsInfoArray().map(n => <NewsCard news={n} />);
|
const NewsCards = () => buildNewsInfoArray().map(n => <NewsCard news={n} />);
|
||||||
|
@ -57,7 +57,7 @@ const NewsCard = ({ news }: NewsProps) => (
|
||||||
<div class="grid md:grid-cols-12 grid-cols-1 gap-4">
|
<div class="grid md:grid-cols-12 grid-cols-1 gap-4">
|
||||||
<div className="md:col-span-10">
|
<div className="md:col-span-10">
|
||||||
<div className="md:flex md:flex-row md:items-baseline md:space-x-3">
|
<div className="md:flex md:flex-row md:items-baseline md:space-x-3">
|
||||||
<Link to={news.url} className={`text-2xl ${gradientTextClasses}`}>
|
<Link to={news.url} className={`text-2xl ${TEXT_GRADIENT}`}>
|
||||||
{title}
|
{title}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="text-sm text-gray-500">{news.dateStr}</div>
|
<div className="text-sm text-gray-500">{news.dateStr}</div>
|
||||||
|
|
|
@ -20,6 +20,15 @@ export class Symbols extends Component<any, any> {
|
||||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||||
>
|
>
|
||||||
<defs>
|
<defs>
|
||||||
|
<symbol id="icon-user-check" viewBox="0 0 24 24">
|
||||||
|
<path d="M17 21v-2c0-1.38-0.561-2.632-1.464-3.536s-2.156-1.464-3.536-1.464h-7c-1.38 0-2.632 0.561-3.536 1.464s-1.464 2.156-1.464 3.536v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.829 0.335-1.577 0.879-2.121s1.292-0.879 2.121-0.879h7c0.829 0 1.577 0.335 2.121 0.879s0.879 1.292 0.879 2.121v2c0 0.552 0.448 1 1 1s1-0.448 1-1zM13.5 7c0-1.38-0.561-2.632-1.464-3.536s-2.156-1.464-3.536-1.464-2.632 0.561-3.536 1.464-1.464 2.156-1.464 3.536 0.561 2.632 1.464 3.536 2.156 1.464 3.536 1.464 2.632-0.561 3.536-1.464 1.464-2.156 1.464-3.536zM11.5 7c0 0.829-0.335 1.577-0.879 2.121s-1.292 0.879-2.121 0.879-1.577-0.335-2.121-0.879-0.879-1.292-0.879-2.121 0.335-1.577 0.879-2.121 1.292-0.879 2.121-0.879 1.577 0.335 2.121 0.879 0.879 1.292 0.879 2.121zM16.293 11.707l2 2c0.391 0.391 1.024 0.391 1.414 0l4-4c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-3.293 3.293-1.293-1.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-users" viewBox="0 0 24 24">
|
||||||
|
<path d="M18 21v-2c0-1.38-0.561-2.632-1.464-3.536s-2.156-1.464-3.536-1.464h-8c-1.38 0-2.632 0.561-3.536 1.464s-1.464 2.156-1.464 3.536v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.829 0.335-1.577 0.879-2.121s1.292-0.879 2.121-0.879h8c0.829 0 1.577 0.335 2.121 0.879s0.879 1.292 0.879 2.121v2c0 0.552 0.448 1 1 1s1-0.448 1-1zM14 7c0-1.38-0.561-2.632-1.464-3.536s-2.156-1.464-3.536-1.464-2.632 0.561-3.536 1.464-1.464 2.156-1.464 3.536 0.561 2.632 1.464 3.536 2.156 1.464 3.536 1.464 2.632-0.561 3.536-1.464 1.464-2.156 1.464-3.536zM12 7c0 0.829-0.335 1.577-0.879 2.121s-1.292 0.879-2.121 0.879-1.577-0.335-2.121-0.879-0.879-1.292-0.879-2.121 0.335-1.577 0.879-2.121 1.292-0.879 2.121-0.879 1.577 0.335 2.121 0.879 0.879 1.292 0.879 2.121zM24 21v-2c-0.001-1.245-0.457-2.385-1.215-3.261-0.652-0.753-1.528-1.311-2.529-1.576-0.534-0.141-1.081 0.177-1.222 0.711s0.177 1.081 0.711 1.222c0.607 0.161 1.136 0.498 1.528 0.952 0.454 0.526 0.726 1.206 0.727 1.952v2c0 0.552 0.448 1 1 1s1-0.448 1-1zM15.752 4.099c0.803 0.206 1.445 0.715 1.837 1.377s0.531 1.47 0.325 2.273c-0.176 0.688-0.575 1.256-1.105 1.652-0.314 0.235-0.675 0.409-1.063 0.511-0.534 0.14-0.854 0.687-0.713 1.221s0.687 0.854 1.221 0.713c0.637-0.167 1.232-0.455 1.752-0.844 0.884-0.66 1.552-1.613 1.845-2.758 0.342-1.337 0.11-2.689-0.542-3.788s-1.725-1.953-3.062-2.296c-0.535-0.137-1.080 0.186-1.217 0.721s0.186 1.080 0.721 1.217z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-message-circle" viewBox="0 0 24 24">
|
||||||
|
<path d="M22 11.497v-0.497c0-0.017-0.001-0.038-0.002-0.058-0.136-2.338-1.113-4.461-2.642-6.051-1.602-1.667-3.814-2.752-6.301-2.889-0.016-0.001-0.036-0.002-0.055-0.002h-0.489c-1.405-0.016-2.882 0.31-4.264 1.008-1.223 0.621-2.291 1.488-3.139 2.535-1.322 1.634-2.107 3.705-2.108 5.946-0.014 1.275 0.253 2.61 0.824 3.877l-1.772 5.317c-0.066 0.196-0.072 0.418 0 0.632 0.175 0.524 0.741 0.807 1.265 0.632l5.314-1.771c1.16 0.527 2.484 0.826 3.876 0.823 1.372-0.009 2.714-0.308 3.941-0.866 1.912-0.871 3.54-2.373 4.541-4.375 0.644-1.249 1.015-2.715 1.011-4.261zM20 11.503c0.003 1.225-0.292 2.375-0.789 3.339-0.801 1.602-2.082 2.785-3.592 3.472-0.97 0.442-2.035 0.679-3.126 0.686-1.221 0.003-2.371-0.292-3.335-0.789-0.249-0.129-0.528-0.142-0.775-0.060l-3.803 1.268 1.268-3.803c0.088-0.263 0.060-0.537-0.056-0.767-0.552-1.094-0.804-2.254-0.792-3.338 0.001-1.789 0.619-3.42 1.663-4.709 0.671-0.829 1.518-1.517 2.49-2.010 1.092-0.552 2.252-0.804 3.336-0.792h0.456c1.962 0.107 3.704 0.961 4.969 2.277 1.202 1.251 1.972 2.916 2.086 4.753z"></path>
|
||||||
|
</symbol>
|
||||||
<symbol id="icon-at-sign" viewBox="0 0 24 24">
|
<symbol id="icon-at-sign" viewBox="0 0 24 24">
|
||||||
<path d="M15 12c0 0.829-0.335 1.577-0.879 2.121s-1.292 0.879-2.121 0.879-1.577-0.335-2.121-0.879-0.879-1.292-0.879-2.121 0.335-1.577 0.879-2.121 1.292-0.879 2.121-0.879 1.577 0.335 2.121 0.879 0.879 1.292 0.879 2.121zM15.74 15.318c0.13 0.182 0.274 0.353 0.431 0.51 0.723 0.723 1.725 1.172 2.829 1.172s2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828v-1c0-3.037-1.233-5.789-3.222-7.778s-4.741-3.222-7.779-3.221-5.788 1.232-7.778 3.222-3.221 4.741-3.221 7.778 1.233 5.789 3.222 7.778 4.741 3.222 7.778 3.221c2.525 0 4.855-0.852 6.69-2.269 0.437-0.337 0.518-0.965 0.18-1.403s-0.965-0.518-1.403-0.18c-1.487 1.148-3.377 1.844-5.435 1.852-2.54-0.009-4.776-1.014-6.398-2.636-1.627-1.629-2.634-3.877-2.634-6.363s1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.363v1c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414v-5c0-0.552-0.448-1-1-1s-1 0.448-1 1c-0.835-0.627-1.875-1-3-1-1.38 0-2.632 0.561-3.536 1.464s-1.464 2.156-1.464 3.536 0.561 2.632 1.464 3.536 2.156 1.464 3.536 1.464 2.632-0.561 3.536-1.464c0.070-0.070 0.139-0.143 0.205-0.217z"></path>
|
<path d="M15 12c0 0.829-0.335 1.577-0.879 2.121s-1.292 0.879-2.121 0.879-1.577-0.335-2.121-0.879-0.879-1.292-0.879-2.121 0.335-1.577 0.879-2.121 1.292-0.879 2.121-0.879 1.577 0.335 2.121 0.879 0.879 1.292 0.879 2.121zM15.74 15.318c0.13 0.182 0.274 0.353 0.431 0.51 0.723 0.723 1.725 1.172 2.829 1.172s2.106-0.449 2.828-1.172 1.172-1.724 1.172-2.828v-1c0-3.037-1.233-5.789-3.222-7.778s-4.741-3.222-7.779-3.221-5.788 1.232-7.778 3.222-3.221 4.741-3.221 7.778 1.233 5.789 3.222 7.778 4.741 3.222 7.778 3.221c2.525 0 4.855-0.852 6.69-2.269 0.437-0.337 0.518-0.965 0.18-1.403s-0.965-0.518-1.403-0.18c-1.487 1.148-3.377 1.844-5.435 1.852-2.54-0.009-4.776-1.014-6.398-2.636-1.627-1.629-2.634-3.877-2.634-6.363s1.006-4.734 2.636-6.364 3.878-2.636 6.364-2.636 4.734 1.006 6.364 2.636 2.636 3.878 2.636 6.363v1c0 0.553-0.223 1.051-0.586 1.414s-0.861 0.586-1.414 0.586-1.051-0.223-1.414-0.586-0.586-0.861-0.586-1.414v-5c0-0.552-0.448-1-1-1s-1 0.448-1 1c-0.835-0.627-1.875-1-3-1-1.38 0-2.632 0.561-3.536 1.464s-1.464 2.156-1.464 3.536 0.561 2.632 1.464 3.536 2.156 1.464 3.536 1.464 2.632-0.561 3.536-1.464c0.070-0.070 0.139-0.143 0.205-0.217z"></path>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
Loading…
Reference in a new issue