👁️
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

search primer!

+291 -3
+284
src/components/SearchPrimer.tsx
··· 1 + import { Link } from "@tanstack/react-router"; 2 + import { CardSymbol } from "./CardSymbol"; 3 + 4 + function Code({ children }: { children: React.ReactNode }) { 5 + return ( 6 + <code className="font-mono text-sm bg-gray-200 dark:bg-slate-700 px-1.5 py-0.5 rounded text-gray-800 dark:text-gray-200"> 7 + {children} 8 + </code> 9 + ); 10 + } 11 + 12 + function Q({ q }: { q: string }) { 13 + return ( 14 + <Link 15 + to="/cards" 16 + search={{ q, sort: undefined, sort2: undefined }} 17 + className="font-mono text-sm bg-gray-200 dark:bg-slate-700 px-1.5 py-0.5 rounded text-cyan-700 dark:text-cyan-300 hover:bg-cyan-100 dark:hover:bg-cyan-900/50 transition-colors" 18 + > 19 + {q} 20 + </Link> 21 + ); 22 + } 23 + 24 + function MainCard({ 25 + title, 26 + children, 27 + className = "", 28 + }: { 29 + title: string; 30 + children: React.ReactNode; 31 + className?: string; 32 + }) { 33 + return ( 34 + <div 35 + className={`bg-gray-50 dark:bg-slate-800/50 border border-gray-200 dark:border-slate-700 rounded-lg p-4 ${className}`} 36 + > 37 + <h3 className="font-semibold text-gray-900 dark:text-white mb-2"> 38 + {title} 39 + </h3> 40 + {children} 41 + </div> 42 + ); 43 + } 44 + 45 + function SecondaryCard({ 46 + title, 47 + children, 48 + className = "", 49 + }: { 50 + title: string; 51 + children: React.ReactNode; 52 + className?: string; 53 + }) { 54 + return ( 55 + <div 56 + className={`bg-gray-50/50 dark:bg-slate-800/30 border border-gray-200/50 dark:border-slate-700/50 rounded-lg p-3 ${className}`} 57 + > 58 + <h4 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2"> 59 + {title} 60 + </h4> 61 + {children} 62 + </div> 63 + ); 64 + } 65 + 66 + function Mana({ s }: { s: string }) { 67 + return ( 68 + <CardSymbol symbol={s} size="text" className="inline align-[-0.125em]" /> 69 + ); 70 + } 71 + 72 + export function SearchPrimer() { 73 + return ( 74 + <div className="space-y-4"> 75 + {/* Intro blurb */} 76 + <div className="text-sm text-gray-600 dark:text-gray-400 space-y-1"> 77 + <p> 78 + Type anything to search by name—we'll find close matches even with 79 + typos. 80 + </p> 81 + <p> 82 + Use <Code>field:value</Code> syntax for precise filtering. Multiple 83 + filters are combined with AND. 84 + </p> 85 + </div> 86 + 87 + <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"> 88 + {/* Fields with examples */} 89 + <MainCard title="Filter by..."> 90 + <ul className="space-y-1 text-sm text-gray-600 dark:text-gray-300"> 91 + <li> 92 + <Q q="t:vampire" /> type 93 + </li> 94 + <li> 95 + <Q q='o:"draw a card"' /> rules text 96 + </li> 97 + <li> 98 + <Q q="mv<=3" /> mana value 99 + </li> 100 + <li> 101 + <Q q="power>=4" /> power 102 + </li> 103 + <li> 104 + <Q q="r:mythic" /> rarity 105 + </li> 106 + <li> 107 + <Q q="s:mh3" /> set code 108 + </li> 109 + <li> 110 + <Q q="f:modern" /> format legal 111 + </li> 112 + <li> 113 + <Q q="loyalty>=5" /> loyalty 114 + </li> 115 + <li> 116 + <Q q="name:dragon" /> name contains 117 + </li> 118 + </ul> 119 + </MainCard> 120 + 121 + {/* Operators */} 122 + <MainCard title="Comparisons"> 123 + <ul className="space-y-1 text-sm text-gray-600 dark:text-gray-300"> 124 + <li> 125 + <Q q="manavalue<3" /> less than 126 + </li> 127 + <li> 128 + <Q q="manavalue>=5" /> at least 129 + </li> 130 + <li> 131 + <Q q="power>5" /> greater than 132 + </li> 133 + <li> 134 + <Q q="toughness<=2" /> at most 135 + </li> 136 + <li> 137 + <Q q="o:/\{(.)\}\{\1\}/" /> regex w/ backrefs 138 + </li> 139 + </ul> 140 + </MainCard> 141 + 142 + {/* Colors - clearer framing */} 143 + <MainCard title="Colors" className="sm:row-span-2 lg:row-span-1"> 144 + <div className="space-y-3 text-sm text-gray-600 dark:text-gray-300"> 145 + {/* Color codes */} 146 + <div className="flex flex-wrap gap-x-3 gap-y-1"> 147 + <span> 148 + <Mana s="W" /> <span className="font-black">w</span>hite 149 + </span> 150 + <span> 151 + <Mana s="U" /> bl<span className="font-black">u</span>e 152 + </span> 153 + <span> 154 + <Mana s="B" /> <span className="font-black">b</span>lack 155 + </span> 156 + <span> 157 + <Mana s="R" /> <span className="font-black">r</span>ed 158 + </span> 159 + <span> 160 + <Mana s="G" /> <span className="font-black">g</span>reen 161 + </span> 162 + <span> 163 + <Mana s="C" /> <span className="font-black">c</span>olorless 164 + </span> 165 + </div> 166 + 167 + {/* Card's colors */} 168 + <div> 169 + <p className="text-gray-500 dark:text-gray-400 text-xs uppercase tracking-wide mb-1"> 170 + Card's colors 171 + </p> 172 + <p> 173 + <Q q="c:ug" /> is both <Mana s="U" /> and <Mana s="G" /> 174 + </p> 175 + <p> 176 + <Q q="c=r" /> is exactly <Mana s="R" /> (mono-red) 177 + </p> 178 + </div> 179 + 180 + {/* Color identity for commander */} 181 + <div> 182 + <p className="text-gray-500 dark:text-gray-400 text-xs uppercase tracking-wide mb-1"> 183 + For commander decks 184 + </p> 185 + <p> 186 + <Q q="id<=wu" /> goes in <Mana s="W" /> 187 + <Mana s="U" /> decks 188 + </p> 189 + <p> 190 + <Q q="id>=2 is:commander" /> 2+ color commanders 191 + </p> 192 + <p> 193 + <Q q="id>=rw is:paupercommander" /> PEDH in <Mana s="R" /> 194 + <Mana s="W" /> 195 + </p> 196 + </div> 197 + </div> 198 + </MainCard> 199 + 200 + {/* Combining */} 201 + <MainCard title="Combining Filters"> 202 + <ul className="space-y-1 text-sm text-gray-600 dark:text-gray-300"> 203 + <li> 204 + <Q q="t:goblin r:rare" /> both (AND) 205 + </li> 206 + <li> 207 + <Q q="t:elf OR t:druid" /> either 208 + </li> 209 + <li> 210 + <Q q="t:creature -c:g" /> exclude (NOT) 211 + </li> 212 + <li> 213 + <Q q="c:u (t:instant OR t:sorcery)" /> grouping 214 + </li> 215 + </ul> 216 + </MainCard> 217 + 218 + {/* Secondary cards - dimmer, just clickable queries */} 219 + <SecondaryCard title="Land Types"> 220 + <div className="flex flex-wrap gap-1.5 text-sm"> 221 + <Q q="is:fetchland" /> 222 + <Q q="is:shockland" /> 223 + <Q q="is:dual" /> 224 + <Q q="is:triome" /> 225 + <Q q="is:checkland" /> 226 + <Q q="is:fastland" /> 227 + <Q q="is:painland" /> 228 + <Q q="is:manland" /> 229 + </div> 230 + </SecondaryCard> 231 + 232 + <SecondaryCard title="Card Traits" className="sm:row-span-2"> 233 + <div className="flex flex-wrap gap-1.5 text-sm"> 234 + <Q q="is:commander" /> 235 + <Q q="is:legendary" /> 236 + <Q q="is:historic" /> 237 + <Q q="is:permanent" /> 238 + <Q q="is:spell" /> 239 + <Q q="is:modal" /> 240 + <Q q="is:spree" /> 241 + <Q q="is:vanilla" /> 242 + <Q q="is:frenchvanilla" /> 243 + <Q q="is:bear" /> 244 + <Q q="is:mdfc" /> 245 + <Q q="is:dfc" /> 246 + <Q q="is:transform" /> 247 + <Q q="is:meld" /> 248 + <Q q="is:saga" /> 249 + <Q q="is:adventure" /> 250 + <Q q="is:split" /> 251 + <Q q="is:flip" /> 252 + <Q q="is:battle" /> 253 + <Q q="is:prototype" /> 254 + <Q q="is:leveler" /> 255 + <Q q="is:party" /> 256 + <Q q="is:outlaw" /> 257 + <Q q="is:snow" /> 258 + <Q q="is:reserved" /> 259 + </div> 260 + </SecondaryCard> 261 + 262 + <SecondaryCard title="Printings"> 263 + <div className="flex flex-wrap gap-1.5 text-sm"> 264 + <Q q="is:showcase" /> 265 + <Q q="is:borderless" /> 266 + <Q q="is:retro" /> 267 + <Q q="is:foil" /> 268 + <Q q="is:extended" /> 269 + <Q q="is:promo" /> 270 + </div> 271 + </SecondaryCard> 272 + 273 + <SecondaryCard title="Advanced"> 274 + <div className="flex flex-wrap gap-1.5 text-sm"> 275 + <Q q='!"Abzan Battle Priest"' /> 276 + <Q q='"Aether M"' /> 277 + <Q q="year>=2024" /> 278 + <Q q="frame:2015" /> 279 + </div> 280 + </SecondaryCard> 281 + </div> 282 + </div> 283 + ); 284 + }
+7 -3
src/routes/cards/index.tsx
··· 12 12 import { CardSkeleton, CardThumbnail } from "@/components/CardImage"; 13 13 import { ClientDate } from "@/components/ClientDate"; 14 14 import { OracleText } from "@/components/OracleText"; 15 + import { SearchPrimer } from "@/components/SearchPrimer"; 15 16 import { 16 17 getCardsMetadataQueryOptions, 17 18 PAGE_SIZE, ··· 452 453 )} 453 454 454 455 {!search.q && ( 455 - <p className="text-sm text-gray-400 mt-2"> 456 - Enter a search query to find cards • <MetadataDisplay /> 457 - </p> 456 + <div className="mt-4"> 457 + <p className="text-sm text-gray-400 mb-4"> 458 + <MetadataDisplay /> 459 + </p> 460 + <SearchPrimer /> 461 + </div> 458 462 )} 459 463 </div> 460 464 </div>