diff --git a/messages/en-US.json b/messages/en-US.json index 77fbdb3..d490ea1 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -54,7 +54,9 @@ "pre": "Ink, the Ethereum L2 unleashed by Kraken, is live on the Superchain", "title": "Ink the future", "tagLine": "Simplified DeFi for|builders,degens,gigachads,institutions,normies,ALL", - "cta:exploreApps": "Explore Apps" + "cta:exploreApps": "Explore Apps", + "appsTitle": "Featured apps on Ink", + "appsCta": "View all apps" }, "Community": { "title": "Join the Ink Community", @@ -64,7 +66,7 @@ "description": "Join the Ink community, vibe with fellow developers and get support" }, "twitter": { - "title": "Follow us on Twitter", + "title": "Follow us on X", "description": "Stay tuned to receive all ink updates first hand" }, "discord": { @@ -87,7 +89,7 @@ }, "Verify": { "title": "Get Verified and Start Your On-Chain Journey Today", - "description": "Ink Verify — Seamlessly authenticate your activity, unlock rewards, and explore the limitless potential of Ink", + "description": "Ink Verify — Seamlessly authenticate your activity, unlock rewards, and explore the limitless potential of Ink.", "cta": "Connect to verify", "whatIsVerify": { "title": "What is Ink Verify?", @@ -103,12 +105,12 @@ }, "haveASuggestion": { "title": "Have a suggestion?", - "description": "Ink Verify is a tool for both users and developers! Have a suggestion? Reach out to the Ink team to request additional categories here", + "description": "Ink Verify is a tool for both users and developers! Have a suggestion? Reach out to the Ink team to request additional categories here.", "contactTeam": "Contact Team" }, "verifications": { "title": "Available verifications", - "description": "Discover the latest verifications on Ink" + "description": "Discover the latest verifications on Ink." } }, "About": { diff --git a/public/ink-the-future.png b/public/ink-the-future.png deleted file mode 100644 index a610c1b..0000000 Binary files a/public/ink-the-future.png and /dev/null differ diff --git a/public/ink-the-future.webp b/public/ink-the-future.webp new file mode 100644 index 0000000..98e5ec1 Binary files /dev/null and b/public/ink-the-future.webp differ diff --git a/public/logo/ink-mark-dark.png b/public/logo/ink-mark-dark.png deleted file mode 100644 index a17a65d..0000000 Binary files a/public/logo/ink-mark-dark.png and /dev/null differ diff --git a/public/logo/ink-mark-dark.webp b/public/logo/ink-mark-dark.webp new file mode 100644 index 0000000..57347cc Binary files /dev/null and b/public/logo/ink-mark-dark.webp differ diff --git a/public/logo/ink-mark-light.png b/public/logo/ink-mark-light.png deleted file mode 100644 index 982297e..0000000 Binary files a/public/logo/ink-mark-light.png and /dev/null differ diff --git a/public/logo/ink-mark-light.webp b/public/logo/ink-mark-light.webp new file mode 100644 index 0000000..48c5b7a Binary files /dev/null and b/public/logo/ink-mark-light.webp differ diff --git a/scripts/image-to-webp.js b/scripts/image-to-webp.js index 3c418b2..a209d58 100644 --- a/scripts/image-to-webp.js +++ b/scripts/image-to-webp.js @@ -9,29 +9,40 @@ const sharp = require("sharp"); const ROOT = path.join(__dirname, ".."); +async function processImage(imagePath, file) { + if (file.endsWith(".webp")) { + return false; + } + + const imagePathWithNewExtension = path.join( + imagePath, + `${file.split(".")[0]}.webp` + ); + await sharp(path.join(imagePath, file)) + .webp() + .toFile(imagePathWithNewExtension); + await fs.unlink(path.join(imagePath, file)); +} + const run = async () => { const imagePath = path.join(__dirname, "..", imagePathArg); - const imagesInFolder = await fs.readdir(imagePath); - - const processedImages = await Promise.all( - imagesInFolder.map(async (file) => { - if (file.endsWith(".webp")) { - return false; - } - - const imagePathWithNewExtension = path.join( - imagePath, - `${file.split(".")[0]}.webp` - ); - await sharp(path.join(imagePath, file)) - .webp() - .toFile(imagePathWithNewExtension); - await fs.unlink(path.join(imagePath, file)); - return true; - }) - ); - console.debug("Processed images:", processedImages.filter(Boolean).length); + if ((await fs.stat(imagePath)).isDirectory()) { + const imagesInFolder = await fs.readdir(imagePath); + const processedImages = await Promise.all( + imagesInFolder.map(async (file) => { + await processImage(imagePath, file); + return true; + }) + ); + + console.debug("Processed images:", processedImages.filter(Boolean).length); + } else { + const path = imagePath.split("/").slice(0, -1).join("/"); + const file = imagePath.split("/").pop(); + await processImage(path, file); + console.debug("Processed image:", imagePath); + } }; run(); diff --git a/src/app/[locale]/_components/Home/HomeApps.tsx b/src/app/[locale]/_components/Home/HomeApps.tsx index 96982a8..fc747ab 100644 --- a/src/app/[locale]/_components/Home/HomeApps.tsx +++ b/src/app/[locale]/_components/Home/HomeApps.tsx @@ -1,5 +1,6 @@ "use client"; import { Button } from "@inkonchain/ink-kit"; +import { useTranslations } from "next-intl"; import { ColoredText } from "@/components/ColoredText"; import { newLayoutSectionClasses } from "@/components/styles/container"; @@ -10,15 +11,16 @@ import { AppsGrid } from "../../apps/_components/AppsGrid"; import { inkHomeApps } from "../../apps/_components/InkApp"; export const HomeApps = () => { + const t = useTranslations("Home"); const query = useRouterQuery(); return (
- Discover apps on Ink + {t("appsTitle")}
{ + const t = useTranslations("Home"); + return ( +
+
+ a lightning bolt in a circle +
{t("pre")}
+
+
+ ); +}; diff --git a/src/app/[locale]/_components/Home/HomeTagLine.tsx b/src/app/[locale]/_components/Home/HomeTagLine.tsx index b2059ec..927ea97 100644 --- a/src/app/[locale]/_components/Home/HomeTagLine.tsx +++ b/src/app/[locale]/_components/Home/HomeTagLine.tsx @@ -9,7 +9,7 @@ export const HomeTagLine = () => { + The future isn't written,
it's waiting to be inked. diff --git a/src/app/[locale]/_components/Home/HomeTitle.tsx b/src/app/[locale]/_components/Home/HomeTitle.tsx index aafe5e9..27b7c61 100644 --- a/src/app/[locale]/_components/Home/HomeTitle.tsx +++ b/src/app/[locale]/_components/Home/HomeTitle.tsx @@ -1,6 +1,5 @@ "use client"; import { Button, InkIcon } from "@inkonchain/ink-kit"; -import Image from "next/image"; import { useTranslations } from "next-intl"; import { ColoredText } from "@/components/ColoredText"; @@ -16,17 +15,6 @@ export const HomeTitle = () => { return ( <> - a lighting bolt in a circle -
{t("pre")}
-
- } title="Ink the future" description={} cta={ diff --git a/src/app/[locale]/_components/InkLogo.tsx b/src/app/[locale]/_components/InkLogo.tsx index c3b38b8..6239075 100644 --- a/src/app/[locale]/_components/InkLogo.tsx +++ b/src/app/[locale]/_components/InkLogo.tsx @@ -31,14 +31,14 @@ export const InkLogoImage: React.FC = () => { return ( <> Ink Logo Ink Logo { return ( @@ -32,11 +30,6 @@ export const PageHeader = ({ "max-w-screen-2xl": size === "home", })} > - {pre && ( -
- {pre} -
- )} 0) || + (filters.tags && filters.tags.length > 0) + ); +} + +function hasActiveFiltersOrSearch(filters: InkAppFilters): boolean { + return !!filters.search || hasActiveFilters(filters); +} + export function AppsContent({ currentCategory }: AppsContentProps) { const searchParams = useSearchParams(); const network = getNetwork(searchParams.get("network")); const category = currentCategory || searchParams.get("category"); const tags = searchParams.get("tags"); - + const search = searchParams.get("search"); const [page, setPage] = useState(0); - const [search, setSearch] = useState(""); - const [filters, setFilters] = useState>({ + const [filters, setFilters] = useState({ + search: search || "", categories: category ? category.split(",") : [], tags: tags ? tags.split(",") : [], network: network ? network : "Mainnet", @@ -68,6 +80,14 @@ export function AppsContent({ currentCategory }: AppsContentProps) { ) return false; + if (hasActiveFiltersOrSearch(filters)) { + if ( + inkFeaturedApps.some((featuredApp) => featuredApp.id === app.id) + ) { + return true; + } + } + return true; }), [filters] @@ -76,7 +96,7 @@ export function AppsContent({ currentCategory }: AppsContentProps) { const filteredApps = useMemo( () => filteredAppsWithoutSearchTerms.filter((app) => { - const searchTerm = search.toLowerCase(); + const searchTerm = filters.search.toLowerCase(); if ( searchTerm && !app.name.toLowerCase().includes(searchTerm) && @@ -89,14 +109,18 @@ export function AppsContent({ currentCategory }: AppsContentProps) { return false; return true; }), - [filteredAppsWithoutSearchTerms, search] + [filteredAppsWithoutSearchTerms, filters.search] ); const updateSearchParams = useCallback( (newParams: Record) => { - const { network, category, tags, ...params } = Object.fromEntries( - searchParams.entries() - ); + const { + network, + category, + tags, + search: _search, + ...params + } = Object.fromEntries(searchParams.entries()); const { category: newCategory, ...newParamsToUpdate } = newParams; const queryParams = new URLSearchParams({ ...params, @@ -126,6 +150,9 @@ export function AppsContent({ currentCategory }: AppsContentProps) { ...(mergedFilters.categories && mergedFilters.categories.length > 0 ? { category: mergedFilters.categories[0] } : {}), + ...(mergedFilters.search && mergedFilters.search.length > 0 + ? { search: mergedFilters.search } + : {}), }); setPage(0); @@ -135,15 +162,6 @@ export function AppsContent({ currentCategory }: AppsContentProps) { [updateSearchParams] ); - const hasActiveFilters = (filters: InkAppFilters): boolean => { - return ( - !!search || - (filters.network && filters.network !== "Mainnet") || - (filters.categories && filters.categories.length > 0) || - (filters.tags && filters.tags.length > 0) - ); - }; - const appsToDisplay = useMemo( () => filteredApps.slice(0, (page + 1) * 10), [filteredApps, page] @@ -163,8 +181,10 @@ export function AppsContent({ currentCategory }: AppsContentProps) { { + updateFilters({ search: value }); + }} /> @@ -208,11 +228,13 @@ export function AppsContent({ currentCategory }: AppsContentProps) { > setSearch("")} + hasSearch={!!filters.search} + resetSearch={() => updateFilters({ search: "" })} hasActiveFilters={hasActiveFilters(filters)} resetFilters={() => { updateFilters({ @@ -255,10 +277,10 @@ function NoAppsFound({ return (
-
+
No matches found
-
+
{`Please change your keywords${ hasActiveFilters ? " or reset your filters" : "" } and try again`} diff --git a/src/app/[locale]/apps/_components/AppsGrid.tsx b/src/app/[locale]/apps/_components/AppsGrid.tsx index d8bf6f7..d6052f1 100644 --- a/src/app/[locale]/apps/_components/AppsGrid.tsx +++ b/src/app/[locale]/apps/_components/AppsGrid.tsx @@ -3,8 +3,10 @@ import { Tag } from "@inkonchain/ink-kit"; import Image from "next/image"; import { useTranslations } from "next-intl"; +import { classNames } from "@/util/classes"; + import { AppLinks } from "./AppLinks"; -import { InkApp, InkAppNetwork, mainUrl } from "./InkApp"; +import { InkApp, InkAppNetwork, inkTransparentIcons, mainUrl } from "./InkApp"; export const AppsGrid: React.FC<{ apps: InkApp[]; @@ -50,7 +52,11 @@ function AppCard({ }} >
-
+
{"dapps "superswap", ].includes(a.id) ); +export const inkTransparentIcons: string[] = []; export const inkTags: string[] = apps.reduce((acc, app) => { app.tags.forEach((tag) => { if (!acc.includes(tag)) { @@ -75,6 +76,7 @@ export const inkTags: string[] = apps.reduce((acc, app) => { }, [] as string[]); export interface InkAppFilters { + search: string; categories: string[]; tags: string[]; network?: InkAppNetwork; diff --git a/src/app/[locale]/apps/_components/apps-data.json b/src/app/[locale]/apps/_components/apps-data.json index 56bb253..72e5dde 100644 --- a/src/app/[locale]/apps/_components/apps-data.json +++ b/src/app/[locale]/apps/_components/apps-data.json @@ -47,7 +47,7 @@ { "id": "astra-swap", "name": "Astra Swap", - "description": "Trade, earn, and own crypto on the all-in-one multichain DEX", + "description": "Trade, earn, and own crypto on the all-in-one multichain DEX.", "imageUrl": "/featured-apps/icons/astraswap.webp", "category": [ "DeFi" @@ -138,7 +138,7 @@ { "id": "comet-protocol", "name": "Comet Protocol", - "description": "Bridge to other chains", + "description": "Bridge to other chains.", "imageUrl": "/featured-apps/icons/cometprotocol.webp", "category": [ "Bridge" @@ -160,7 +160,7 @@ { "id": "curve", "name": "Curve", - "description": "Creating deep on-chain liquidity using advanced bonding curves", + "description": "Creating deep on-chain liquidity using advanced bonding curves.", "imageUrl": "/featured-apps/icons/curve.webp", "category": [ "DeFi" @@ -182,7 +182,7 @@ { "id": "deep-on-ink", "name": "The Deep", - "description": "Dive into DeFi on Ink", + "description": "Dive into DeFi on Ink.", "imageUrl": "/featured-apps/icons/thedeep.webp", "category": [ "DeFi" @@ -226,7 +226,7 @@ { "id": "dune", "name": "Dune", - "description": "Query, visualize, share and export data across 75+ blockchains — build together with Web3’s biggest data community.", + "description": "Query, visualize, share and export data across 75+ blockchains — build together with Web3's biggest data community.", "imageUrl": "/featured-apps/icons/dune.webp", "category": [ "Infra" @@ -249,7 +249,7 @@ { "id": "dyorswap", "name": "DYORSWAP", - "description": "DYORSWAP is a multi-chain decentralized exchange (DEX) operating on multichain .", + "description": "DYORSWAP is a multi-chain decentralized exchange (DEX) operating on multichain.", "imageUrl": "/featured-apps/icons/dyorswap.webp", "category": [ "DeFi" @@ -294,7 +294,7 @@ { "id": "frax", "name": "Frax", - "description": "The Decentralized Central Bank of Crypto", + "description": "The Decentralized Central Bank of Crypto.", "imageUrl": "/featured-apps/icons/frax.webp", "category": [ "DeFi" @@ -340,7 +340,7 @@ { "id": "gelato", "name": "Gelato", - "description": "Build scalable, custom enterprise-grade Rollups with Gelato's Web3 Services natively integrated", + "description": "Build scalable, custom enterprise-grade Rollups with Gelato's Web3 Services natively integrated.", "imageUrl": "/featured-apps/icons/gelato.webp", "category": [ "Bridge" @@ -407,7 +407,7 @@ { "id": "holyheld", "name": "Holyheld", - "description": "One card for all crypto", + "description": "One card for all crypto.", "imageUrl": "/featured-apps/icons/holyheld.webp", "category": [ "Other", @@ -477,7 +477,7 @@ { "id": "inkypump", "name": "InkyPump", - "description": "The first pump.fun-style protocol on Ink Network (Kraken's L2). Users can instantly create tokens by choosing a name, ticker, and JPG image. ", + "description": "The first pump.fun-style protocol on Ink Network (Kraken's L2). Users can instantly create tokens by choosing a name, ticker, and JPG image.", "imageUrl": "/featured-apps/icons/inkypump.webp", "category": [ "DeFi" @@ -546,7 +546,7 @@ { "id": "kraken", "name": "Kraken", - "description": "Kraken is your bridge to the world of crypto. Spot, Futures, Margin, NFTs, Staking & OTC Buy, sell, trade, earn, explore and learn", + "description": "Kraken is your bridge to the world of crypto. Spot, Futures, Margin, NFTs, Staking & OTC Buy, sell, trade, earn, explore and learn.", "imageUrl": "https://cdn.sanity.io/images/51n36hrp/facade/a925939f448a3a410f4f32334165623ad4cccba1-512x512.svg", "category": [ "On-ramps" @@ -590,7 +590,7 @@ { "id": "layerzero", "name": "LayerZero", - "description": "LayerZero is a technology that enables applications to move data across blockchains, uniquely supporting censorship-resistant messages and permissionless development through immutable smart contracts", + "description": "LayerZero is a technology that enables applications to move data across blockchains, uniquely supporting censorship-resistant messages and permissionless development through immutable smart contracts.", "imageUrl": "/featured-apps/icons/layerzero.webp", "category": [ "Infra" @@ -613,7 +613,7 @@ { "id": "meme-bridge", "name": "Meme Bridge", - "description": "The cheapest Layer2 bridge. Earn points and bridge through Layer2s within seconds", + "description": "The cheapest Layer2 bridge. Earn points and bridge through Layer2s within seconds.", "imageUrl": "/featured-apps/icons/meme-bridge.webp", "category": [ "Bridge" @@ -636,7 +636,7 @@ { "id": "merkly", "name": "Merkly", - "description": "Multifunctional Interoperability Platform | Bridge & Refuel across 50+ Chains", + "description": "Multifunctional Interoperability Platform | Bridge & Refuel across 50+ Chains.", "imageUrl": "/featured-apps/icons/merkly.webp", "category": [ "Bridge" @@ -659,7 +659,7 @@ { "id": "mini-bridge", "name": "Mini Bridge", - "description": "MiniBridge is a \"zero-fee\" cross-chain tool that offers multi-chain support for BTC/EVM/non-EVM and features such as fast transactions. ", + "description": "MiniBridge is a \"zero-fee\" cross-chain tool that offers multi-chain support for BTC/EVM/non-EVM and features such as fast transactions.", "imageUrl": "/featured-apps/icons/mini-bridge.webp", "category": [ "Bridge" @@ -888,7 +888,7 @@ { "id": "reservoir:-relay", "name": "Reservoir: Relay", - "description": "Instant, low-cost bridging\nand swapping", + "description": "Instant, low-cost bridging\nand swapping.", "imageUrl": "/featured-apps/icons/reservoir_relay.webp", "category": [ "Bridge" @@ -910,7 +910,7 @@ { "id": "reservoir:-swap", "name": "Reservoir: Swap", - "description": "Buy, sell & trade Ethereum and other top tokens on Swap", + "description": "Buy, sell & trade Ethereum and other top tokens on Swap.", "imageUrl": "/featured-apps/icons/reservoir_swap.webp", "category": [ "DeFi" @@ -998,7 +998,7 @@ { "id": "squidswap", "name": "SquidSwap", - "description": "SquidSwap is designed to provide a secure and efficient way to launch, lock, and trade tokens. ", + "description": "SquidSwap is designed to provide a secure and efficient way to launch, lock, and trade tokens.", "imageUrl": "/featured-apps/icons/squidswap.webp", "category": [ "DeFi", @@ -1137,7 +1137,7 @@ { "id": "token-deployer", "name": "Token Deployer", - "description": "1-click token deployer", + "description": "1-click token deployer.", "imageUrl": "", "category": [ "DeFi" @@ -1182,7 +1182,7 @@ { "id": "trade-on-ink", "name": "Trade On INK", - "description": "A fast and secure telegram trading bot for INK, enabling instant token buys and sells with real-time transaction tracking and no private key storage", + "description": "A fast and secure telegram trading bot for INK, enabling instant token buys and sells with real-time transaction tracking and no private key storage.", "imageUrl": "/featured-apps/icons/trade-on-ink.webp", "category": [ "Bridge" @@ -1271,7 +1271,7 @@ { "id": "zkcodex-wallet-tracker", "name": "zkCodex Wallet Tracker", - "description": "zkCodex is a comprehensive wallet analysis platform for Layer 2. Track transaction volume, Chain Score, NFTs, DApp interactions, and airdrop eligibility across 15+ blockchains with ease and efficiency", + "description": "zkCodex is a comprehensive wallet analysis platform for Layer 2. Track transaction volume, Chain Score, NFTs, DApp interactions, and airdrop eligibility across 15+ blockchains with ease and efficiency.", "imageUrl": "/featured-apps/icons/zkcodex-wallet-tracker.webp", "category": [ "Infra", @@ -1296,7 +1296,7 @@ { "id": "zns-connect", "name": "ZNS Connect", - "description": "Decentralized ID platform powered by decentralized addresses", + "description": "Decentralized ID platform powered by decentralized addresses.", "imageUrl": "/featured-apps/icons/znsconnect.webp", "category": [ "Social" diff --git a/src/app/[locale]/builders/_components/DeveloperContent.tsx b/src/app/[locale]/builders/_components/DeveloperContent.tsx index 0a46a17..ff06385 100644 --- a/src/app/[locale]/builders/_components/DeveloperContent.tsx +++ b/src/app/[locale]/builders/_components/DeveloperContent.tsx @@ -44,9 +44,9 @@ export const DeveloperContent = () => { revolutions.

- Our commitment to builders: Ink will provide you with a world- - class development environment, complete with the tools, support, - and users you need to bring your ideas to life. + Our commitment to builders: Ink will provide you with a + world-class development environment, complete with the tools, + support, and users you need to bring your ideas to life.

{isMainnet ? ( diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 10da9f3..9fc765e 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -6,6 +6,7 @@ import { newLayoutContainerClasses } from "@/components/styles/container"; import { HomeApps } from "./_components/Home/HomeApps"; import { HomeEvent } from "./_components/Home/HomeEvent"; +import { HomeSmallTag } from "./_components/Home/HomeSmallTag"; import { HomeTagLine } from "./_components/Home/HomeTagLine"; import { HomeTitle } from "./_components/Home/HomeTitle"; @@ -52,6 +53,7 @@ export default async function HomePage() {

+ diff --git a/src/app/globals.css b/src/app/globals.css index cd52dfe..76cee6d 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -202,7 +202,13 @@ div[type="button"] > button { font-weight: 700 !important; } -/* A fix that must be applied to all h2 so that they don't cut off the text */ +/* A fix that must be applied to all h- so that they don't cut off the text */ +.ink\:text-h1 { + margin-top: -4px; + margin-bottom: -4px; + line-height: calc(var(--ink-text-h1--line-height) + 16px); +} + .ink\:text-h2 { margin-top: -12px; margin-bottom: -12px; diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index cd0aaab..4970305 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -20,7 +20,8 @@ export const Footer = () => {
-
+ {/** Need a pt-1 here to align the "Terms of Service" text with the images (since the images are _exactly_ at 0px from the top, contrary to standard text) */} +