mirror of
https://github.com/LemmyNet/joinlemmy-site.git
synced 2024-11-22 12:21:16 +00:00
Addressing PR comments.
This commit is contained in:
parent
d43f482d90
commit
dfc7bfdc98
15 changed files with 271 additions and 237 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -17,4 +17,4 @@
|
||||||
[submodule "lemmy-stats-crawler"]
|
[submodule "lemmy-stats-crawler"]
|
||||||
path = lemmy-stats-crawler
|
path = lemmy-stats-crawler
|
||||||
url = https://github.com/LemmyNet/lemmy-stats-crawler.git
|
url = https://github.com/LemmyNet/lemmy-stats-crawler.git
|
||||||
branch = upgrade_deps_1
|
branch = main
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit cacc71ec5453b4c4d8d701a495659cfc8f92b058
|
Subproject commit 229a9319ba1130723928e58fcbdbfccad45a4e81
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0e5578aaf34e0293c489eea64dbe7444c12732ec
|
Subproject commit ff8a2db505771c9f142ab31626b49de54a756192
|
|
@ -70,7 +70,7 @@ const AppDetailsCard = ({ app }: AppDetailsCardProps) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
const AppTitle = ({ title }) => (
|
const AppTitle = ({ title }) => (
|
||||||
<div className="text-xl mb-3 text-gray-300">{title}</div>
|
<div className="text-2xl mb-3 text-gray-300">{title}</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const MobileAppsBlock = () => (
|
const MobileAppsBlock = () => (
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
END_FUNDRAISER_DATE,
|
END_FUNDRAISER_DATE,
|
||||||
FUNDED_DEVS,
|
FUNDED_DEVS,
|
||||||
FUNDED_DEV_GOAL,
|
FUNDED_DEV_GOAL,
|
||||||
MEDIAN_DEV_MONTHLY_EUR,
|
|
||||||
MEDIAN_DEV_SALARY,
|
MEDIAN_DEV_SALARY,
|
||||||
TOTAL_RECURRING_MONTHLY_EUR,
|
TOTAL_RECURRING_MONTHLY_EUR,
|
||||||
TOTAL_SUPPORTERS,
|
TOTAL_SUPPORTERS,
|
||||||
|
@ -42,7 +41,7 @@ export const DonateDesc = () => (
|
||||||
<p className="text-sm text-gray-300 mb-3">
|
<p className="text-sm text-gray-300 mb-3">
|
||||||
<T i18nKey="donate_desc">
|
<T i18nKey="donate_desc">
|
||||||
#
|
#
|
||||||
<Link className="link link-primary" to="/donate">
|
<Link className="link" to="/donate">
|
||||||
#
|
#
|
||||||
</Link>
|
</Link>
|
||||||
#
|
#
|
||||||
|
@ -76,6 +75,12 @@ export const DonateButtons = () => (
|
||||||
#<span className="font-bold">#</span>
|
#<span className="font-bold">#</span>
|
||||||
</T>
|
</T>
|
||||||
</a>
|
</a>
|
||||||
|
<Link
|
||||||
|
class="btn btn-secondary text-white sm:max-md:btn-block normal-case"
|
||||||
|
to="/crypto"
|
||||||
|
>
|
||||||
|
Crypto
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -89,14 +94,18 @@ const FundingGoal = () => (
|
||||||
<span className="text-gray-200 mr-3">
|
<span className="text-gray-200 mr-3">
|
||||||
{i18n.t("per_month", { formattedCount: "" })}
|
{i18n.t("per_month", { formattedCount: "" })}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm text-gray-300">
|
|
||||||
{i18n.t("supporters", {
|
|
||||||
formattedCount: NUMBER_FORMAT.format(TOTAL_SUPPORTERS),
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xl font-bold">
|
<div
|
||||||
€{NUMBER_FORMAT.format(MEDIAN_DEV_MONTHLY_EUR * FUNDED_DEV_GOAL)}
|
className="text-xl font-bold tooltip"
|
||||||
|
data-tip={i18n.t("based_on_salary", {
|
||||||
|
formattedCount: NUMBER_FORMAT.format(MEDIAN_DEV_SALARY),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{i18n.t("devs_funded", {
|
||||||
|
formattedCount1: FUNDED_DEVS.toFixed(1),
|
||||||
|
formattedCount2: FUNDED_DEV_GOAL,
|
||||||
|
})}
|
||||||
|
*
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<progress
|
<progress
|
||||||
|
@ -105,17 +114,10 @@ const FundingGoal = () => (
|
||||||
max={FUNDED_DEV_GOAL}
|
max={FUNDED_DEV_GOAL}
|
||||||
></progress>
|
></progress>
|
||||||
<div className="flex flex-row flex-wrap justify-between gap-4">
|
<div className="flex flex-row flex-wrap justify-between gap-4">
|
||||||
<div
|
<div className="text-sm text-gray-300">
|
||||||
className="text-sm text-gray-300 tooltip"
|
{i18n.t("supporters", {
|
||||||
data-tip={i18n.t("based_on_salary", {
|
formattedCount: NUMBER_FORMAT.format(TOTAL_SUPPORTERS),
|
||||||
formattedCount: NUMBER_FORMAT.format(MEDIAN_DEV_SALARY),
|
|
||||||
})}
|
})}
|
||||||
>
|
|
||||||
{i18n.t("devs_funded", {
|
|
||||||
formattedCount1: FUNDED_DEVS.toFixed(2),
|
|
||||||
formattedCount2: FUNDED_DEV_GOAL,
|
|
||||||
})}
|
|
||||||
*
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-gray-300">
|
<div className="text-sm text-gray-300">
|
||||||
{monthsBetween(new Date(), END_FUNDRAISER_DATE)} months remaining
|
{monthsBetween(new Date(), END_FUNDRAISER_DATE)} months remaining
|
||||||
|
@ -124,12 +126,12 @@ const FundingGoal = () => (
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SupportDonateBlock = () => (
|
export const DonateBlock = () => (
|
||||||
<div className="flex flex-col items-center pt-16">
|
<div className="flex flex-col items-center pt-16">
|
||||||
<div className={`card card-bordered ${CARD_GRADIENT} shadow-xl`}>
|
<div className={`card card-bordered ${CARD_GRADIENT} shadow-xl`}>
|
||||||
<div className="card-body px-8 md:px-32 py-16">
|
<div className="card-body px-8 md:px-32 py-16">
|
||||||
<p class={`card-title text-4xl mb-3 ${TEXT_GRADIENT}`}>
|
<p class={`card-title text-4xl mb-3 ${TEXT_GRADIENT}`}>
|
||||||
{i18n.t("support_donate")}
|
{i18n.t("donate")}
|
||||||
</p>
|
</p>
|
||||||
<DonateDesc />
|
<DonateDesc />
|
||||||
<FundingGoal />
|
<FundingGoal />
|
||||||
|
|
59
src/shared/components/crypto.tsx
Normal file
59
src/shared/components/crypto.tsx
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { Helmet } from "inferno-helmet";
|
||||||
|
import { Badge } from "./common";
|
||||||
|
|
||||||
|
const title = "Crypto";
|
||||||
|
|
||||||
|
interface Crypto {
|
||||||
|
name: string;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CRYPTOS: Crypto[] = [
|
||||||
|
{
|
||||||
|
name: "bitcoin",
|
||||||
|
address: "1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ethereum",
|
||||||
|
address: "0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "monero",
|
||||||
|
address:
|
||||||
|
"41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cardano",
|
||||||
|
address:
|
||||||
|
"addr1q858t89l2ym6xmrugjs0af9cslfwvnvsh2xxp6x4dcez7pf5tushkp4wl7zxfhm2djp6gq60dk4cmc7seaza5p3slx0sakjutm",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const Crypto = () => (
|
||||||
|
<div className="container mx-auto px-4">
|
||||||
|
<Helmet title={title}>
|
||||||
|
<meta property={"title"} content={title} />
|
||||||
|
</Helmet>
|
||||||
|
<div className="pt-16 text-center text-4xl font-bold mb-8">{title}</div>
|
||||||
|
<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>
|
||||||
|
);
|
|
@ -99,8 +99,8 @@ export interface Coder {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CODERS: Coder[] = [
|
export const CODERS: Coder[] = [
|
||||||
{ name: "dessalines", link: "https://mastodon.social/@dessalines" },
|
{ name: "dessalines", link: "https://github.com/dessalines" },
|
||||||
{ name: "Nutomic", link: "https://lemmy.ml/u/nutomic" },
|
{ name: "Nutomic", link: "https://github.com/nutomic" },
|
||||||
{ name: "phiresky", link: "https://github.com/phiresky" },
|
{ name: "phiresky", link: "https://github.com/phiresky" },
|
||||||
{ name: "SleeplessOne1917", link: "https://github.com/SleeplessOne1917" },
|
{ name: "SleeplessOne1917", link: "https://github.com/SleeplessOne1917" },
|
||||||
{ name: "asonix", link: "https://github.com/asonix" },
|
{ name: "asonix", link: "https://github.com/asonix" },
|
||||||
|
@ -124,32 +124,6 @@ export interface Translator {
|
||||||
link?: 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",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
interface FundingPlatform {
|
interface FundingPlatform {
|
||||||
supporterCount: number;
|
supporterCount: number;
|
||||||
monthlyEUR: number;
|
monthlyEUR: number;
|
||||||
|
|
|
@ -5,12 +5,7 @@ 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 {
|
import { Badge, BottomSpacer, DonateBlock, TEXT_GRADIENT } from "./common";
|
||||||
Badge,
|
|
||||||
BottomSpacer,
|
|
||||||
SupportDonateBlock,
|
|
||||||
TEXT_GRADIENT,
|
|
||||||
} from "./common";
|
|
||||||
import {
|
import {
|
||||||
CODERS,
|
CODERS,
|
||||||
GOLD_SPONSORS,
|
GOLD_SPONSORS,
|
||||||
|
@ -20,7 +15,6 @@ import {
|
||||||
LATINUM_SPONSORS,
|
LATINUM_SPONSORS,
|
||||||
GENERAL_SPONSORS,
|
GENERAL_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";
|
||||||
|
@ -44,7 +38,7 @@ const ContributorsBlock = () => (
|
||||||
<T i18nKey="add_weblate">
|
<T i18nKey="add_weblate">
|
||||||
#
|
#
|
||||||
<a
|
<a
|
||||||
className="link link-primary"
|
className="link"
|
||||||
href="https://weblate.join-lemmy.org/projects/lemmy/"
|
href="https://weblate.join-lemmy.org/projects/lemmy/"
|
||||||
>
|
>
|
||||||
#
|
#
|
||||||
|
@ -191,32 +185,6 @@ const GeneralSponsorCard = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CryptoBlock = () => (
|
|
||||||
<div>
|
|
||||||
<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;
|
||||||
|
@ -284,16 +252,15 @@ export class Donate extends Component<any, any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const title = i18n.t("support_title");
|
const title = i18n.t("donate_title");
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<Helmet title={title}>
|
<Helmet title={title}>
|
||||||
<meta property={"title"} content={title} />
|
<meta property={"title"} content={title} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<SupportDonateBlock />
|
<DonateBlock />
|
||||||
<ContributorsBlock />
|
<ContributorsBlock />
|
||||||
<SponsorsBlock />
|
<SponsorsBlock />
|
||||||
<CryptoBlock />
|
|
||||||
<BottomSpacer />
|
<BottomSpacer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@ export enum IconSize {
|
||||||
Small = "w-3 h-3",
|
Small = "w-3 h-3",
|
||||||
Medium = "w-4 h-4",
|
Medium = "w-4 h-4",
|
||||||
Large = "w-6 h-6",
|
Large = "w-6 h-6",
|
||||||
|
Largest = "w-8 h-8",
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IconProps {
|
interface IconProps {
|
||||||
|
|
|
@ -8,7 +8,10 @@ import { Icon } from "./icon";
|
||||||
enum Step {
|
enum Step {
|
||||||
Interest,
|
Interest,
|
||||||
Language,
|
Language,
|
||||||
Join,
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
reset?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
@ -17,14 +20,21 @@ interface State {
|
||||||
language?: string;
|
language?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InstancePicker extends Component<any, State> {
|
export class InstancePicker extends Component<Props, State> {
|
||||||
state: State = {
|
state: State = {
|
||||||
activeStep: Step.Interest,
|
activeStep: Step.Interest,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(): void {
|
||||||
|
this.setState({
|
||||||
|
activeStep: Step.Interest,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<dialog id="picker" className="modal">
|
<dialog id="picker" className="modal">
|
||||||
|
@ -43,23 +53,18 @@ export class InstancePicker extends Component<any, State> {
|
||||||
<p className="text-2xl font-bold text-center pb-4">
|
<p className="text-2xl font-bold text-center pb-4">
|
||||||
{i18n.t("what_topic")}
|
{i18n.t("what_topic")}
|
||||||
</p>
|
</p>
|
||||||
|
<div className="flex flex-row flex-wrap gap-4 pb-4">
|
||||||
{TOPICS.map(c => (
|
{TOPICS.map(c => (
|
||||||
<div className="form-control">
|
<button
|
||||||
<label className="label cursor-pointer">
|
className="btn btn-sm btn-outline normal-case"
|
||||||
<span className="label-text text-sm text-gray-300">
|
|
||||||
<Icon icon={c.icon} classes="mr-3" />
|
|
||||||
{i18n.t(c.name as I18nKeys)}
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="topic-radio"
|
|
||||||
className="radio"
|
|
||||||
value={c.name}
|
value={c.name}
|
||||||
onChange={linkEvent(this, handleTopicChange)}
|
onClick={linkEvent(this, handleTopicChange)}
|
||||||
/>
|
>
|
||||||
</label>
|
<Icon icon={c.icon} />
|
||||||
</div>
|
{i18n.t(c.name as I18nKeys)}
|
||||||
|
</button>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{this.state.activeStep == Step.Language && (
|
{this.state.activeStep == Step.Language && (
|
||||||
|
@ -67,36 +72,24 @@ export class InstancePicker extends Component<any, State> {
|
||||||
<p className="text-2xl font-bold text-center pb-4">
|
<p className="text-2xl font-bold text-center pb-4">
|
||||||
{i18n.t("what_language")}
|
{i18n.t("what_language")}
|
||||||
</p>
|
</p>
|
||||||
<div className="form-control">
|
<div className="flex flex-row flex-wrap gap-4 pb-4">
|
||||||
<label className="label cursor-pointer">
|
<button
|
||||||
<span className="label-text text-sm text-gray-300">
|
className="btn btn-sm btn-outline normal-case"
|
||||||
{i18n.t("all_languages")}
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="language-radio"
|
|
||||||
className="radio"
|
|
||||||
value={"all"}
|
value={"all"}
|
||||||
onChange={linkEvent(this, handleLanguageChange)}
|
onClick={linkEvent(this, handleLanguageChange)}
|
||||||
/>
|
>
|
||||||
</label>
|
{i18n.t("all_languages")}
|
||||||
</div>
|
</button>
|
||||||
{LANGUAGES.map(l => (
|
{LANGUAGES.map(l => (
|
||||||
<div className="form-control">
|
<button
|
||||||
<label className="label cursor-pointer">
|
className="btn btn-sm btn-outline normal-case"
|
||||||
<span className="label-text text-sm text-gray-300">
|
|
||||||
{l.name}
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
name="language-radio"
|
|
||||||
className="radio"
|
|
||||||
value={l.code}
|
value={l.code}
|
||||||
onChange={linkEvent(this, handleLanguageChange)}
|
onClick={linkEvent(this, handleLanguageChange)}
|
||||||
/>
|
>
|
||||||
</label>
|
{l.name}
|
||||||
</div>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -117,13 +110,6 @@ export class InstancePicker extends Component<any, State> {
|
||||||
>
|
>
|
||||||
{i18n.t("languages")}
|
{i18n.t("languages")}
|
||||||
</li>
|
</li>
|
||||||
<li
|
|
||||||
className={classNames("step text-gray-300", {
|
|
||||||
"step-primary": this.state.activeStep == Step.Join,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{i18n.t("join")}
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,20 +12,44 @@ import {
|
||||||
All_TOPIC,
|
All_TOPIC,
|
||||||
TOPICS,
|
TOPICS,
|
||||||
} from "./instances-definitions";
|
} from "./instances-definitions";
|
||||||
import { Icon } from "./icon";
|
import { Icon, IconSize } from "./icon";
|
||||||
import { I18nKeys } from "i18next";
|
import { I18nKeys } from "i18next";
|
||||||
|
|
||||||
const TitleBlock = () => (
|
const TitleBlock = () => (
|
||||||
<div className="flex flex-col items-center pt-16 mb-16">
|
<div className="flex flex-col items-center pt-16 mb-16">
|
||||||
<T i18nKey="lemmy_servers" className="text-4xl font-bold mb-3">
|
<T i18nKey="lemmy_servers" className="text-4xl font-bold mb-8">
|
||||||
#<span className={TEXT_GRADIENT}>#</span>
|
#<span className={TEXT_GRADIENT}>#</span>
|
||||||
</T>
|
</T>
|
||||||
<p className="text-xl text-gray-300 text-center max-w-xl">
|
<div
|
||||||
{i18n.t("instance_totals", {
|
className="tooltip"
|
||||||
instances: numToSI(instance_stats.stats.crawled_instances),
|
data-tip={i18n.t("monthly_active_users", {
|
||||||
users: numToSI(instance_stats.stats.users_active_month),
|
formattedCount: numToSI(instance_stats.stats.users_active_month),
|
||||||
})}
|
})}
|
||||||
</p>
|
>
|
||||||
|
<div className="stats shadow mb-8">
|
||||||
|
<div className="stat">
|
||||||
|
<div className="stat-figure text-primary">
|
||||||
|
<Icon icon="globe" size={IconSize.Largest} />
|
||||||
|
</div>
|
||||||
|
<div className="stat-title">{i18n.t("servers")}</div>
|
||||||
|
<div className="stat-value">
|
||||||
|
{numToSI(instance_stats.stats.crawled_instances)}
|
||||||
|
</div>
|
||||||
|
<div className="stat-desc">{i18n.t("lemmyverse")}</div>
|
||||||
|
</div>
|
||||||
|
<div className="stat">
|
||||||
|
<div className="stat-figure text-secondary">
|
||||||
|
<Icon icon="users" size={IconSize.Largest} />
|
||||||
|
</div>
|
||||||
|
<div className="stat-title">{i18n.t("active_users")}*</div>
|
||||||
|
<div className="stat-value">
|
||||||
|
{numToSI(instance_stats.stats.users_active_month)}
|
||||||
|
</div>
|
||||||
|
<div className="stat-desc">{new Date().toLocaleDateString()}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-xl text-gray-300">{i18n.t("instance_disclaimer")}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -122,7 +146,7 @@ const InstanceCard = ({ instance }: InstanceCardProps) => {
|
||||||
class="btn btn-primary text-white sm:max-md:btn-block bg-gradient-to-r from-[#69D066] to-[#03A80E] normal-case"
|
class="btn btn-primary text-white sm:max-md:btn-block bg-gradient-to-r from-[#69D066] to-[#03A80E] normal-case"
|
||||||
href={buildUrl(domain)}
|
href={buildUrl(domain)}
|
||||||
>
|
>
|
||||||
{i18n.t("join_a_server")}
|
{i18n.t("browse_instance")}
|
||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
class="btn btn-secondary btn-outline text-white sm:max-md:btn-block normal-case"
|
class="btn btn-secondary btn-outline text-white sm:max-md:btn-block normal-case"
|
||||||
|
@ -161,7 +185,12 @@ export const StatsBadges = ({ users, comments, monthlyUsers }) => (
|
||||||
<>
|
<>
|
||||||
<Badge
|
<Badge
|
||||||
content={
|
content={
|
||||||
<div className="text-sm text-gray-500">
|
<div
|
||||||
|
className="text-sm text-gray-500 tooltip"
|
||||||
|
data-tip={i18n.t("total_users", {
|
||||||
|
formattedCount: users.toLocaleString(),
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Icon icon="users" classes="mr-2" />
|
<Icon icon="users" classes="mr-2" />
|
||||||
<span>{users.toLocaleString()}</span>
|
<span>{users.toLocaleString()}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -169,7 +198,12 @@ export const StatsBadges = ({ users, comments, monthlyUsers }) => (
|
||||||
/>
|
/>
|
||||||
<Badge
|
<Badge
|
||||||
content={
|
content={
|
||||||
<div className="text-sm text-gray-500">
|
<div
|
||||||
|
className="text-sm text-gray-500 tooltip"
|
||||||
|
data-tip={i18n.t("total_comments", {
|
||||||
|
formattedCount: comments.toLocaleString(),
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Icon icon="message-circle" classes="mr-2" />
|
<Icon icon="message-circle" classes="mr-2" />
|
||||||
<span>{comments.toLocaleString()}</span>
|
<span>{comments.toLocaleString()}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -177,7 +211,12 @@ export const StatsBadges = ({ users, comments, monthlyUsers }) => (
|
||||||
/>
|
/>
|
||||||
<Badge
|
<Badge
|
||||||
content={
|
content={
|
||||||
<div className="text-sm text-gray-500">
|
<div
|
||||||
|
className="text-sm text-gray-500 tooltip"
|
||||||
|
data-tip={i18n.t("monthly_active_users", {
|
||||||
|
formattedCount: monthlyUsers.toLocaleString(),
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Icon icon="user-check" classes="mr-2" />
|
<Icon icon="user-check" classes="mr-2" />
|
||||||
<span>
|
<span>
|
||||||
{i18n.t("per_month", {
|
{i18n.t("per_month", {
|
||||||
|
|
|
@ -8,64 +8,67 @@ import { Icon } from "./icon";
|
||||||
import {
|
import {
|
||||||
BottomSpacer,
|
BottomSpacer,
|
||||||
CARD_GRADIENT,
|
CARD_GRADIENT,
|
||||||
SupportDonateBlock,
|
DonateBlock,
|
||||||
TEXT_GRADIENT,
|
TEXT_GRADIENT,
|
||||||
} from "./common";
|
} from "./common";
|
||||||
import { InstancePicker } from "./instance-picker";
|
import { InstancePicker } from "./instance-picker";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
const TitleBlock = () => (
|
interface MainProps {
|
||||||
|
i: Main;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TitleBlock = ({ i }: MainProps) => (
|
||||||
<div className="py-16 flex flex-col items-center">
|
<div className="py-16 flex flex-col items-center">
|
||||||
<div className="flex flex-col items-center gap-4 mb-8">
|
<div className="flex flex-col items-center gap-4 mb-8">
|
||||||
<p className={`text-6xl font-bold ${TEXT_GRADIENT}`}>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-4">
|
<div className="flex flex-row justify-around gap-4">
|
||||||
<JoinServerButton />
|
<JoinServerButton i={i} />
|
||||||
<SeeAllServersButton />
|
<SeeAllServersButton />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const carouselImages = [
|
||||||
|
"/static/assets/images/main_screen_2.webp",
|
||||||
|
"/static/assets/images/main_screen_3.webp",
|
||||||
|
"/static/assets/images/main_screen_1.webp",
|
||||||
|
];
|
||||||
|
|
||||||
const CarouselBlock = () => (
|
const CarouselBlock = () => (
|
||||||
<div>
|
<div>
|
||||||
<div className="carousel carousel-center p-8 space-x-8 rounded-box">
|
<div className="carousel carousel-center p-8 space-x-8 rounded-box mt-16">
|
||||||
<div id="item1" className="carousel-item w-9/12">
|
{carouselImages.map((image, i) => (
|
||||||
|
<div id={`item-${i}`} className="carousel-item w-9/12 lg:w-5/12">
|
||||||
<img
|
<img
|
||||||
src={"/static/assets/images/main_screen_2.webp"}
|
src={image}
|
||||||
className="rounded-box border-8 border-secondary/[.15] z-10"
|
className={classNames("rounded-box border-8 z-10", {
|
||||||
/>
|
"border-primary/[.15]": i & 1,
|
||||||
</div>
|
"border-secondary/[.15]": !(i & 1),
|
||||||
<div id="item2" className="carousel-item w-9/12">
|
})}
|
||||||
<img
|
|
||||||
src={"/static/assets/images/main_screen_3.webp"}
|
|
||||||
className="rounded-box border-8 border-primary/[.15] z-10"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div id="item3" className="carousel-item w-9/12">
|
|
||||||
<img
|
|
||||||
src={"/static/assets/images/main_screen_1.webp"}
|
|
||||||
className="rounded-box border-8 border-secondary/[.15] z-10"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center w-full py-2 gap-4">
|
<div className="flex justify-center w-full py-2 gap-4">
|
||||||
<a href="#item1" className={TEXT_GRADIENT}>
|
{carouselImages.map((_, i) => (
|
||||||
●
|
<a href={`#item-${i}`} className={TEXT_GRADIENT}>
|
||||||
</a>
|
|
||||||
<a href="#item2" className={TEXT_GRADIENT}>
|
|
||||||
●
|
|
||||||
</a>
|
|
||||||
<a href="#item3" className={TEXT_GRADIENT}>
|
|
||||||
●
|
●
|
||||||
</a>
|
</a>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const JoinServerButton = () => (
|
const JoinServerButton = ({ i }: MainProps) => (
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary text-white normal-case z-10"
|
className="btn btn-primary text-white normal-case z-10"
|
||||||
onClick={() => (document.getElementById("picker") as any).showModal()}
|
onClick={() => {
|
||||||
|
i.setState({ resetInstancePicker: true });
|
||||||
|
(document.getElementById("picker") as any).showModal();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{i18n.t("join_a_server")}
|
{i18n.t("join_a_server")}
|
||||||
</button>
|
</button>
|
||||||
|
@ -80,8 +83,8 @@ const SeeAllServersButton = () => (
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
const FollowCommunitiesBlock = () => (
|
const FollowCommunitiesBlock = ({ i }: MainProps) => (
|
||||||
<div className="flex flex-col items-center mt-16">
|
<div className="flex flex-col items-center">
|
||||||
<div className={`card card-bordered ${CARD_GRADIENT} shadow-xl`}>
|
<div className={`card card-bordered ${CARD_GRADIENT} shadow-xl`}>
|
||||||
<div className="card-body items-center px-8 md:px-32 py-16">
|
<div className="card-body items-center px-8 md:px-32 py-16">
|
||||||
<T
|
<T
|
||||||
|
@ -93,14 +96,14 @@ const FollowCommunitiesBlock = () => (
|
||||||
<p className="text-sm text-gray-300 text-center mb-6">
|
<p className="text-sm text-gray-300 text-center mb-6">
|
||||||
{i18n.t("lemmy_long_desc")}
|
{i18n.t("lemmy_long_desc")}
|
||||||
</p>
|
</p>
|
||||||
<JoinServerButton />
|
<JoinServerButton i={i} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const FeatureCard = ({ pic, title, subtitle, classes }) => (
|
const FeatureCard = ({ pic, title, subtitle, classes }) => (
|
||||||
<div className={`card card-bordered bg-neutral-800 shadow-xl ${classes}`}>
|
<div className={`card ${CARD_GRADIENT} shadow-xl ${classes}`}>
|
||||||
<figure className="p-4">
|
<figure className="p-4">
|
||||||
<img src={pic} className="rounded-xl w-full object-fill min-h-[300px]" />
|
<img src={pic} className="rounded-xl w-full object-fill min-h-[300px]" />
|
||||||
</figure>
|
</figure>
|
||||||
|
@ -247,13 +250,13 @@ const MoreFeaturesBlock = () => (
|
||||||
<T i18nKey="self_hostable">
|
<T i18nKey="self_hostable">
|
||||||
#
|
#
|
||||||
<a
|
<a
|
||||||
className="link link-primary"
|
className="link"
|
||||||
href={`/docs/administration/install_docker.html`}
|
href={`/docs/administration/install_docker.html`}
|
||||||
>
|
>
|
||||||
#
|
#
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
className="link link-primary"
|
className="link"
|
||||||
href={`/docs/administration/install_ansible.html`}
|
href={`/docs/administration/install_ansible.html`}
|
||||||
>
|
>
|
||||||
#
|
#
|
||||||
|
@ -276,7 +279,7 @@ const MoreFeaturesBlock = () => (
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
text={
|
text={
|
||||||
<Link className="link link-primary" to="/apps">
|
<Link className="link" to="/apps">
|
||||||
{i18n.t("mobile_apps_for_ios_and_android")}
|
{i18n.t("mobile_apps_for_ios_and_android")}
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
|
@ -297,7 +300,7 @@ const MoreFeaturesBlock = () => (
|
||||||
}
|
}
|
||||||
text={
|
text={
|
||||||
<T i18nKey="full_vote_scores">
|
<T i18nKey="full_vote_scores">
|
||||||
#<code className="text-primary">#</code>#
|
#<code>#</code>#
|
||||||
</T>
|
</T>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -313,7 +316,7 @@ const MoreFeaturesBlock = () => (
|
||||||
icons={<div>:</div>}
|
icons={<div>:</div>}
|
||||||
text={
|
text={
|
||||||
<T i18nKey="emojis_autocomplete">
|
<T i18nKey="emojis_autocomplete">
|
||||||
#<code className="text-primary">#</code>
|
#<code>#</code>
|
||||||
</T>
|
</T>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -325,8 +328,8 @@ const MoreFeaturesBlock = () => (
|
||||||
}
|
}
|
||||||
text={
|
text={
|
||||||
<T i18nKey="user_tagging">
|
<T i18nKey="user_tagging">
|
||||||
#<code className="text-primary">#</code>
|
#<code>#</code>
|
||||||
<code className="text-primary">#</code>
|
<code>#</code>
|
||||||
</T>
|
</T>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -356,7 +359,7 @@ const MoreFeaturesBlock = () => (
|
||||||
<T i18nKey="i18n_support">
|
<T i18nKey="i18n_support">
|
||||||
#
|
#
|
||||||
<a
|
<a
|
||||||
className="link link-primary"
|
className="link"
|
||||||
href="https://weblate.join-lemmy.org/projects/lemmy/lemmy/"
|
href="https://weblate.join-lemmy.org/projects/lemmy/lemmy/"
|
||||||
>
|
>
|
||||||
#
|
#
|
||||||
|
@ -372,11 +375,11 @@ const MoreFeaturesBlock = () => (
|
||||||
}
|
}
|
||||||
text={
|
text={
|
||||||
<T i18nKey="rss_feeds">
|
<T i18nKey="rss_feeds">
|
||||||
#<code className="text-primary">#</code>
|
#<code>#</code>
|
||||||
<code className="text-primary">#</code>
|
<code>#</code>
|
||||||
<code className="text-primary">#</code>
|
<code>#</code>
|
||||||
<code className="text-primary">#</code>
|
<code>#</code>
|
||||||
<code className="text-primary">#</code>
|
<code>#</code>
|
||||||
</T>
|
</T>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -411,13 +414,19 @@ const MoreFeaturesBlock = () => (
|
||||||
const MoreFeaturesCard = ({ icons, text }) => (
|
const MoreFeaturesCard = ({ icons, text }) => (
|
||||||
<div className="card card-bordered w-auto bg-neutral-800 shadow-xl">
|
<div className="card card-bordered w-auto bg-neutral-800 shadow-xl">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className="btn btn-sm btn-secondary w-fit mb-2">{icons}</div>
|
<div className="btn btn-sm btn-secondary w-fit mb-2 pointer-events-none">
|
||||||
|
{icons}
|
||||||
|
</div>
|
||||||
<p className="text-sm text-gray-300">{text}</p>
|
<p className="text-sm text-gray-300">{text}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export class Main extends Component<any, any> {
|
export class Main extends Component<any, any> {
|
||||||
|
state = {
|
||||||
|
resetInstancePicker: false,
|
||||||
|
};
|
||||||
|
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +441,7 @@ export class Main extends Component<any, any> {
|
||||||
const title = i18n.t("lemmy_title");
|
const title = i18n.t("lemmy_title");
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<InstancePicker />
|
<InstancePicker reset={this.state.resetInstancePicker} />
|
||||||
<Helmet title={title}>
|
<Helmet title={title}>
|
||||||
<meta property={"title"} content={title} />
|
<meta property={"title"} content={title} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
@ -441,15 +450,15 @@ export class Main extends Component<any, any> {
|
||||||
className="bg-top bg-no-repeat bg-contain opacity-20 absolute"
|
className="bg-top bg-no-repeat bg-contain opacity-20 absolute"
|
||||||
/>
|
/>
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<TitleBlock />
|
<TitleBlock i={this} />
|
||||||
|
<FollowCommunitiesBlock i={this} />
|
||||||
</div>
|
</div>
|
||||||
<CarouselBlock />
|
<CarouselBlock />
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<FollowCommunitiesBlock />
|
|
||||||
<FeatureCardsBlock />
|
<FeatureCardsBlock />
|
||||||
<DiscussionPlatformBlock />
|
<DiscussionPlatformBlock />
|
||||||
<MoreFeaturesBlock />
|
<MoreFeaturesBlock />
|
||||||
<SupportDonateBlock />
|
<DonateBlock />
|
||||||
<BottomSpacer />
|
<BottomSpacer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -82,7 +82,10 @@ export const Navbar = ({ footer = false }) => (
|
||||||
</div>
|
</div>
|
||||||
<div className="navbar-end">
|
<div className="navbar-end">
|
||||||
{footer ? (
|
{footer ? (
|
||||||
<a className="text-sm text-gray-600 sm:max-lg:hidden">
|
<a
|
||||||
|
className="text-sm text-gray-600 sm:max-lg:hidden text-right"
|
||||||
|
href="https://github.com/LemmyNet/lemmy/blob/main/LICENSE"
|
||||||
|
>
|
||||||
{i18n.t("copyright_line")}
|
{i18n.t("copyright_line")}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -2,20 +2,17 @@ import { Component } from "inferno";
|
||||||
import { Link } from "inferno-router";
|
import { Link } from "inferno-router";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { i18n } from "../i18next";
|
import { i18n } from "../i18next";
|
||||||
import { isBrowser } from "../utils";
|
import { isBrowser, mdToHtml } from "../utils";
|
||||||
import { news_md } from "../translations/news";
|
import { news_md } from "../translations/news";
|
||||||
import { Badge, BottomSpacer, TEXT_GRADIENT } from "./common";
|
import { BottomSpacer, TEXT_GRADIENT } from "./common";
|
||||||
import { Icon } from "./icon";
|
|
||||||
|
|
||||||
const title = i18n.t("news");
|
const title = i18n.t("news");
|
||||||
const authors = ["nutomic", "dessalines"];
|
|
||||||
const news_reversed = news_md.reverse();
|
const news_reversed = news_md.reverse();
|
||||||
|
|
||||||
interface NewsInfo {
|
interface NewsInfo {
|
||||||
title: string;
|
title: string;
|
||||||
dateStr: string;
|
dateStr: string;
|
||||||
preview: string;
|
preview: string;
|
||||||
authors: Array<string>;
|
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +24,6 @@ function buildNewsInfoArray(): Array<NewsInfo> {
|
||||||
dateStr: split[0],
|
dateStr: split[0],
|
||||||
title: split[1],
|
title: split[1],
|
||||||
preview: split[2] || previewMarkdown(n.markdown),
|
preview: split[2] || previewMarkdown(n.markdown),
|
||||||
authors,
|
|
||||||
url: `news/${titleToUrl(n.title)}`,
|
url: `news/${titleToUrl(n.title)}`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -38,7 +34,11 @@ function titleToUrl(title: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function previewMarkdown(markdown: string): string {
|
function previewMarkdown(markdown: string): string {
|
||||||
return markdown.replace(/#/g, "").slice(0, 100).concat("...");
|
return markdown
|
||||||
|
.replace(/#/g, "")
|
||||||
|
.replace(/[\n\r]/g, " ")
|
||||||
|
.slice(0, 100)
|
||||||
|
.concat("...");
|
||||||
}
|
}
|
||||||
|
|
||||||
const TitleBlock = () => (
|
const TitleBlock = () => (
|
||||||
|
@ -61,14 +61,13 @@ const NewsCard = ({ news }: NewsProps) => (
|
||||||
{news.title}
|
{news.title}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="text-sm text-gray-500">{news.dateStr}</div>
|
<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>
|
{news.preview && (
|
||||||
<div className="text-sm text-gray-300">{news.preview}</div>
|
<div
|
||||||
|
className="text-sm text-gray-300"
|
||||||
|
dangerouslySetInnerHTML={mdToHtml(news.preview)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
to={news.url}
|
to={news.url}
|
||||||
|
@ -81,17 +80,6 @@ const NewsCard = ({ news }: NewsProps) => (
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const AuthorBadge = ({ name }) => (
|
|
||||||
<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> {
|
export class News extends Component<any, any> {
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { Contact } from "./components/contact";
|
||||||
import { Donate } from "./components/donate";
|
import { Donate } from "./components/donate";
|
||||||
import { News } from "./components/news";
|
import { News } from "./components/news";
|
||||||
import { NewsItem } from "./components/news-item";
|
import { NewsItem } from "./components/news-item";
|
||||||
|
import { Crypto } from "./components/crypto";
|
||||||
|
|
||||||
export const routes: IRouteProps[] = [
|
export const routes: IRouteProps[] = [
|
||||||
{
|
{
|
||||||
|
@ -48,4 +49,9 @@ export const routes: IRouteProps[] = [
|
||||||
exact: true,
|
exact: true,
|
||||||
component: Donate,
|
component: Donate,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `/crypto`,
|
||||||
|
exact: true,
|
||||||
|
component: Crypto,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue