mirror of
https://github.com/LemmyNet/joinlemmy-site.git
synced 2024-11-25 22:01:17 +00:00
Almost done with donation page.
This commit is contained in:
parent
74d8257694
commit
14d463464d
8 changed files with 201 additions and 124 deletions
|
@ -18,6 +18,7 @@
|
|||
"repository": "https://github.com/LemmyNet/joinlemmy-site",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/parser": "^5.60.1",
|
||||
"classnames": "^2.3.2",
|
||||
"express": "~4.18.2",
|
||||
"i18next": "^23.2.6",
|
||||
"inferno": "^8.2.1",
|
||||
|
|
|
@ -1,2 +1,59 @@
|
|||
import { Link } from "inferno-router";
|
||||
import { i18n } from "../i18next";
|
||||
import { T } from "inferno-i18next";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
export const gradientTextClasses =
|
||||
"bg-gradient-to-r bg-clip-text text-transparent from-[#69D066] to-[#03A80E]";
|
||||
|
||||
export const Badge = ({ content }) => (
|
||||
<div className="p-2 rounded-xl bg-neutral-800 text-gray-300 w-fit">
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const DonateDesc = () => (
|
||||
<p className="text-sm text-gray-300 mb-6">
|
||||
<T i18nKey="donate_desc">
|
||||
#
|
||||
<Link className="link" to="/donate">
|
||||
#
|
||||
</Link>
|
||||
#
|
||||
</T>
|
||||
</p>
|
||||
);
|
||||
|
||||
export const DonateButtons = () => (
|
||||
<div class="flex flex-row justify-between gap-2">
|
||||
<a class="btn btn-primary text-white" href="https://liberapay.com/Lemmy">
|
||||
{i18n.t("support_on_liberapay")}
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-secondary text-white"
|
||||
href="https://www.patreon.com/dessalines"
|
||||
>
|
||||
{i18n.t("support_on_patreon")}
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-primary text-white"
|
||||
href="https://opencollective.com/lemmy"
|
||||
>
|
||||
{i18n.t("support_on_opencollective")}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const SupportDonateBlock = () => (
|
||||
<div className="flex flex-col items-center mt-16">
|
||||
<div className="card card-bordered bg-neutral-800 shadow-xl">
|
||||
<div className="card-body px-32 py-16">
|
||||
<p class={`card-title text-4xl mb-3 ${gradientTextClasses}`}>
|
||||
{i18n.t("support_donate")}
|
||||
</p>
|
||||
<DonateDesc />
|
||||
<DonateButtons />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -5,79 +5,124 @@ import { T } from "inferno-i18next";
|
|||
import { translators } from "../translations/translators";
|
||||
import { languagesAll, countries } from "countries-list";
|
||||
import { isBrowser } from "../utils";
|
||||
import { Badge, SupportDonateBlock, gradientTextClasses } from "./common";
|
||||
import {
|
||||
CODERS,
|
||||
GOLD_SPONSORS,
|
||||
HIGHLIGHTED_SPONSORS,
|
||||
LATINUM_SPONSORS,
|
||||
SILVER_SPONSORS,
|
||||
SPONSORS,
|
||||
Translation,
|
||||
} from "./donate-definitions";
|
||||
import classNames from "classnames";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
const avatarSize = 40;
|
||||
const bannerWidth = 240;
|
||||
const bannerHeight = 101;
|
||||
|
||||
interface LinkedSponsor {
|
||||
name: string;
|
||||
link: string;
|
||||
}
|
||||
const SectionTitle = ({ title }) => (
|
||||
<div className="text-2xl mb-3">{title}</div>
|
||||
);
|
||||
|
||||
interface GoldSponsor {
|
||||
name: string;
|
||||
link: string;
|
||||
avatar: string;
|
||||
}
|
||||
const ContributorsBlock = () => (
|
||||
<div>
|
||||
<SectionTitle title={i18n.t("contributers")} />
|
||||
<p class="text-sm text-gray-300 mb-3">{i18n.t("thanks_coders")}</p>
|
||||
<CodersBlock />
|
||||
<p class="text-sm text-gray-300 mt-6 mb-3">
|
||||
{i18n.t("thanks_translators")}
|
||||
</p>
|
||||
<TranslatorsBlock />
|
||||
</div>
|
||||
);
|
||||
|
||||
let goldSponsors: GoldSponsor[] = [];
|
||||
const CodersBlock = () => (
|
||||
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||
<div className="card-body p-4">
|
||||
<PersonBadges persons={CODERS} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
let latinumSponsors: GoldSponsor[] = [
|
||||
{
|
||||
name: "NLnet",
|
||||
link: "https://nlnet.nl",
|
||||
avatar: "https://nlnet.nl/image/logo_nlnet.svg",
|
||||
},
|
||||
];
|
||||
const TranslatorsBlock = () => (
|
||||
<div className="card card-bordered bg-neutral-900 shadow-xl">
|
||||
<div className="card-body p-4">
|
||||
<table>
|
||||
{convertTranslators().map(t => (
|
||||
<tr>
|
||||
<td>
|
||||
<div className="text-secondary">
|
||||
<span>{languagesAll[t.lang].native}</span>
|
||||
{t.country && <span> {countries[t.country].native}</span>}
|
||||
<span>:</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<PersonBadges persons={t.translators} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
let silverSponsors: LinkedSponsor[] = [];
|
||||
|
||||
let highlightedSponsors = ["DQW", "John Knapp"];
|
||||
let sponsors = [
|
||||
"Anthony",
|
||||
"Remi Rampin",
|
||||
"Cameron C",
|
||||
"Vegard",
|
||||
"0ti.me",
|
||||
"Brendan",
|
||||
"mexicanhalloween .",
|
||||
"Arthur Nieuwland",
|
||||
"Forrest Weghorst",
|
||||
"Luke Black",
|
||||
"Brandon Abbott",
|
||||
"Eon Gattignolo",
|
||||
];
|
||||
|
||||
export interface Coder {
|
||||
interface PersonBadgeData {
|
||||
name: string;
|
||||
link?: string;
|
||||
greenOutline?: boolean;
|
||||
greenAt?: boolean;
|
||||
}
|
||||
|
||||
let 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[];
|
||||
interface PersonBadgeProps {
|
||||
person: PersonBadgeData;
|
||||
}
|
||||
|
||||
export interface Translator {
|
||||
name: string;
|
||||
link?: string;
|
||||
const PersonBadge = ({ person }: PersonBadgeProps) =>
|
||||
person.link ? (
|
||||
<a href={person.link}>
|
||||
<PersonBadgeInternal person={person} />
|
||||
</a>
|
||||
) : (
|
||||
<PersonBadgeInternal person={person} />
|
||||
);
|
||||
|
||||
const PersonBadgeInternal = ({ person }: PersonBadgeProps) => (
|
||||
<Badge
|
||||
content={
|
||||
<div>
|
||||
<Icon
|
||||
icon="at-sign"
|
||||
classes={classNames("fill-current text-gray-600", {
|
||||
"text-primary": person.greenAt,
|
||||
})}
|
||||
/>
|
||||
<span
|
||||
className={classNames("ml-1", {
|
||||
[`${gradientTextClasses}`]: person.link,
|
||||
})}
|
||||
>
|
||||
{person.name}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
interface PersonBadgesProps {
|
||||
persons: PersonBadgeData[];
|
||||
}
|
||||
|
||||
const PersonBadges = ({ persons }: PersonBadgesProps) => (
|
||||
<div className="flex flex-row flex-wrap gap-2 mb-2">
|
||||
{persons.map(p => (
|
||||
<PersonBadge person={p} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export class Donate extends Component<any, any> {
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
|
@ -92,10 +137,14 @@ export class Donate extends Component<any, any> {
|
|||
render() {
|
||||
const title = i18n.t("support_title");
|
||||
return (
|
||||
<div>
|
||||
<div className="container mx-auto">
|
||||
<Helmet title={title}>
|
||||
<meta property={"title"} content={title} />
|
||||
</Helmet>
|
||||
<SupportDonateBlock />
|
||||
<div className="mb-16" />
|
||||
<ContributorsBlock />
|
||||
|
||||
<div class="container">
|
||||
<div class="text-center">
|
||||
<h1>{i18n.t("support_lemmy")}</h1>
|
||||
|
@ -109,11 +158,11 @@ export class Donate extends Component<any, any> {
|
|||
</div>
|
||||
<div class="text-center">
|
||||
<h2>{i18n.t("sponsors")}</h2>
|
||||
{latinumSponsors.length > 0 && (
|
||||
{LATINUM_SPONSORS.length > 0 && (
|
||||
<div>
|
||||
<p>{i18n.t("gold_pressed_latinum_sponsors_desc")}</p>
|
||||
<div class="row is-horizontal-align">
|
||||
{latinumSponsors.map(s => (
|
||||
{LATINUM_SPONSORS.map(s => (
|
||||
<div class="col-6">
|
||||
<a class="button outline" href={s.link}>
|
||||
<img
|
||||
|
@ -129,11 +178,11 @@ export class Donate extends Component<any, any> {
|
|||
<br />
|
||||
</div>
|
||||
)}
|
||||
{goldSponsors.length > 0 && (
|
||||
{GOLD_SPONSORS.length > 0 && (
|
||||
<div>
|
||||
<p>{i18n.t("gold_sponsors_desc")}</p>
|
||||
<div class="row is-horizontal-align">
|
||||
{goldSponsors.map(s => (
|
||||
{GOLD_SPONSORS.map(s => (
|
||||
<div class="col">
|
||||
<a class="button outline gold" href={s.link}>
|
||||
<img
|
||||
|
@ -150,11 +199,11 @@ export class Donate extends Component<any, any> {
|
|||
<br />
|
||||
</div>
|
||||
)}
|
||||
{silverSponsors.length > 0 && (
|
||||
{SILVER_SPONSORS.length > 0 && (
|
||||
<div>
|
||||
<p>{i18n.t("silver_sponsors_desc")}</p>
|
||||
<div class="row is-horizontal-align">
|
||||
{silverSponsors.map(s => (
|
||||
{SILVER_SPONSORS.map(s => (
|
||||
<div class="col">
|
||||
<a class="button outline primary" href={s.link}>
|
||||
💎 {s.name}
|
||||
|
@ -167,12 +216,12 @@ export class Donate extends Component<any, any> {
|
|||
)}
|
||||
<p>{i18n.t("general_sponsors_desc")}</p>
|
||||
<div class="row is-horizontal-align">
|
||||
{highlightedSponsors.map(s => (
|
||||
{HIGHLIGHTED_SPONSORS.map(s => (
|
||||
<div class="col">
|
||||
<div class="button outline primary">{s}</div>
|
||||
</div>
|
||||
))}
|
||||
{sponsors.map(s => (
|
||||
{SPONSORS.map(s => (
|
||||
<div class="col">
|
||||
<div class="button outline">{s}</div>
|
||||
</div>
|
||||
|
@ -257,14 +306,14 @@ export class Donate extends Component<any, any> {
|
|||
<div>
|
||||
<p>
|
||||
<span>{i18n.t("thanks_coders")}</span>
|
||||
{coders.map((coder, i) => (
|
||||
{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>{i != CODERS.length - 1 ? ", " : " "}</span>
|
||||
</span>
|
||||
))}
|
||||
</p>
|
||||
|
|
|
@ -5,7 +5,7 @@ import { i18n } from "../i18next";
|
|||
import { T } from "inferno-i18next";
|
||||
import { isBrowser } from "../utils";
|
||||
import { Icon } from "./icon";
|
||||
import { gradientTextClasses } from "./common";
|
||||
import { SupportDonateBlock, gradientTextClasses } from "./common";
|
||||
|
||||
const TitleBlock = () => (
|
||||
<div className="flex flex-col items-center">
|
||||
|
@ -354,52 +354,6 @@ const MoreFeaturesCard = ({ icons, text }) => (
|
|||
</div>
|
||||
);
|
||||
|
||||
const DonateDesc = () => (
|
||||
<p className="text-sm text-gray-300 mb-6">
|
||||
<T i18nKey="donate_desc">
|
||||
#
|
||||
<Link className="link" to="/donate">
|
||||
#
|
||||
</Link>
|
||||
#
|
||||
</T>
|
||||
</p>
|
||||
);
|
||||
|
||||
const DonateButtons = () => (
|
||||
<div class="flex flex-row justify-between gap-2">
|
||||
<a class="btn btn-primary text-white" href="https://liberapay.com/Lemmy">
|
||||
{i18n.t("support_on_liberapay")}
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-secondary text-white"
|
||||
href="https://www.patreon.com/dessalines"
|
||||
>
|
||||
{i18n.t("support_on_patreon")}
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-primary text-white"
|
||||
href="https://opencollective.com/lemmy"
|
||||
>
|
||||
{i18n.t("support_on_opencollective")}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
const SupportDonateBlock = () => (
|
||||
<div className="flex flex-col items-center mt-16">
|
||||
<div className="card card-bordered bg-neutral-800 shadow-xl">
|
||||
<div className="card-body px-32 py-16">
|
||||
<p class={`card-title text-4xl mb-3 ${gradientTextClasses}`}>
|
||||
{i18n.t("support_donate")}
|
||||
</p>
|
||||
<DonateDesc />
|
||||
<DonateButtons />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export class Main extends Component<any, any> {
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
|
|
|
@ -29,7 +29,7 @@ export class NewsItem extends Component<any, any> {
|
|||
<Helmet title={title}>
|
||||
<meta property={"title"} content={title} />
|
||||
</Helmet>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="flex flex-col items-center mt-8">
|
||||
<article className="prose prose-a:text-primary prose-h1:text-primary">
|
||||
<div dangerouslySetInnerHTML={mdToHtml(this.markdown)} />
|
||||
</article>
|
||||
|
|
|
@ -4,7 +4,8 @@ import { Helmet } from "inferno-helmet";
|
|||
import { i18n } from "../i18next";
|
||||
import { isBrowser } from "../utils";
|
||||
import { news_md } from "../translations/news";
|
||||
import { gradientTextClasses } from "./common";
|
||||
import { Badge, gradientTextClasses } from "./common";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
const title = i18n.t("news");
|
||||
const authors = ["nutomic", "dessalines"];
|
||||
|
@ -51,7 +52,7 @@ interface NewsProps {
|
|||
}
|
||||
|
||||
const NewsCard = ({ news }: NewsProps) => (
|
||||
<div className="card card-bordered bg-neutral-800 shadow-xl mb-3">
|
||||
<div className="card card-bordered bg-neutral-900 shadow-xl mb-3">
|
||||
<div className="card-body">
|
||||
<div class="grid md:grid-cols-12 grid-cols-1 gap-4">
|
||||
<div className="md:col-span-10">
|
||||
|
@ -60,9 +61,12 @@ const NewsCard = ({ news }: NewsProps) => (
|
|||
{title}
|
||||
</Link>
|
||||
<div className="text-sm text-gray-500">{news.dateStr}</div>
|
||||
{authors.map(name => (
|
||||
<AuthorBadge name={name} />
|
||||
))}
|
||||
|
||||
<div className="flex flex-row flex-wrap items-baseline space-x-3 mb-2">
|
||||
{authors.map(name => (
|
||||
<AuthorBadge name={name} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-sm text-gray-300">{news.preview}</div>
|
||||
</div>
|
||||
|
@ -75,10 +79,14 @@ const NewsCard = ({ news }: NewsProps) => (
|
|||
);
|
||||
|
||||
const AuthorBadge = ({ name }) => (
|
||||
<div className="badge bg-neutral-700">
|
||||
<code>@</code>
|
||||
<span className="ml-1 text-gray-300">{name}</span>
|
||||
</div>
|
||||
<Badge
|
||||
content={
|
||||
<div>
|
||||
<Icon icon="at-sign" classes={"fill-current text-gray-600"} />
|
||||
<span className="ml-1 text-gray-300">{name}</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
export class News extends Component<any, any> {
|
||||
|
|
|
@ -20,6 +20,9 @@ export class Symbols extends Component<any, any> {
|
|||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<defs>
|
||||
<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>
|
||||
</symbol>
|
||||
<symbol id="icon-embed" viewBox="0 0 40 32">
|
||||
<path d="M26 23l3 3 10-10-10-10-3 3 7 7z"></path>
|
||||
<path d="M14 9l-3-3-10 10 10 10 3-3-7-7z"></path>
|
||||
|
|
|
@ -2335,6 +2335,11 @@ cidr-regex@1.0.6:
|
|||
resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-1.0.6.tgz#74abfd619df370b9d54ab14475568e97dd64c0c1"
|
||||
integrity sha1-dKv9YZ3zcLnVSrFEdVaOl91kwME=
|
||||
|
||||
classnames@^2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
|
||||
integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
|
||||
|
||||
clean-stack@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||
|
|
Loading…
Reference in a new issue