Almost done with donation page.

This commit is contained in:
Dessalines 2023-09-26 13:08:22 -04:00
parent 74d8257694
commit 14d463464d
8 changed files with 201 additions and 124 deletions

View file

@ -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",

View file

@ -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>
);

View file

@ -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>

View file

@ -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);

View file

@ -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>

View file

@ -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,10 +61,13 @@ const NewsCard = ({ news }: NewsProps) => (
{title}
</Link>
<div className="text-sm text-gray-500">{news.dateStr}</div>
<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>
<Link to={news.url} className="md:col-span-2 btn btn-secondary">
@ -75,10 +79,14 @@ const NewsCard = ({ news }: NewsProps) => (
);
const AuthorBadge = ({ name }) => (
<div className="badge bg-neutral-700">
<code>@</code>
<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> {

View file

@ -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>

View file

@ -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"