mirror of
https://github.com/LemmyNet/joinlemmy-site.git
synced 2024-11-22 04:11:15 +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"]
|
||||
path = lemmy-stats-crawler
|
||||
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 }) => (
|
||||
<div className="text-xl mb-3 text-gray-300">{title}</div>
|
||||
<div className="text-2xl mb-3 text-gray-300">{title}</div>
|
||||
);
|
||||
|
||||
const MobileAppsBlock = () => (
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
END_FUNDRAISER_DATE,
|
||||
FUNDED_DEVS,
|
||||
FUNDED_DEV_GOAL,
|
||||
MEDIAN_DEV_MONTHLY_EUR,
|
||||
MEDIAN_DEV_SALARY,
|
||||
TOTAL_RECURRING_MONTHLY_EUR,
|
||||
TOTAL_SUPPORTERS,
|
||||
|
@ -42,7 +41,7 @@ export const DonateDesc = () => (
|
|||
<p className="text-sm text-gray-300 mb-3">
|
||||
<T i18nKey="donate_desc">
|
||||
#
|
||||
<Link className="link link-primary" to="/donate">
|
||||
<Link className="link" to="/donate">
|
||||
#
|
||||
</Link>
|
||||
#
|
||||
|
@ -76,6 +75,12 @@ export const DonateButtons = () => (
|
|||
#<span className="font-bold">#</span>
|
||||
</T>
|
||||
</a>
|
||||
<Link
|
||||
class="btn btn-secondary text-white sm:max-md:btn-block normal-case"
|
||||
to="/crypto"
|
||||
>
|
||||
Crypto
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -89,14 +94,18 @@ const FundingGoal = () => (
|
|||
<span className="text-gray-200 mr-3">
|
||||
{i18n.t("per_month", { formattedCount: "" })}
|
||||
</span>
|
||||
<span className="text-sm text-gray-300">
|
||||
{i18n.t("supporters", {
|
||||
formattedCount: NUMBER_FORMAT.format(TOTAL_SUPPORTERS),
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xl font-bold">
|
||||
€{NUMBER_FORMAT.format(MEDIAN_DEV_MONTHLY_EUR * FUNDED_DEV_GOAL)}
|
||||
<div
|
||||
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>
|
||||
<progress
|
||||
|
@ -105,17 +114,10 @@ const FundingGoal = () => (
|
|||
max={FUNDED_DEV_GOAL}
|
||||
></progress>
|
||||
<div className="flex flex-row flex-wrap justify-between gap-4">
|
||||
<div
|
||||
className="text-sm text-gray-300 tooltip"
|
||||
data-tip={i18n.t("based_on_salary", {
|
||||
formattedCount: NUMBER_FORMAT.format(MEDIAN_DEV_SALARY),
|
||||
<div className="text-sm text-gray-300">
|
||||
{i18n.t("supporters", {
|
||||
formattedCount: NUMBER_FORMAT.format(TOTAL_SUPPORTERS),
|
||||
})}
|
||||
>
|
||||
{i18n.t("devs_funded", {
|
||||
formattedCount1: FUNDED_DEVS.toFixed(2),
|
||||
formattedCount2: FUNDED_DEV_GOAL,
|
||||
})}
|
||||
*
|
||||
</div>
|
||||
<div className="text-sm text-gray-300">
|
||||
{monthsBetween(new Date(), END_FUNDRAISER_DATE)} months remaining
|
||||
|
@ -124,12 +126,12 @@ const FundingGoal = () => (
|
|||
</div>
|
||||
);
|
||||
|
||||
export const SupportDonateBlock = () => (
|
||||
export const DonateBlock = () => (
|
||||
<div className="flex flex-col items-center pt-16">
|
||||
<div className={`card card-bordered ${CARD_GRADIENT} shadow-xl`}>
|
||||
<div className="card-body px-8 md:px-32 py-16">
|
||||
<p class={`card-title text-4xl mb-3 ${TEXT_GRADIENT}`}>
|
||||
{i18n.t("support_donate")}
|
||||
{i18n.t("donate")}
|
||||
</p>
|
||||
<DonateDesc />
|
||||
<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[] = [
|
||||
{ name: "dessalines", link: "https://mastodon.social/@dessalines" },
|
||||
{ name: "Nutomic", link: "https://lemmy.ml/u/nutomic" },
|
||||
{ name: "dessalines", link: "https://github.com/dessalines" },
|
||||
{ name: "Nutomic", link: "https://github.com/nutomic" },
|
||||
{ name: "phiresky", link: "https://github.com/phiresky" },
|
||||
{ name: "SleeplessOne1917", link: "https://github.com/SleeplessOne1917" },
|
||||
{ name: "asonix", link: "https://github.com/asonix" },
|
||||
|
@ -124,32 +124,6 @@ export interface Translator {
|
|||
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 {
|
||||
supporterCount: number;
|
||||
monthlyEUR: number;
|
||||
|
|
|
@ -5,12 +5,7 @@ import { T } from "inferno-i18next";
|
|||
import { translators } from "../translations/translators";
|
||||
import { languagesAll, countries } from "countries-list";
|
||||
import { isBrowser } from "../utils";
|
||||
import {
|
||||
Badge,
|
||||
BottomSpacer,
|
||||
SupportDonateBlock,
|
||||
TEXT_GRADIENT,
|
||||
} from "./common";
|
||||
import { Badge, BottomSpacer, DonateBlock, TEXT_GRADIENT } from "./common";
|
||||
import {
|
||||
CODERS,
|
||||
GOLD_SPONSORS,
|
||||
|
@ -20,7 +15,6 @@ import {
|
|||
LATINUM_SPONSORS,
|
||||
GENERAL_SPONSORS,
|
||||
Translation,
|
||||
CRYPTOS,
|
||||
} from "./donate-definitions";
|
||||
import classNames from "classnames";
|
||||
import { Icon } from "./icon";
|
||||
|
@ -44,7 +38,7 @@ const ContributorsBlock = () => (
|
|||
<T i18nKey="add_weblate">
|
||||
#
|
||||
<a
|
||||
className="link link-primary"
|
||||
className="link"
|
||||
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 {
|
||||
name: string;
|
||||
link?: string;
|
||||
|
@ -284,16 +252,15 @@ export class Donate extends Component<any, any> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const title = i18n.t("support_title");
|
||||
const title = i18n.t("donate_title");
|
||||
return (
|
||||
<div className="container mx-auto px-4">
|
||||
<Helmet title={title}>
|
||||
<meta property={"title"} content={title} />
|
||||
</Helmet>
|
||||
<SupportDonateBlock />
|
||||
<DonateBlock />
|
||||
<ContributorsBlock />
|
||||
<SponsorsBlock />
|
||||
<CryptoBlock />
|
||||
<BottomSpacer />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -2,6 +2,7 @@ export enum IconSize {
|
|||
Small = "w-3 h-3",
|
||||
Medium = "w-4 h-4",
|
||||
Large = "w-6 h-6",
|
||||
Largest = "w-8 h-8",
|
||||
}
|
||||
|
||||
interface IconProps {
|
||||
|
|
|
@ -8,7 +8,10 @@ import { Icon } from "./icon";
|
|||
enum Step {
|
||||
Interest,
|
||||
Language,
|
||||
Join,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
reset?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -17,14 +20,21 @@ interface State {
|
|||
language?: string;
|
||||
}
|
||||
|
||||
export class InstancePicker extends Component<any, State> {
|
||||
export class InstancePicker extends Component<Props, State> {
|
||||
state: State = {
|
||||
activeStep: Step.Interest,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(): void {
|
||||
this.setState({
|
||||
activeStep: Step.Interest,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<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">
|
||||
{i18n.t("what_topic")}
|
||||
</p>
|
||||
{TOPICS.map(c => (
|
||||
<div className="form-control">
|
||||
<label className="label cursor-pointer">
|
||||
<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}
|
||||
onChange={linkEvent(this, handleTopicChange)}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
<div className="flex flex-row flex-wrap gap-4 pb-4">
|
||||
{TOPICS.map(c => (
|
||||
<button
|
||||
className="btn btn-sm btn-outline normal-case"
|
||||
value={c.name}
|
||||
onClick={linkEvent(this, handleTopicChange)}
|
||||
>
|
||||
<Icon icon={c.icon} />
|
||||
{i18n.t(c.name as I18nKeys)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{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">
|
||||
{i18n.t("what_language")}
|
||||
</p>
|
||||
<div className="form-control">
|
||||
<label className="label cursor-pointer">
|
||||
<span className="label-text text-sm text-gray-300">
|
||||
{i18n.t("all_languages")}
|
||||
</span>
|
||||
<input
|
||||
type="radio"
|
||||
name="language-radio"
|
||||
className="radio"
|
||||
value={"all"}
|
||||
onChange={linkEvent(this, handleLanguageChange)}
|
||||
/>
|
||||
</label>
|
||||
<div className="flex flex-row flex-wrap gap-4 pb-4">
|
||||
<button
|
||||
className="btn btn-sm btn-outline normal-case"
|
||||
value={"all"}
|
||||
onClick={linkEvent(this, handleLanguageChange)}
|
||||
>
|
||||
{i18n.t("all_languages")}
|
||||
</button>
|
||||
{LANGUAGES.map(l => (
|
||||
<button
|
||||
className="btn btn-sm btn-outline normal-case"
|
||||
value={l.code}
|
||||
onClick={linkEvent(this, handleLanguageChange)}
|
||||
>
|
||||
{l.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{LANGUAGES.map(l => (
|
||||
<div className="form-control">
|
||||
<label className="label cursor-pointer">
|
||||
<span className="label-text text-sm text-gray-300">
|
||||
{l.name}
|
||||
</span>
|
||||
<input
|
||||
type="radio"
|
||||
name="language-radio"
|
||||
className="radio"
|
||||
value={l.code}
|
||||
onChange={linkEvent(this, handleLanguageChange)}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
@ -117,13 +110,6 @@ export class InstancePicker extends Component<any, State> {
|
|||
>
|
||||
{i18n.t("languages")}
|
||||
</li>
|
||||
<li
|
||||
className={classNames("step text-gray-300", {
|
||||
"step-primary": this.state.activeStep == Step.Join,
|
||||
})}
|
||||
>
|
||||
{i18n.t("join")}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,20 +12,44 @@ import {
|
|||
All_TOPIC,
|
||||
TOPICS,
|
||||
} from "./instances-definitions";
|
||||
import { Icon } from "./icon";
|
||||
import { Icon, IconSize } from "./icon";
|
||||
import { I18nKeys } from "i18next";
|
||||
|
||||
const TitleBlock = () => (
|
||||
<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>
|
||||
</T>
|
||||
<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),
|
||||
<div
|
||||
className="tooltip"
|
||||
data-tip={i18n.t("monthly_active_users", {
|
||||
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>
|
||||
);
|
||||
|
||||
|
@ -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"
|
||||
href={buildUrl(domain)}
|
||||
>
|
||||
{i18n.t("join_a_server")}
|
||||
{i18n.t("browse_instance")}
|
||||
</a>
|
||||
<button
|
||||
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
|
||||
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" />
|
||||
<span>{users.toLocaleString()}</span>
|
||||
</div>
|
||||
|
@ -169,7 +198,12 @@ export const StatsBadges = ({ users, comments, monthlyUsers }) => (
|
|||
/>
|
||||
<Badge
|
||||
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" />
|
||||
<span>{comments.toLocaleString()}</span>
|
||||
</div>
|
||||
|
@ -177,7 +211,12 @@ export const StatsBadges = ({ users, comments, monthlyUsers }) => (
|
|||
/>
|
||||
<Badge
|
||||
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" />
|
||||
<span>
|
||||
{i18n.t("per_month", {
|
||||
|
|
|
@ -8,64 +8,67 @@ import { Icon } from "./icon";
|
|||
import {
|
||||
BottomSpacer,
|
||||
CARD_GRADIENT,
|
||||
SupportDonateBlock,
|
||||
DonateBlock,
|
||||
TEXT_GRADIENT,
|
||||
} from "./common";
|
||||
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="flex flex-col items-center gap-4 mb-8">
|
||||
<p className={`text-6xl font-bold ${TEXT_GRADIENT}`}>Lemmy</p>
|
||||
<p className="text-3xl font-medium text-center">{i18n.t("lemmy_desc")}</p>
|
||||
</div>
|
||||
<div className="flex flex-row justify-around gap-4">
|
||||
<JoinServerButton />
|
||||
<JoinServerButton i={i} />
|
||||
<SeeAllServersButton />
|
||||
</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 = () => (
|
||||
<div>
|
||||
<div className="carousel carousel-center p-8 space-x-8 rounded-box">
|
||||
<div id="item1" className="carousel-item w-9/12">
|
||||
<img
|
||||
src={"/static/assets/images/main_screen_2.webp"}
|
||||
className="rounded-box border-8 border-secondary/[.15] z-10"
|
||||
/>
|
||||
</div>
|
||||
<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 className="carousel carousel-center p-8 space-x-8 rounded-box mt-16">
|
||||
{carouselImages.map((image, i) => (
|
||||
<div id={`item-${i}`} className="carousel-item w-9/12 lg:w-5/12">
|
||||
<img
|
||||
src={image}
|
||||
className={classNames("rounded-box border-8 z-10", {
|
||||
"border-primary/[.15]": i & 1,
|
||||
"border-secondary/[.15]": !(i & 1),
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex justify-center w-full py-2 gap-4">
|
||||
<a href="#item1" className={TEXT_GRADIENT}>
|
||||
●
|
||||
</a>
|
||||
<a href="#item2" className={TEXT_GRADIENT}>
|
||||
●
|
||||
</a>
|
||||
<a href="#item3" className={TEXT_GRADIENT}>
|
||||
●
|
||||
</a>
|
||||
{carouselImages.map((_, i) => (
|
||||
<a href={`#item-${i}`} className={TEXT_GRADIENT}>
|
||||
●
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const JoinServerButton = () => (
|
||||
const JoinServerButton = ({ i }: MainProps) => (
|
||||
<button
|
||||
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")}
|
||||
</button>
|
||||
|
@ -80,8 +83,8 @@ const SeeAllServersButton = () => (
|
|||
</Link>
|
||||
);
|
||||
|
||||
const FollowCommunitiesBlock = () => (
|
||||
<div className="flex flex-col items-center mt-16">
|
||||
const FollowCommunitiesBlock = ({ i }: MainProps) => (
|
||||
<div className="flex flex-col items-center">
|
||||
<div className={`card card-bordered ${CARD_GRADIENT} shadow-xl`}>
|
||||
<div className="card-body items-center px-8 md:px-32 py-16">
|
||||
<T
|
||||
|
@ -93,14 +96,14 @@ const FollowCommunitiesBlock = () => (
|
|||
<p className="text-sm text-gray-300 text-center mb-6">
|
||||
{i18n.t("lemmy_long_desc")}
|
||||
</p>
|
||||
<JoinServerButton />
|
||||
<JoinServerButton i={i} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
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">
|
||||
<img src={pic} className="rounded-xl w-full object-fill min-h-[300px]" />
|
||||
</figure>
|
||||
|
@ -247,13 +250,13 @@ const MoreFeaturesBlock = () => (
|
|||
<T i18nKey="self_hostable">
|
||||
#
|
||||
<a
|
||||
className="link link-primary"
|
||||
className="link"
|
||||
href={`/docs/administration/install_docker.html`}
|
||||
>
|
||||
#
|
||||
</a>
|
||||
<a
|
||||
className="link link-primary"
|
||||
className="link"
|
||||
href={`/docs/administration/install_ansible.html`}
|
||||
>
|
||||
#
|
||||
|
@ -276,7 +279,7 @@ const MoreFeaturesBlock = () => (
|
|||
</div>
|
||||
}
|
||||
text={
|
||||
<Link className="link link-primary" to="/apps">
|
||||
<Link className="link" to="/apps">
|
||||
{i18n.t("mobile_apps_for_ios_and_android")}
|
||||
</Link>
|
||||
}
|
||||
|
@ -297,7 +300,7 @@ const MoreFeaturesBlock = () => (
|
|||
}
|
||||
text={
|
||||
<T i18nKey="full_vote_scores">
|
||||
#<code className="text-primary">#</code>#
|
||||
#<code>#</code>#
|
||||
</T>
|
||||
}
|
||||
/>
|
||||
|
@ -313,7 +316,7 @@ const MoreFeaturesBlock = () => (
|
|||
icons={<div>:</div>}
|
||||
text={
|
||||
<T i18nKey="emojis_autocomplete">
|
||||
#<code className="text-primary">#</code>
|
||||
#<code>#</code>
|
||||
</T>
|
||||
}
|
||||
/>
|
||||
|
@ -325,8 +328,8 @@ const MoreFeaturesBlock = () => (
|
|||
}
|
||||
text={
|
||||
<T i18nKey="user_tagging">
|
||||
#<code className="text-primary">#</code>
|
||||
<code className="text-primary">#</code>
|
||||
#<code>#</code>
|
||||
<code>#</code>
|
||||
</T>
|
||||
}
|
||||
/>
|
||||
|
@ -356,7 +359,7 @@ const MoreFeaturesBlock = () => (
|
|||
<T i18nKey="i18n_support">
|
||||
#
|
||||
<a
|
||||
className="link link-primary"
|
||||
className="link"
|
||||
href="https://weblate.join-lemmy.org/projects/lemmy/lemmy/"
|
||||
>
|
||||
#
|
||||
|
@ -372,11 +375,11 @@ const MoreFeaturesBlock = () => (
|
|||
}
|
||||
text={
|
||||
<T i18nKey="rss_feeds">
|
||||
#<code className="text-primary">#</code>
|
||||
<code className="text-primary">#</code>
|
||||
<code className="text-primary">#</code>
|
||||
<code className="text-primary">#</code>
|
||||
<code className="text-primary">#</code>
|
||||
#<code>#</code>
|
||||
<code>#</code>
|
||||
<code>#</code>
|
||||
<code>#</code>
|
||||
<code>#</code>
|
||||
</T>
|
||||
}
|
||||
/>
|
||||
|
@ -411,13 +414,19 @@ const MoreFeaturesBlock = () => (
|
|||
const MoreFeaturesCard = ({ icons, text }) => (
|
||||
<div className="card card-bordered w-auto bg-neutral-800 shadow-xl">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export class Main extends Component<any, any> {
|
||||
state = {
|
||||
resetInstancePicker: false,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
@ -432,7 +441,7 @@ export class Main extends Component<any, any> {
|
|||
const title = i18n.t("lemmy_title");
|
||||
return (
|
||||
<div>
|
||||
<InstancePicker />
|
||||
<InstancePicker reset={this.state.resetInstancePicker} />
|
||||
<Helmet title={title}>
|
||||
<meta property={"title"} content={title} />
|
||||
</Helmet>
|
||||
|
@ -441,15 +450,15 @@ export class Main extends Component<any, any> {
|
|||
className="bg-top bg-no-repeat bg-contain opacity-20 absolute"
|
||||
/>
|
||||
<div className="container mx-auto px-4">
|
||||
<TitleBlock />
|
||||
<TitleBlock i={this} />
|
||||
<FollowCommunitiesBlock i={this} />
|
||||
</div>
|
||||
<CarouselBlock />
|
||||
<div className="container mx-auto px-4">
|
||||
<FollowCommunitiesBlock />
|
||||
<FeatureCardsBlock />
|
||||
<DiscussionPlatformBlock />
|
||||
<MoreFeaturesBlock />
|
||||
<SupportDonateBlock />
|
||||
<DonateBlock />
|
||||
<BottomSpacer />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -82,7 +82,10 @@ export const Navbar = ({ footer = false }) => (
|
|||
</div>
|
||||
<div className="navbar-end">
|
||||
{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")}
|
||||
</a>
|
||||
) : (
|
||||
|
|
|
@ -2,20 +2,17 @@ import { Component } from "inferno";
|
|||
import { Link } from "inferno-router";
|
||||
import { Helmet } from "inferno-helmet";
|
||||
import { i18n } from "../i18next";
|
||||
import { isBrowser } from "../utils";
|
||||
import { isBrowser, mdToHtml } from "../utils";
|
||||
import { news_md } from "../translations/news";
|
||||
import { Badge, BottomSpacer, TEXT_GRADIENT } from "./common";
|
||||
import { Icon } from "./icon";
|
||||
import { BottomSpacer, TEXT_GRADIENT } from "./common";
|
||||
|
||||
const title = i18n.t("news");
|
||||
const authors = ["nutomic", "dessalines"];
|
||||
const news_reversed = news_md.reverse();
|
||||
|
||||
interface NewsInfo {
|
||||
title: string;
|
||||
dateStr: string;
|
||||
preview: string;
|
||||
authors: Array<string>;
|
||||
url: string;
|
||||
}
|
||||
|
||||
|
@ -27,7 +24,6 @@ function buildNewsInfoArray(): Array<NewsInfo> {
|
|||
dateStr: split[0],
|
||||
title: split[1],
|
||||
preview: split[2] || previewMarkdown(n.markdown),
|
||||
authors,
|
||||
url: `news/${titleToUrl(n.title)}`,
|
||||
};
|
||||
});
|
||||
|
@ -38,7 +34,11 @@ function titleToUrl(title: 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 = () => (
|
||||
|
@ -61,14 +61,13 @@ const NewsCard = ({ news }: NewsProps) => (
|
|||
{news.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>
|
||||
{news.preview && (
|
||||
<div
|
||||
className="text-sm text-gray-300"
|
||||
dangerouslySetInnerHTML={mdToHtml(news.preview)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Link
|
||||
to={news.url}
|
||||
|
@ -81,17 +80,6 @@ const NewsCard = ({ news }: NewsProps) => (
|
|||
</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> {
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Contact } from "./components/contact";
|
|||
import { Donate } from "./components/donate";
|
||||
import { News } from "./components/news";
|
||||
import { NewsItem } from "./components/news-item";
|
||||
import { Crypto } from "./components/crypto";
|
||||
|
||||
export const routes: IRouteProps[] = [
|
||||
{
|
||||
|
@ -48,4 +49,9 @@ export const routes: IRouteProps[] = [
|
|||
exact: true,
|
||||
component: Donate,
|
||||
},
|
||||
{
|
||||
path: `/crypto`,
|
||||
exact: true,
|
||||
component: Crypto,
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue