Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/web/public/social/discord.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions apps/web/public/social/x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions apps/web/src/components/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ExternalLink from '@lucide/astro/icons/external-link';
import { GITHUB_REPO_URL, withBase } from '../lib/site';
import { HeaderActions } from './HeaderActions.tsx';
import { MobileChrome } from './MobileChrome.tsx';
import { SocialLinks } from './SocialLinks.tsx';

const homeHref = withBase();
const learnHref = withBase('learn');
Expand Down Expand Up @@ -45,6 +46,7 @@ function tabClass(active: boolean): string {
<ExternalLink class="h-3 w-3 text-accent" stroke-width={1.5} aria-hidden="true" />
<span class="sr-only">(opens in a new tab)</span>
</a>
<SocialLinks className="flex items-center gap-3" />
</nav>
<div class="hidden justify-self-end md:block">
<HeaderActions client:load />
Expand Down
7 changes: 7 additions & 0 deletions apps/web/src/components/MobileChrome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ExternalLink, Menu, X } from 'lucide-react';
import { WalletProviders } from './wallet/WalletProviders.tsx';
import { NetworkSwitch } from './NetworkSwitch.tsx';
import { ConnectButton } from './wallet/ConnectButton.tsx';
import { SocialLinks } from './SocialLinks.tsx';

export function MobileChrome({
learnHref,
Expand Down Expand Up @@ -89,6 +90,12 @@ export function MobileChrome({
<ExternalLink className="h-3.5 w-3.5 text-accent" strokeWidth={1.5} aria-hidden="true" />
<span className="sr-only">(opens in a new tab)</span>
</a>
<SocialLinks
labeled
className="flex flex-col gap-4"
iconClass="h-3.5 w-3.5"
linkClass="inline-flex items-center gap-1.5 text-sm tracking-[0.22em] text-white uppercase"
/>
</nav>
<div className="mt-6">
<NetworkSwitch />
Expand Down
46 changes: 46 additions & 0 deletions apps/web/src/components/SocialLinks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { DISCORD_URL, X_URL } from '../lib/site.ts';
import { SocialMark } from './SocialMark.tsx';

const ITEMS = [
{ name: 'discord' as const, href: DISCORD_URL, label: 'Discord' },
{ name: 'x' as const, href: X_URL, label: 'X' },
] as const;

export function SocialLinks({
labeled = false,
className,
iconClass,
linkClass,
}: {
labeled?: boolean;
className?: string;
iconClass?: string;
linkClass?: string;
}) {
const markClass = iconClass ?? (labeled ? 'h-3.5 w-3.5' : 'h-4 w-4');
const itemClass =
linkClass ??
(labeled
? 'inline-flex items-center gap-1.5 text-[0.65rem] font-normal tracking-[0.28em] text-white uppercase md:text-[0.7rem]'
: 'inline-flex items-center justify-center p-1 text-paper/80 hover:text-white focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent');

return (
<div role="group" aria-label="Social" className={className ?? 'flex items-center gap-3'}>
{ITEMS.map((item) => (
<a
key={item.name}
href={item.href}
rel="noopener noreferrer"
target="_blank"
className={itemClass}
>
<SocialMark name={item.name} className={markClass} />
{labeled ? item.label : null}
<span className="sr-only">
{labeled ? '(opens in a new tab)' : `${item.label} (opens in a new tab)`}
</span>
</a>
))}
</div>
);
}
16 changes: 16 additions & 0 deletions apps/web/src/components/SocialMark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { DISCORD_MARK_PATH, DISCORD_MARK_VIEWBOX, X_MARK_PATH, X_MARK_VIEWBOX } from '../lib/social.ts';

export function SocialMark({ name, className }: { name: 'discord' | 'x'; className?: string }) {
const viewBox = name === 'discord' ? DISCORD_MARK_VIEWBOX : X_MARK_VIEWBOX;
const path = name === 'discord' ? DISCORD_MARK_PATH : X_MARK_PATH;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox={viewBox}
className={className ? `shrink-0 ${className}` : 'shrink-0'}
aria-hidden="true"
>
<path d={path} fill="currentColor" />
</svg>
);
}
3 changes: 3 additions & 0 deletions apps/web/src/components/dashboard/DashboardApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { MIN_GAS_RESERVE_WEI } from '../../lib/slippage.ts';
import { simulateThenSend, waitOneConfirmation, type WalletWriter } from '../../lib/tx.ts';
import { isUserRejected, revertShortMessage } from '../../lib/errors.ts';
import { useLiveSnapshot } from '../useLiveSnapshot.ts';
import { SocialLinks } from '../SocialLinks.tsx';
import { WalletProviders } from '../wallet/WalletProviders.tsx';
import { WrongNetworkBanner } from '../wallet/WrongNetworkBanner.tsx';
import { BuryForm } from './BuryForm.tsx';
Expand Down Expand Up @@ -261,6 +262,7 @@ function DashboardBody() {
return (
<div className="px-5 py-10 md:px-10 md:py-14">
<RpcDown network={network} contracts={contracts} onRetry={retry} />
<SocialLinks className="mt-8 flex items-center gap-4" />
<MobileDock />
</div>
);
Expand Down Expand Up @@ -378,6 +380,7 @@ function DashboardBody() {
onChain={onChain}
nethBalance={nethBalance}
/>
<SocialLinks className="flex items-center gap-4 px-1 pt-1 md:pt-2" />
<MobileDock />
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/lib/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export const STATS: readonly Stat[] = [

export const GITHUB_REPO_FALLBACK = 'https://github.com/rastsislaux/nether';
export const GITHUB_REPO_URL = githubRepoUrl();
export const DISCORD_URL = 'https://discord.gg/N9mTHr5VE';
export const X_URL = 'https://x.com/netherprotocol';

export const RISK_WARNING =
'Capital at high risk, team does not hold any responsibility for possible losses. Hover for details.';
Expand Down
36 changes: 36 additions & 0 deletions apps/web/src/lib/social.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import assert from 'node:assert/strict';
import { existsSync, readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { describe, it } from 'node:test';
import { fileURLToPath } from 'node:url';
import { DISCORD_URL, X_URL } from './site.ts';
import {
DISCORD_MARK_FILE,
DISCORD_MARK_PATH,
DISCORD_MARK_VIEWBOX,
X_MARK_FILE,
X_MARK_PATH,
X_MARK_VIEWBOX,
} from './social.ts';

describe('social links', () => {
const publicDir = join(dirname(fileURLToPath(import.meta.url)), '../../public');

it('points at Nether Discord and X accounts', () => {
assert.equal(DISCORD_URL, 'https://discord.gg/N9mTHr5VE');
assert.equal(X_URL, 'https://x.com/netherprotocol');
});

it('publishes unmodified Discord and X marks', () => {
for (const [file, path, viewBox] of [
[DISCORD_MARK_FILE, DISCORD_MARK_PATH, DISCORD_MARK_VIEWBOX],
[X_MARK_FILE, X_MARK_PATH, X_MARK_VIEWBOX],
] as const) {
assert.equal(existsSync(join(publicDir, file)), true, file);
const svg = readFileSync(join(publicDir, file), 'utf8');
assert.ok(svg.includes(path));
assert.ok(svg.includes(`viewBox="${viewBox}"`));
assert.ok(svg.includes('fill="#000000"'));
}
});
});
11 changes: 11 additions & 0 deletions apps/web/src/lib/social.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const DISCORD_MARK_FILE = 'social/discord.svg';
export const X_MARK_FILE = 'social/x.svg';

export const DISCORD_MARK_VIEWBOX = '0 0 24 24';
export const X_MARK_VIEWBOX = '0 0 24 24';

export const DISCORD_MARK_PATH =
'M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z';

export const X_MARK_PATH =
'M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z';
2 changes: 2 additions & 0 deletions apps/web/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import FeatureIcon from '../components/FeatureIcons.astro';
import GraveCta from '../components/GraveCta.astro';
import { HolderStats } from '../components/HolderStats.tsx';
import RiskWarning from '../components/RiskWarning.astro';
import { SocialLinks } from '../components/SocialLinks.tsx';
import {
FEATURES,
HOLDER_COPY,
Expand Down Expand Up @@ -43,6 +44,7 @@ const heroSrc = withBase('hero.png');
>
{SECONDARY_CTA}
</a>
<SocialLinks className="flex items-center gap-3" iconClass="h-5 w-5" />
</div>
<div class="mt-4">
<RiskWarning />
Expand Down
58 changes: 57 additions & 1 deletion apps/web/src/pages/learn.astro
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
formatLearnNumber,
hasIndependentProductionAudit,
} from '../lib/learn';
import { GITHUB_REPO_URL, withBase } from '../lib/site';
import { DISCORD_URL, GITHUB_REPO_URL, X_URL, withBase } from '../lib/site';
import { SocialMark } from '../components/SocialMark.tsx';

const docsHref = withBase('docs');
const specHref = withBase('docs/protocol-spec');
Expand Down Expand Up @@ -138,6 +139,7 @@ const toc = [
{ href: '#strategy-losses', label: 'Strategy losses' },
{ href: '#allocation', label: 'Token allocation' },
{ href: '#faq', label: 'FAQ' },
{ href: '#community', label: 'Questions' },
{ href: '#risks', label: 'Risks' },
{ href: '#verify', label: 'Verify it' },
] as const;
Expand Down Expand Up @@ -684,6 +686,24 @@ const toc = [
)
}
</FaqItem>
<FaqItem question="Where can I ask questions?">
<p>
If you have questions, you can ask them in{' '}
<a href={DISCORD_URL} rel="noopener noreferrer" target="_blank">
Nether's Discord
<span class="sr-only">, opens in a new tab</span>
</a>
.
</p>
<p>
Protocol updates are also posted on{' '}
<a href={X_URL} rel="noopener noreferrer" target="_blank">
X
<span class="sr-only">, opens in a new tab</span>
</a>
.
</p>
</FaqItem>
<FaqItem question="Where can I verify the protocol?">
<ul>
<li>
Expand Down Expand Up @@ -711,6 +731,42 @@ const toc = [
</div>
</section>

<section class="learn-section" id="community" aria-labelledby="learn-community">
<h2 id="learn-community" class="learn-heading">Questions?</h2>
<p class="mt-4 max-w-2xl text-sm leading-relaxed text-paper">
If you have questions, you can ask them in Nether's Discord. Follow along on X for updates.
</p>
<div class="mt-8 grid gap-4 md:grid-cols-2">
<a
class="learn-card learn-card-link"
href={DISCORD_URL}
rel="noopener noreferrer"
target="_blank"
>
<SocialMark name="discord" className="h-6 w-6 text-white" />
<h3 class="mt-3 text-[0.7rem] tracking-[0.22em] text-accent uppercase">
Discord
<ExternalLink class="ml-1.5 inline h-3.5 w-3.5 align-[-0.1em]" stroke-width={1.5} />
</h3>
<p class="mt-2 text-sm leading-relaxed text-paper/90">
Ask questions in Nether's Discord community.
</p>
<span class="sr-only">, opens in a new tab</span>
</a>
<a class="learn-card learn-card-link" href={X_URL} rel="noopener noreferrer" target="_blank">
<SocialMark name="x" className="h-6 w-6 text-white" />
<h3 class="mt-3 text-[0.7rem] tracking-[0.22em] text-accent uppercase">
X
<ExternalLink class="ml-1.5 inline h-3.5 w-3.5 align-[-0.1em]" stroke-width={1.5} />
</h3>
<p class="mt-2 text-sm leading-relaxed text-paper/90">
Follow @netherprotocol for protocol updates.
</p>
<span class="sr-only">, opens in a new tab</span>
</a>
</div>
</section>

<section class="learn-section learn-risks" id="risks" aria-labelledby="learn-risks">
<h2 id="learn-risks" class="learn-heading">Understand the risks</h2>
<p class="mt-4 max-w-2xl text-sm leading-relaxed text-paper">
Expand Down
Loading