useful search feature
https://github.com/github/github-mcp-server is not a good mcp. It is better to encapsulate https://github.com/search into mcp.
import React, { useMemo, useState, useContext, useEffect } from "react";
/*************************
- MINI I18N (FR / EN) *************************/ const I18nContext = React.createContext({ lang: "fr", setLang: (_l) => {}, t: (k) => k });
function LanguageProvider({ children }) { const [lang, setLang] = useState("fr"); const dict = useMemo( () => ({ // Nav "nav.new": { fr: "Nouveautés", en: "New" }, "nav.categories": { fr: "Catégories", en: "Categories" }, "nav.bestsellers": { fr: "Best‑sellers", en: "Best‑sellers" }, "nav.faq": { fr: "FAQ", en: "FAQ" }, "nav.contact": { fr: "Contact", en: "Contact" },
// UI
"ui.paynow": { fr: "Payer par carte (Stripe)", en: "Pay by card (Stripe)" },
"ui.badge": { fr: "🚚 48–72h • 🔄 Retours 14j", en: "🚚 2–3 days • 🔄 14‑day returns" },
"ui.secure": { fr: "Paiement sécurisé", en: "Secure payment" },
// Hero
"hero.title": { fr: "Boutique Gen Z — petits prix, gros style", en: "Gen Z Shop — small prices, big style" },
"hero.tag": { fr: "Produits viraux US, livrés vite en France.", en: "Viral US products, shipped fast in EU." },
"hero.cta": { fr: "Voir les best‑sellers", en: "See best‑sellers" },
// Steamer
"steamer.title": { fr: "Spa maison 10 minutes — Résultat visible en 7 jours ✨", en: "At‑home spa in 10 minutes — Visible results in 7 days ✨" },
"steamer.desc": { fr: "Le Vapozone Peach diffuse une vapeur fine qui ouvre les pores, hydrate la peau et booste l’efficacité de tes soins.", en: "Peach facial steamer releases fine steam to open pores, hydrate skin and boost skincare effectiveness." },
"steamer.b1": { fr: "Résultat après 7 jours", en: "Results after 7 days" },
"steamer.b2": { fr: "Routine cocooning (aromathérapie possible)", en: "Cocooning routine (aromatherapy option)" },
"steamer.b3": { fr: "Luxe accessible", en: "Accessible luxury" },
// Projector
"proj.title": { fr: "Ton cinéma de poche 🎥 — ambiance instantanée", en: "Your pocket cinema 🎥 — instant vibes" },
"proj.desc": { fr: "Transforme ta chambre en salle de cinéma. Connecte ton smartphone et projette jusqu’à 120″.", en: "Turn your room into a theater. Connect your phone and project up to 120″." },
"proj.b1": { fr: "Ambiance immersive", en: "Immersive ambiance" },
"proj.b2": { fr: "Nomade & compact", en: "Portable & compact" },
"proj.b3": { fr: "Parfait pour TikTok", en: "Perfect for TikTok" },
// Charm
"charm.title": { fr: "Donne une âme à ton sac 🎒💖", en: "Give your bag a soul 🎒💖" },
"charm.desc": { fr: "Des peluches exubérantes à accrocher partout. Chaque charm = une vibe.", en: "Exuberant plush charms to clip anywhere. Each charm = a vibe." },
"charm.b1": { fr: "Ultra cute & fun", en: "Ultra cute & fun" },
"charm.b2": { fr: "Prix mini, grand effet", en: "Tiny price, big effect" },
"charm.b3": { fr: "Parfait pour stories", en: "Perfect for stories" },
// Hoodie
"hoodie.title": { fr: "L’oversize qui parle pour toi ✌️", en: "Oversize that speaks for you ✌️" },
"hoodie.desc": { fr: "Hoodie large, confortable, slogans audacieux. Inspiré street US, adopté par la Gen Z.", en: "Roomy, comfy hoodie with bold slogans. US street‑inspired, Gen Z‑approved." },
"hoodie.b1": { fr: "Style urbain affirmé", en: "Bold urban style" },
"hoodie.b2": { fr: "Confort premium", en: "Premium comfort" },
"hoodie.b3": { fr: "Identité mode Gen Z", en: "Gen Z fashion identity" },
// Neon
"neon.title": { fr: "Ta chambre, ton mood 💡✨", en: "Your room, your mood 💡✨" },
"neon.desc": { fr: "Néons design pour une vibe TikTok. Faciles à installer, personnalisables.", en: "Design neon lights for TikTok vibes. Easy to install, customizable." },
"neon.b1": { fr: "Ambiance personnalisée", en: "Personalized ambiance" },
"neon.b2": { fr: "Installation simple", en: "Simple setup" },
"neon.b3": { fr: "Top pour créateurs", en: "Great for creators" },
// Stand 360
"360.title": { fr: "Ton caméraman perso 🤳", en: "Your personal cameraman 🤳" },
"360.desc": { fr: "Filme tes TikToks/Reels sans galérer. Tracking 360° qui suit tes mouvements.", en: "Shoot TikToks/Reels effortlessly. 360° tracking follows your moves." },
"360.b1": { fr: "Contenu pro facilement", en: "Pro‑looking content easily" },
"360.b2": { fr: "Compact & léger", en: "Compact & lightweight" },
"360.b3": { fr: "Viral sur TikTok Shop", en: "Viral on TikTok Shop" },
// Contact
"contact.title": { fr: "Commander / Contact", en: "Order / Contact" },
"contact.name": { fr: "Nom", en: "Name" },
"contact.email": { fr: "Email", en: "Email" },
"contact.product": { fr: "Produit", en: "Product" },
"contact.msg": { fr: "Message", en: "Message" },
"contact.send": { fr: "Envoyer", en: "Send" },
}),
[]
); const t = (key) => (dict[key] ? dict[key][lang] : key); return ( <I18nContext.Provider value={{ lang, setLang, t }}>
/*************************
- PAIEMENT – STRIPE LINKS *************************/ const PAY = { STEAMER: "https://buy.stripe.com/XXX_STEAMER", // TODO: remplace par ton lien Stripe PROJECTOR: "https://buy.stripe.com/XXX_PROJECTOR", CHARM: "https://buy.stripe.com/XXX_CHARM", HOODIE: "https://buy.stripe.com/XXX_HOODIE", NEON: "https://buy.stripe.com/XXX_NEON", STAND360: "https://buy.stripe.com/XXX_STAND360", };
function StripeLinkButton({ href, label }) { const { t } = useI18n(); return ( <a href={href} target="_blank" rel="noopener noreferrer" className="inline-flex items-center justify-center rounded-2xl bg-indigo-600 px-5 py-3 text-white font-medium hover:brightness-110 active:scale-[.98]" > {label || t("ui.paynow")} ); }
/*************************
- COUNTDOWN (DROP)
*************************/
function Countdown({ targetISO }) {
const [left, setLeft] = useState(() => new Date(targetISO).getTime() - Date.now());
useEffect(() => {
const id = setInterval(() => setLeft(new Date(targetISO).getTime() - Date.now()), 1000);
return () => clearInterval(id);
}, [targetISO]);
if (left <= 0) return (
🔥 Drop en cours — stock limité !
); const s = Math.floor(left / 1000); const d = Math.floor(s / 86400); const h = Math.floor((s % 86400) / 3600); const m = Math.floor((s % 3600) / 60); return ( <div className="rounded-xl border border-amber-300 bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 px-4 py-3 text-sm"> ⏳ Drop dans {d}j {h}h {m}m {s % 60}s ); }
/*************************
- UI BASICS
*************************/
function LanguageSwitcher() {
const { lang, setLang } = useI18n();
return (
); }
function Navbar() { const { t } = useI18n(); return ( <header className="sticky top-0 z-40 backdrop-blur bg-white/70 dark:bg-slate-950/60 border-b border-slate-200 dark:border-slate-800"> <div className="mx-auto max-w-6xl px-4 h-14 flex items-center justify-between"> <a href="#" className="font-semibold">Kach Trends <nav className="hidden md:flex items-center gap-6 text-sm"> <a href="#bestsellers" className="hover:opacity-80">{t("nav.bestsellers")} <a href="#categories" className="hover:opacity-80">{t("nav.categories")} <a href="#faq" className="hover:opacity-80">{t("nav.faq")} <a href="#contact" className="hover:opacity-80">{t("nav.contact")} <LanguageSwitcher /> ); }
function Hero() { const { t } = useI18n(); return ( <section className="mx-auto max-w-6xl px-4 py-12 md:py-16"> <div className="grid lg:grid-cols-2 gap-8 items-center">
(produits / ambiance chambre) <div className="mt-6"> {/* Drop ce vendredi 18:00 heure Paris (exemple) */} <Countdown targetISO="2025-08-29T18:00:00+02:00" /> ); }
function Bullet({ children }) { return ( <li className="flex gap-2 text-sm">✅{children} ); }
function ProductSection({ id, title, desc, bullets, price, imgText, payHref, cta }) { return ( <section id={id} className="mx-auto max-w-6xl px-4 py-16 md:py-20"> <div className="grid gap-8 lg:grid-cols-2 items-start"> <div className="rounded-2xl overflow-hidden border border-slate-200 dark:border-slate-800 order-1 lg:order-2"> <div className="aspect-[4/3] bg-slate-100 dark:bg-slate-900 grid place-items-center text-slate-400"> <span className="p-6 text-center">{imgText} <div className="order-2 lg:order-1"> <h2 className="text-2xl md:text-3xl font-semibold">{title} <p className="mt-3 text-slate-600 dark:text-slate-300">{desc}
<ul className="mt-5 space-y-2"> {bullets.map((b, i) => ( <Bullet key={i}>{b}</Bullet> ))} <div className="mt-6 flex items-center gap-4"> <span className="text-2xl font-bold">{price} <div className="mt-4"> <StripeLinkButton href={payHref} label={cta} /> ); }function BestsellersGrid() { const items = [ { name: "Vapozone visage Peach — Spa maison", price: "34,99 €" }, { name: "Mini projecteur portable", price: "59,99 €" }, { name: "Bag charm plushie", price: "14,99 €" }, { name: "Hoodie oversize slogan", price: "49,99 €" }, { name: "LED néon déco", price: "29,99 €" }, { name: "Support téléphone 360°", price: "34,99 €" }, ]; return ( <section id="bestsellers" className="mx-auto max-w-6xl px-4 pb-6"> <h3 className="text-xl font-semibold mb-4">Best‑sellers <div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4"> {items.map((it) => ( <div key={it.name} className="rounded-2xl border border-slate-200 dark:border-slate-800 overflow-hidden"> <div className="aspect-[4/3] bg-slate-100 dark:bg-slate-900 grid place-items-center text-slate-400"> <span className="p-4 text-center">{it.name} <div className="p-4 flex items-center justify-between">
function CategoriesAnchor() { return ( <section id="categories" className="mx-auto max-w-6xl px-4 py-8"> <div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3 text-xs"> {[ { href: "#steamer", label: "Beauté" }, { href: "#projector", label: "Gadgets" }, { href: "#charm", label: "Accessoires" }, { href: "#hoodie", label: "Streetwear" }, { href: "#neon", label: "Lifestyle" }, { href: "#stand360", label: "Tech/Gaming" }, ].map((c) => ( <a key={c.href} href={c.href} className="rounded-xl border border-slate-200 dark:border-slate-800 px-3 py-2 text-center hover:bg-slate-50 dark:hover:bg-slate-900"> {c.label} ))} ); }
function Contact() { const { t } = useI18n(); return ( <section id="contact" className="mx-auto max-w-6xl px-4 py-16"> <h3 className="text-2xl md:text-3xl font-semibold">{t("contact.title")} <form className="mt-6 grid md:grid-cols-2 gap-4" action="mailto:[email protected]" method="post"> <input name="name" placeholder={t("contact.name")} className="rounded-xl border border-slate-300 dark:border-slate-700 bg-transparent px-4 py-3" /> <input type="email" name="email" placeholder={t("contact.email")} className="rounded-xl border border-slate-300 dark:border-slate-700 bg-transparent px-4 py-3" /> <select name="product" className="rounded-xl border border-slate-300 dark:border-slate-700 bg-transparent px-4 py-3"> <textarea name="message" placeholder={t("contact.msg")} rows={4} className="md:col-span-2 rounded-xl border border-slate-300 dark:border-slate-700 bg-transparent px-4 py-3" /> <button className="md:col-span-2 inline-flex items-center justify-center rounded-2xl bg-indigo-600 px-5 py-3 text-white font-medium hover:brightness-110"> {t("contact.send")} <p className="mt-3 text-xs text-slate-500">📌 Remplace l'adresse mail par la tienne. Pour un vrai panier + paiement, on utilise les boutons Stripe ci‑dessus.
); }function LegalPages() { return ( <> <section id="cgv" className="mx-auto max-w-6xl px-4 py-16"> <h3 className="text-2xl md:text-3xl font-semibold">Conditions Générales de Vente (CGV) <div className="mt-4 space-y-3 text-sm text-slate-700 dark:text-slate-300">
Prix & Paiement. Prix en EUR TTC. Règlement sécurisé via Stripe (cartes, Apple Pay/Google Pay). Les liens de paiement redirigent vers l’interface Stripe.
Livraison. Stock FR/UE : 48–72h ouvrées ; import direct : 7–10 jours ouvrés. Les délais sont estimatifs.
Retours. 14 jours pour changer d’avis (produit inutilisé, emballage d’origine). Remboursement après réception/contrôle.
SAV. Defaut produit : écris‑nous sous 48h avec photo/vidéo — échange ou remboursement selon cas.
Responsable légal. Kach Trends — Contact : [email protected]
<section id="privacy" className="bg-slate-50 dark:bg-slate-900/40">
<div className="mx-auto max-w-6xl px-4 py-16">
<h3 className="text-2xl md:text-3xl font-semibold">Politique de Confidentialité</h3>
<div className="mt-4 space-y-3 text-sm text-slate-700 dark:text-slate-300">
<p><strong>Données collectées.</strong> Formulaire (nom, e‑mail, message). Paiement hébergé par Stripe : nous ne stockons pas tes données de carte.</p>
<p><strong>Finalités.</strong> Traitement de commande, support client, statistiques anonymes de fréquentation.</p>
<p><strong>Conservation.</strong> Données de contact : 12 mois max. Tu peux demander l’accès/suppression : [email protected].</p>
</div>
</div>
</section>
<section id="mentions" className="mx-auto max-w-6xl px-4 py-16">
<h3 className="text-2xl md:text-3xl font-semibold">Mentions Légales</h3>
<p className="mt-4 text-sm text-slate-700 dark:text-slate-300">Éditeur : Kach Trends — e‑mail : [email protected] — Hébergeur : Vercel Inc.</p>
</section>
<section id="cookies" className="mx-auto max-w-6xl px-4 py-16">
<h3 className="text-2xl md:text-3xl font-semibold">Politique Cookies</h3>
<p className="mt-4 text-sm text-slate-700 dark:text-slate-300">Nous utilisons des cookies techniques (langue, thème) et, si activés par toi, des pixels d’analyse/ads (TikTok/Meta). Tu peux refuser via la bannière.</p>
</section>
</>
); }
function CookieBanner() { const [open, setOpen] = useState(false); useEffect(() => { const c = localStorage.getItem("cookie-consent-v1"); if (!c) setOpen(true); }, []); if (!open) return null; return ( <div className="fixed inset-x-2 bottom-2 z-50 rounded-2xl border border-slate-200 dark:border-slate-800 bg-white/90 dark:bg-slate-950/90 backdrop-blur p-4 shadow-lg"> <p className="text-sm">Cookies : techniques pour le site + mesure d’audience optionnelle. Tu peux accepter ou refuser.
<div className="mt-3 flex gap-2"> <button onClick={() => { localStorage.setItem("cookie-consent-v1","denied"); setOpen(false); }} className="px-3 py-2 rounded-xl border">Refuser <button onClick={() => { localStorage.setItem("cookie-consent-v1","granted"); setOpen(false); }} className="px-3 py-2 rounded-xl bg-indigo-600 text-white">Accepter <a href="#cookies" className="ml-auto text-sm underline">En savoir plus ); }function Footer() { return ( <footer className="border-t border-slate-200 dark:border-slate-800"> <div className="mx-auto max-w-6xl px-4 py-8 text-xs text-slate-500 grid md:grid-cols-3 gap-4">
<a className="underline" href="#cgv">CGV · <a className="underline" href="#privacy">Confidentialité · <a className="underline" href="#mentions">Mentions légales · <a className="underline" href="#cookies">Cookies
/*************************
-
PAGE PRINCIPALE *************************/ function Page() { const { t } = useI18n(); return (
{/* BEAUTÉ */}
{/* GADGETS */}
{/* ACCESSOIRES */}
{/* STREETWEAR */}
{/* LIFESTYLE */}
{/* TECH/GAMING */}
); }
export default function App() { return ( <LanguageProvider> <CookieBanner /> <Page /> <LegalPages /> </LanguageProvider> ); }
Hi @d0lwl0b - I was wondering if it would be possible to elaborate a bit more on what you'd like to be added to the GitHub MCP Server with regards to search?
Hi @d0lwl0b - I was wondering if it would be possible to elaborate a bit more on what you'd like to be added to the GitHub MCP Server with regards to search?
MCP needs a temporary search feature that leverages GitHub’s built-in search syntax and search capabilities.