Merge pull request #1604 from AnishSarkar22/feat/amazon-scraper
feat(amazon): add public multi-marketplace product scraping capability
|
|
@ -14,6 +14,11 @@ import { AppError } from "@/lib/error";
|
|||
import { findVerb } from "@/lib/playground/catalog";
|
||||
import { formatCost, formatDuration, formatPricing } from "@/lib/playground/format";
|
||||
import { buildPayload, initialFormValues, parseSchemaFields } from "@/lib/playground/json-schema";
|
||||
import {
|
||||
AmazonMarketplaceHint,
|
||||
getAmazonFieldOptions,
|
||||
hasAmazonFranceValue,
|
||||
} from "@/lib/playground/platform-overrides/amazon";
|
||||
import { ApiReference } from "./api-reference";
|
||||
import { OutputViewer } from "./output-viewer";
|
||||
import { RunProgressPanel } from "./run-progress-panel";
|
||||
|
|
@ -171,6 +176,8 @@ export function PlaygroundRunner({ workspaceId, platform, verb }: PlaygroundRunn
|
|||
[run.detail]
|
||||
);
|
||||
const endpoint = `POST /workspaces/${workspaceId}/scrapers/${platform}/${verb}`;
|
||||
const isAmazonScrape = platform === "amazon" && verb === "scrape";
|
||||
const hasAmazonFranceUrl = useMemo(() => hasAmazonFranceValue(values), [values]);
|
||||
|
||||
useEffect(() => {
|
||||
const previousStatus = previousStatusRef.current;
|
||||
|
|
@ -260,7 +267,9 @@ export function PlaygroundRunner({ workspaceId, platform, verb }: PlaygroundRunn
|
|||
values={values}
|
||||
onChange={handleChange}
|
||||
disabled={isRunning}
|
||||
getFieldOptions={isAmazonScrape ? getAmazonFieldOptions : undefined}
|
||||
/>
|
||||
{isAmazonScrape ? <AmazonMarketplaceHint showFranceWarning={hasAmazonFranceUrl} /> : null}
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button type="button" onClick={handleRun} disabled={isRunning} className="relative">
|
||||
|
|
|
|||
|
|
@ -17,11 +17,19 @@ import { Textarea } from "@/components/ui/textarea";
|
|||
import type { FormField } from "@/lib/playground/json-schema";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface FieldOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
type FieldOptionsResolver = (field: FormField) => FieldOption[] | undefined;
|
||||
|
||||
interface SchemaFormProps {
|
||||
fields: FormField[];
|
||||
values: Record<string, unknown>;
|
||||
onChange: (name: string, value: unknown) => void;
|
||||
disabled?: boolean;
|
||||
getFieldOptions?: FieldOptionsResolver;
|
||||
/** Field names flagged by a 422 response, shown with error styling. */
|
||||
fieldErrors?: Record<string, string>;
|
||||
}
|
||||
|
|
@ -32,12 +40,14 @@ function FieldControl({
|
|||
onChange,
|
||||
disabled,
|
||||
invalid,
|
||||
options,
|
||||
}: {
|
||||
field: FormField;
|
||||
value: unknown;
|
||||
onChange: (value: unknown) => void;
|
||||
disabled?: boolean;
|
||||
invalid?: boolean;
|
||||
options?: FieldOption[];
|
||||
}) {
|
||||
const id = `field-${field.name}`;
|
||||
|
||||
|
|
@ -68,6 +78,27 @@ function FieldControl({
|
|||
);
|
||||
}
|
||||
|
||||
if (options) {
|
||||
return (
|
||||
<Select
|
||||
value={value ? String(value) : options[0]?.value}
|
||||
onValueChange={onChange}
|
||||
disabled={disabled}
|
||||
>
|
||||
<SelectTrigger id={id} className={cn("w-full", invalid && "border-destructive")}>
|
||||
<SelectValue placeholder="Select…" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{options.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label} ({option.value})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
if (field.kind === "string_array") {
|
||||
return (
|
||||
<Textarea
|
||||
|
|
@ -116,12 +147,14 @@ function FieldRow({
|
|||
onChange,
|
||||
disabled,
|
||||
error,
|
||||
options,
|
||||
}: {
|
||||
field: FormField;
|
||||
value: unknown;
|
||||
onChange: (value: unknown) => void;
|
||||
disabled?: boolean;
|
||||
error?: string;
|
||||
options?: FieldOption[];
|
||||
}) {
|
||||
return (
|
||||
<div className="space-y-1.5">
|
||||
|
|
@ -143,13 +176,21 @@ function FieldRow({
|
|||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
invalid={!!error}
|
||||
options={options}
|
||||
/>
|
||||
{error && <p className="text-xs text-destructive">{error}</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SchemaForm({ fields, values, onChange, disabled, fieldErrors }: SchemaFormProps) {
|
||||
export function SchemaForm({
|
||||
fields,
|
||||
values,
|
||||
onChange,
|
||||
disabled,
|
||||
getFieldOptions,
|
||||
fieldErrors,
|
||||
}: SchemaFormProps) {
|
||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||
|
||||
const { primary, advanced } = useMemo(() => {
|
||||
|
|
@ -168,6 +209,7 @@ export function SchemaForm({ fields, values, onChange, disabled, fieldErrors }:
|
|||
onChange={(value) => onChange(field.name, value)}
|
||||
disabled={disabled}
|
||||
error={fieldErrors?.[field.name]}
|
||||
options={getFieldOptions?.(field)}
|
||||
/>
|
||||
))}
|
||||
|
||||
|
|
@ -197,6 +239,7 @@ export function SchemaForm({ fields, values, onChange, disabled, fieldErrors }:
|
|||
onChange={(value) => onChange(field.name, value)}
|
||||
disabled={disabled}
|
||||
error={fieldErrors?.[field.name]}
|
||||
options={getFieldOptions?.(field)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -233,4 +233,4 @@ Image.Preview = ImagePreview;
|
|||
Image.Filename = ImageFilename;
|
||||
Image.Zoom = ImageZoom;
|
||||
|
||||
export { Image, ImageRoot, ImagePreview, ImageFilename, ImageZoom, imageVariants };
|
||||
export { Image, ImageFilename, ImagePreview, ImageRoot, ImageZoom, imageVariants };
|
||||
|
|
|
|||
|
|
@ -181,13 +181,13 @@ function ComposerSuggestionSkeleton({
|
|||
}
|
||||
|
||||
export {
|
||||
ComposerSuggestionPopoverContent,
|
||||
ComposerSuggestionList,
|
||||
ComposerSuggestionGroup,
|
||||
ComposerSuggestionGroupHeading,
|
||||
ComposerSuggestionHeader,
|
||||
ComposerSuggestionItem,
|
||||
ComposerSuggestionSeparator,
|
||||
ComposerSuggestionList,
|
||||
ComposerSuggestionMessage,
|
||||
ComposerSuggestionPopoverContent,
|
||||
ComposerSuggestionSeparator,
|
||||
ComposerSuggestionSkeleton,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ export const GenerateImageToolUI = ({
|
|||
};
|
||||
|
||||
export {
|
||||
GenerateImageArgsSchema,
|
||||
GenerateImageResultSchema,
|
||||
type GenerateImageArgs,
|
||||
GenerateImageArgsSchema,
|
||||
type GenerateImageResult,
|
||||
GenerateImageResultSchema,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -418,4 +418,4 @@ export const SandboxExecuteToolUI = ({
|
|||
return <ExecuteCompleted command={command} parsed={parsed} threadId={threadId} />;
|
||||
};
|
||||
|
||||
export { ExecuteArgsSchema, ExecuteResultSchema, type ExecuteArgs, type ExecuteResult };
|
||||
export { type ExecuteArgs, ExecuteArgsSchema, type ExecuteResult, ExecuteResultSchema };
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ export const UpdateMemoryToolUI = ({
|
|||
// ============================================================================
|
||||
|
||||
export {
|
||||
UpdateMemoryArgsSchema,
|
||||
UpdateMemoryResultSchema,
|
||||
type UpdateMemoryArgs,
|
||||
UpdateMemoryArgsSchema,
|
||||
type UpdateMemoryResult,
|
||||
UpdateMemoryResultSchema,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -157,4 +157,4 @@ export const WriteTodosToolUI = ({
|
|||
);
|
||||
};
|
||||
|
||||
export { WriteTodosSchema, type WriteTodosData };
|
||||
export { type WriteTodosData, WriteTodosSchema };
|
||||
|
|
|
|||
|
|
@ -61,4 +61,4 @@ function AccordionContent({
|
|||
);
|
||||
}
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
||||
|
|
|
|||
|
|
@ -121,14 +121,14 @@ function AlertDialogCancel({
|
|||
|
||||
export {
|
||||
AlertDialog,
|
||||
AlertDialogPortal,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogTrigger,
|
||||
AlertDialogContent,
|
||||
AlertDialogHeader,
|
||||
AlertDialogFooter,
|
||||
AlertDialogTitle,
|
||||
AlertDialogDescription,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogPortal,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -59,4 +59,4 @@ function AlertDescription({ className, ...props }: React.ComponentProps<"div">)
|
|||
);
|
||||
}
|
||||
|
||||
export { Alert, AlertTitle, AlertDescription };
|
||||
export { Alert, AlertDescription, AlertTitle };
|
||||
|
|
|
|||
|
|
@ -556,4 +556,4 @@ const TabsContent = forwardRef<
|
|||
});
|
||||
TabsContent.displayName = "TabsContent";
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
||||
export { Tabs, TabsContent, TabsList, TabsTrigger };
|
||||
|
|
|
|||
|
|
@ -55,4 +55,4 @@ function AvatarGroupCount({ className, ...props }: React.ComponentProps<"span">)
|
|||
);
|
||||
}
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, AvatarGroupCount };
|
||||
export { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage };
|
||||
|
|
|
|||
|
|
@ -52,4 +52,4 @@ const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDiv
|
|||
);
|
||||
CardFooter.displayName = "CardFooter";
|
||||
|
||||
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter };
|
||||
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@ function CollapsibleContent({
|
|||
return <CollapsiblePrimitive.CollapsibleContent data-slot="collapsible-content" {...props} />;
|
||||
}
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
||||
export { Collapsible, CollapsibleContent, CollapsibleTrigger };
|
||||
|
|
|
|||
|
|
@ -150,11 +150,11 @@ function CommandShortcut({ className, ...props }: React.ComponentProps<"span">)
|
|||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -207,18 +207,18 @@ function ContextMenuShortcut({ className, ...props }: React.ComponentProps<"span
|
|||
|
||||
export {
|
||||
ContextMenu,
|
||||
ContextMenuTrigger,
|
||||
ContextMenuContent,
|
||||
ContextMenuItem,
|
||||
ContextMenuCheckboxItem,
|
||||
ContextMenuRadioItem,
|
||||
ContextMenuContent,
|
||||
ContextMenuGroup,
|
||||
ContextMenuItem,
|
||||
ContextMenuLabel,
|
||||
ContextMenuPortal,
|
||||
ContextMenuRadioGroup,
|
||||
ContextMenuRadioItem,
|
||||
ContextMenuSeparator,
|
||||
ContextMenuShortcut,
|
||||
ContextMenuGroup,
|
||||
ContextMenuPortal,
|
||||
ContextMenuSub,
|
||||
ContextMenuSubContent,
|
||||
ContextMenuSubTrigger,
|
||||
ContextMenuRadioGroup,
|
||||
ContextMenuTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -92,13 +92,13 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogClose,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogOverlay,
|
||||
DialogPortal,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -102,14 +102,14 @@ DrawerHandle.displayName = "DrawerHandle";
|
|||
|
||||
export {
|
||||
Drawer,
|
||||
DrawerPortal,
|
||||
DrawerOverlay,
|
||||
DrawerTrigger,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerHeader,
|
||||
DrawerFooter,
|
||||
DrawerTitle,
|
||||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerHandle,
|
||||
DrawerHeader,
|
||||
DrawerOverlay,
|
||||
DrawerPortal,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -211,18 +211,18 @@ function DropdownMenuSubContent({
|
|||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -91,4 +91,4 @@ function EmptyContent({ className, ...props }: React.ComponentProps<"div">) {
|
|||
);
|
||||
}
|
||||
|
||||
export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia };
|
||||
export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle };
|
||||
|
|
|
|||
|
|
@ -91,4 +91,4 @@ const ExpandedGifOverlay = ExpandedMediaOverlay;
|
|||
/** @deprecated Use useExpandedMedia instead */
|
||||
const useExpandedGif = useExpandedMedia;
|
||||
|
||||
export { ExpandedMediaOverlay, useExpandedMedia, ExpandedGifOverlay, useExpandedGif };
|
||||
export { ExpandedGifOverlay, ExpandedMediaOverlay, useExpandedGif, useExpandedMedia };
|
||||
|
|
|
|||
|
|
@ -140,12 +140,12 @@ function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
|
|||
}
|
||||
|
||||
export {
|
||||
useFormField,
|
||||
Form,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormMessage,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
useFormField,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -96,9 +96,9 @@ function PaginationEllipsis({ className, ...props }: React.ComponentProps<"span"
|
|||
export {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationLink,
|
||||
PaginationItem,
|
||||
PaginationPrevious,
|
||||
PaginationNext,
|
||||
PaginationEllipsis,
|
||||
PaginationItem,
|
||||
PaginationLink,
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,4 +39,4 @@ function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitiv
|
|||
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
|
||||
}
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|
||||
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };
|
||||
|
|
|
|||
|
|
@ -122,11 +122,11 @@ function SheetDescription({
|
|||
|
||||
export {
|
||||
Sheet,
|
||||
SheetTrigger,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -89,4 +89,4 @@ function TableCaption({ className, ...props }: React.ComponentProps<"caption">)
|
|||
);
|
||||
}
|
||||
|
||||
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
|
||||
export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
|
||||
|
|
|
|||
|
|
@ -52,4 +52,4 @@ const TabsContent = React.forwardRef<
|
|||
));
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
||||
export { Tabs, TabsContent, TabsList, TabsTrigger };
|
||||
|
|
|
|||
|
|
@ -82,4 +82,4 @@ function TooltipContent({
|
|||
);
|
||||
}
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
||||
|
|
|
|||
67
surfsense_web/content/docs/connectors/native/amazon.mdx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
title: Amazon
|
||||
description: Scrape public Amazon product data as structured JSON
|
||||
---
|
||||
|
||||
The Amazon scraper returns public product data as structured JSON: price and list price, rating and review breakdown, availability, marketplace offers, sellers, best-seller ranks, product variants, and on-page reviews. It only uses public, anonymous data — no login or seller account. Give it search terms or Amazon product, search, category, or best-seller URLs.
|
||||
|
||||
Marketplace support is inferred from the Amazon URL or `domain` you provide. Supported public marketplaces include US (`amazon.com`), UK (`amazon.co.uk`), Germany (`amazon.de`), Italy (`amazon.it`), and Spain (`amazon.es`). France (`amazon.fr`) is supported in the scraper but remains best-effort because Amazon France is more sensitive to proxy-pool WAF challenges.
|
||||
|
||||
## Endpoint
|
||||
|
||||
```bash
|
||||
POST /api/v1/workspaces/{workspace_id}/scrapers/amazon/scrape
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
| Field | Default | Description |
|
||||
|-------|---------|-------------|
|
||||
| `urls` | — | Amazon product, search, category, best-seller, or short (`a.co` / `amzn.to`) URLs. Marketplace is inferred from the URL, e.g. `amazon.co.uk`, `amazon.de`, `amazon.it`, or `amazon.es`. Provide `urls` or `search_terms` |
|
||||
| `search_terms` | — | Search phrases run on the selected `domain`, e.g. `wireless earbuds`. Provide `search_terms` or `urls` |
|
||||
| `max_items` | `10` | Max products per search term or category/best-seller URL (1–100) |
|
||||
| `domain` | `www.amazon.com` | Amazon marketplace domain for `search_terms`, e.g. `www.amazon.co.uk`, `www.amazon.de`, `www.amazon.it`, or `www.amazon.es`. `www.amazon.fr` is best-effort due to Amazon WAF sensitivity |
|
||||
| `include_details` | `true` | Fetch full product detail pages; `false` returns faster card-only results |
|
||||
| `max_offers` | `0` | Extra marketplace offers per product (0–100); `0` = featured offer only |
|
||||
| `include_sellers` | `false` | Enrich the product and each offer with the seller's public profile |
|
||||
| `max_variants` | `0` | Product variants to return as separate results (0–100) |
|
||||
| `include_variant_prices` | `false` | Attach per-variant prices (one extra request per variant) |
|
||||
| `country_code` | — | Two-letter delivery country for localized pricing, e.g. `us` |
|
||||
| `zip_code` | — | Delivery ZIP/postal code for localized availability, e.g. `10001` |
|
||||
| `language` | — | Content language for the domain, e.g. `en` |
|
||||
|
||||
At least one of `urls` or `search_terms` is required, with up to 20 combined sources per call.
|
||||
|
||||
## Example
|
||||
|
||||
```bash
|
||||
curl -X POST "$BASE_URL/api/v1/workspaces/1/scrapers/amazon/scrape" \
|
||||
-H "Authorization: Bearer $SURFSENSE_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"search_terms": ["mechanical keyboard"],
|
||||
"max_items": 5,
|
||||
"max_offers": 3
|
||||
}'
|
||||
```
|
||||
|
||||
## Marketplace examples
|
||||
|
||||
```json
|
||||
{
|
||||
"urls": [
|
||||
"https://www.amazon.co.uk/s?k=usb+c+cable",
|
||||
"https://www.amazon.de/s?k=mechanische+tastatur",
|
||||
"https://www.amazon.it/s?k=cavo+usb+c",
|
||||
"https://www.amazon.es/s?k=cable+usb+c"
|
||||
],
|
||||
"max_items": 5,
|
||||
"include_details": false
|
||||
}
|
||||
```
|
||||
|
||||
For `search_terms`, set `domain` to the marketplace you want to search. For direct URLs, the scraper infers the marketplace from each URL.
|
||||
|
||||
The response is `{ "items": [...] }` — one item per product, plus structured error items for any input that could not be resolved. Billing is per returned product; error items are never billed.
|
||||
|
||||
For the full input and output JSON schemas and generated code snippets in your language, open **API Playground → Amazon → Scrape** in your workspace.
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
"tiktok",
|
||||
"google-maps",
|
||||
"google-search",
|
||||
"amazon",
|
||||
"web-crawl"
|
||||
],
|
||||
"defaultOpen": false
|
||||
|
|
|
|||
|
|
@ -426,6 +426,6 @@ export interface ObsidianStats {
|
|||
last_sync_at: string | null;
|
||||
}
|
||||
|
||||
export type { SlackChannel, DiscordChannel };
|
||||
export type { DiscordChannel, SlackChannel };
|
||||
|
||||
export const connectorsApiService = new ConnectorsApiService();
|
||||
|
|
|
|||
320
surfsense_web/lib/connectors-marketing/amazon.tsx
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
import { IconBrandAmazon } from "@tabler/icons-react";
|
||||
import type { ConnectorPageContent } from "./types";
|
||||
|
||||
export const amazon: ConnectorPageContent = {
|
||||
slug: "amazon",
|
||||
name: "Amazon",
|
||||
cardTitle: "Amazon Product API",
|
||||
icon: IconBrandAmazon,
|
||||
|
||||
metaTitle: "Amazon Product Scraper API for Price & Review Data | SurfSense",
|
||||
metaDescription:
|
||||
"Scrape public Amazon product data as structured JSON across US, UK, Germany, Italy, and Spain: prices, ratings, offers, sellers, and ranks. Start free.",
|
||||
keywords: [
|
||||
"amazon product api",
|
||||
"amazon scraper api",
|
||||
"amazon price scraper",
|
||||
"scrape amazon product data",
|
||||
"amazon product data api",
|
||||
"amazon review scraper",
|
||||
"amazon best sellers api",
|
||||
"amazon asin lookup",
|
||||
"amazon price tracking api",
|
||||
"amazon competitor monitoring",
|
||||
"amazon offers scraper",
|
||||
"ecommerce product api",
|
||||
],
|
||||
|
||||
h1: "Amazon Product Scraper API for Price, Review, and Offer Data",
|
||||
heroLede:
|
||||
"The SurfSense Amazon Product API scrapes public Amazon listings as structured JSON: price and list price, rating and review breakdown, availability, marketplace offers, sellers, best-seller ranks, and on-page reviews. Point your AI agents at a search term or product URL and track prices across US, UK, German, Italian, and Spanish marketplaces — no login, only public data.",
|
||||
|
||||
transcript: {
|
||||
prompt: "Track the price and rating of the top mechanical keyboards on Amazon",
|
||||
toolCall:
|
||||
'amazon.scrape({ search_terms: ["mechanical keyboard"],\n max_items: 5, max_offers: 3 })',
|
||||
rows: [
|
||||
{
|
||||
primary: "Keychron K8 Pro — $89.99 (was $99.99)",
|
||||
secondary: "4.7 stars · 12,431 ratings · In Stock",
|
||||
tag: "-10%",
|
||||
},
|
||||
{
|
||||
primary: "3 marketplace offers, cheapest $84.50 used",
|
||||
secondary: "sold by 2 third-party sellers",
|
||||
tag: "offers",
|
||||
},
|
||||
{
|
||||
primary: "#2 in Computer Keyboards best-sellers",
|
||||
secondary: "Electronics › Accessories › Keyboards",
|
||||
tag: "rank",
|
||||
},
|
||||
],
|
||||
resultSummary: "5 products · 14 offers · 5 best-seller ranks · surfaced in 3.1s",
|
||||
},
|
||||
|
||||
extractIntro:
|
||||
"Give the API a list of product/search/category/best-seller URLs or search terms and a domain. Marketplace is inferred from each Amazon URL, or from the domain used with search terms. Supported marketplaces include US, UK, Germany, Italy, and Spain; France is best-effort because Amazon France is more WAF-sensitive.",
|
||||
extractFields: [
|
||||
{
|
||||
label: "Product core",
|
||||
description:
|
||||
"Title, ASIN, brand, price, list price, availability, condition, and canonical URL for every product.",
|
||||
},
|
||||
{
|
||||
label: "Ratings & reviews",
|
||||
description:
|
||||
"Star rating, review count, the 5-to-1-star histogram, and on-page customer reviews with text, author, and date.",
|
||||
},
|
||||
{
|
||||
label: "Marketplace offers",
|
||||
description:
|
||||
"Additional buy-box offers with price, condition, delivery, and the third-party seller behind each.",
|
||||
},
|
||||
{
|
||||
label: "Sellers",
|
||||
description:
|
||||
"Public seller profile summaries — name, rating, and feedback count — for the featured and offer sellers.",
|
||||
},
|
||||
{
|
||||
label: "Best-seller ranks",
|
||||
description:
|
||||
"Category rank positions and best-seller list placements, for demand and category monitoring.",
|
||||
},
|
||||
{
|
||||
label: "Variants & media",
|
||||
description:
|
||||
"Variant ASINs and attributes (color, size), per-variant prices, gallery and high-resolution images.",
|
||||
},
|
||||
],
|
||||
|
||||
useCasesHeading: "What teams do with the Amazon Product API",
|
||||
useCases: [
|
||||
{
|
||||
title: "Price and buy-box tracking",
|
||||
description:
|
||||
"Watch your own and competitors' prices, list prices, and marketplace offers across US, UK, German, Italian, and Spanish marketplaces. Feed each run to an agent that diffs prices and alerts you when a competitor undercuts or the buy box changes hands.",
|
||||
},
|
||||
{
|
||||
title: "Review mining and product research",
|
||||
description:
|
||||
"Pull ratings, the star histogram, and on-page reviews to understand what customers love and complain about, then brief an agent to summarize themes and inform your roadmap or listing copy.",
|
||||
},
|
||||
{
|
||||
title: "Best-seller and category monitoring",
|
||||
description:
|
||||
"Track best-seller ranks in the categories you care about to spot rising products and demand shifts before they show up anywhere else.",
|
||||
},
|
||||
{
|
||||
title: "Catalog and seller intelligence",
|
||||
description:
|
||||
"Enrich a catalog by ASIN with structured attributes, variants, and images, and see which third-party sellers are winning offers on the products that matter to you.",
|
||||
},
|
||||
],
|
||||
|
||||
comparison: {
|
||||
heading: "An Amazon scraper API built for agents",
|
||||
intro:
|
||||
"Most Amazon data APIs bill per request, meter add-ons separately, and leave the discovery-to-detail logic to you. Here is how SurfSense compares.",
|
||||
columnLabel: "Typical Amazon data API",
|
||||
rows: [
|
||||
{
|
||||
feature: "Pricing",
|
||||
official: "Per-request pricing that climbs fast at scale",
|
||||
surfsense: "Pay per product returned, with a free tier to start",
|
||||
},
|
||||
{
|
||||
feature: "Discovery",
|
||||
official: "Separate search and detail endpoints you stitch together",
|
||||
surfsense: "One verb takes search terms, product, category, or best-seller URLs",
|
||||
},
|
||||
{
|
||||
feature: "Offers & sellers",
|
||||
official: "Often separate paid endpoints",
|
||||
surfsense: "Offers and seller profiles enriched inline on the product",
|
||||
},
|
||||
{
|
||||
feature: "Data access",
|
||||
official: "Requires accounts, keys, or approval for many providers",
|
||||
surfsense: "Public, anonymous data only — no login or seller account",
|
||||
},
|
||||
{
|
||||
feature: "Agent-ready",
|
||||
official: "No; you wire the harness yourself",
|
||||
surfsense: "MCP server exposes amazon.scrape as a native tool",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
api: {
|
||||
platform: "amazon",
|
||||
verb: "scrape",
|
||||
mcpTool: "amazon.scrape",
|
||||
requestBody: {
|
||||
search_terms: ["mechanical keyboard"],
|
||||
max_items: 5,
|
||||
max_offers: 3,
|
||||
},
|
||||
},
|
||||
|
||||
schema: {
|
||||
requestNote:
|
||||
"Provide urls or search_terms (at least one). Marketplace is inferred from Amazon URLs, or from domain for search terms. Up to 20 combined sources per call.",
|
||||
request: [
|
||||
{
|
||||
name: "urls",
|
||||
type: "string[]",
|
||||
description:
|
||||
"Amazon product, search, category, best-seller, or short (a.co / amzn.to) URLs. Supports amazon.com, amazon.co.uk, amazon.de, amazon.it, and amazon.es; amazon.fr is best-effort. Provide urls or search_terms.",
|
||||
},
|
||||
{
|
||||
name: "search_terms",
|
||||
type: "string[]",
|
||||
description:
|
||||
"Search phrases run on the Amazon domain, e.g. 'wireless earbuds'. Provide search_terms or urls.",
|
||||
},
|
||||
{
|
||||
name: "max_items",
|
||||
type: "integer",
|
||||
defaultValue: "10",
|
||||
description: "Max products per search term or category/best-seller URL, 1 to 100.",
|
||||
},
|
||||
{
|
||||
name: "domain",
|
||||
type: "string",
|
||||
defaultValue: '"www.amazon.com"',
|
||||
description:
|
||||
"Amazon marketplace domain for search_terms, e.g. 'www.amazon.co.uk', 'www.amazon.de', 'www.amazon.it', or 'www.amazon.es'. 'www.amazon.fr' is best-effort due to WAF sensitivity.",
|
||||
},
|
||||
{
|
||||
name: "include_details",
|
||||
type: "boolean",
|
||||
defaultValue: "true",
|
||||
description: "Fetch full product detail pages. false returns faster card-only results.",
|
||||
},
|
||||
{
|
||||
name: "max_offers",
|
||||
type: "integer",
|
||||
defaultValue: "0",
|
||||
description:
|
||||
"Extra marketplace offers to fetch per product, 0 to 100. 0 returns the featured offer only.",
|
||||
},
|
||||
{
|
||||
name: "include_sellers",
|
||||
type: "boolean",
|
||||
defaultValue: "false",
|
||||
description: "Enrich the product and each offer with the seller's public profile.",
|
||||
},
|
||||
{
|
||||
name: "max_variants",
|
||||
type: "integer",
|
||||
defaultValue: "0",
|
||||
description: "Product variants to return as separate results, 0 to 100.",
|
||||
},
|
||||
{
|
||||
name: "include_variant_prices",
|
||||
type: "boolean",
|
||||
defaultValue: "false",
|
||||
description: "Attach per-variant prices (one extra request per variant).",
|
||||
},
|
||||
{
|
||||
name: "country_code",
|
||||
type: "string",
|
||||
description: "Two-letter delivery country for localized pricing, e.g. 'us'.",
|
||||
},
|
||||
{
|
||||
name: "zip_code",
|
||||
type: "string",
|
||||
description: "Delivery ZIP/postal code for localized availability, e.g. '10001'.",
|
||||
},
|
||||
{
|
||||
name: "language",
|
||||
type: "string",
|
||||
description: "Content language for the domain, e.g. 'en'.",
|
||||
},
|
||||
],
|
||||
responseNote:
|
||||
"The response is { items: [...] } with one item per product. One returned product is one billable unit; error items are never billed.",
|
||||
response: [
|
||||
{
|
||||
name: "title / asin / brand",
|
||||
type: "string",
|
||||
description: "Product identity: display title, ASIN, and brand.",
|
||||
},
|
||||
{
|
||||
name: "price / listPrice",
|
||||
type: "object",
|
||||
description: "Current price and strike-through list price, each with value and currency.",
|
||||
},
|
||||
{
|
||||
name: "stars / reviewsCount / starsBreakdown",
|
||||
type: "object",
|
||||
description:
|
||||
"Average rating, total review count, and the 5-to-1-star distribution as fractions.",
|
||||
},
|
||||
{
|
||||
name: "offers",
|
||||
type: "object[]",
|
||||
description:
|
||||
"Marketplace offers with price, condition, delivery, seller, and pinned-offer flag.",
|
||||
},
|
||||
{
|
||||
name: "seller",
|
||||
type: "object",
|
||||
description: "Featured seller profile: id, name, url, rating, and feedback count.",
|
||||
},
|
||||
{
|
||||
name: "bestsellerRanks",
|
||||
type: "object[]",
|
||||
description: "Category rank positions and best-seller list placements.",
|
||||
},
|
||||
{
|
||||
name: "variantAsins / variantDetails / variantAttributes",
|
||||
type: "object[]",
|
||||
description: "Related variant ASINs and their attributes and per-variant prices.",
|
||||
},
|
||||
{
|
||||
name: "productPageReviews",
|
||||
type: "object[]",
|
||||
description: "On-page customer reviews with text, author, rating, and date.",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
faq: [
|
||||
{
|
||||
question: "What is an Amazon product API?",
|
||||
answer:
|
||||
"An Amazon product API returns a listing's data as structured JSON instead of raw HTML. The SurfSense Amazon API scrapes public product pages and gives you price, rating, review breakdown, offers, sellers, and best-seller ranks as clean JSON your agents can read.",
|
||||
},
|
||||
{
|
||||
question: "Can I track Amazon prices with it?",
|
||||
answer:
|
||||
"Yes. Each product returns its current price, list price, and marketplace offers. Run the same URLs or search terms on a schedule and diff the prices to build price and buy-box tracking, without maintaining scrapers or proxies yourself.",
|
||||
},
|
||||
{
|
||||
question: "Does it only use public data?",
|
||||
answer:
|
||||
"It does. The scraper collects public, anonymous product data only — no login, seller account, or authenticated APIs. That covers product details, ratings, on-page reviews, offers, public seller profiles, and best-seller rankings.",
|
||||
},
|
||||
{
|
||||
question: "How do I look up a product by ASIN or search term?",
|
||||
answer:
|
||||
"Pass a product URL (which contains the ASIN) in urls, or a phrase in search_terms to discover products on the domain. You can also pass search, category, and best-seller URLs. One verb, amazon.scrape, handles all of them.",
|
||||
},
|
||||
{
|
||||
question: "Which Amazon marketplaces are supported?",
|
||||
answer:
|
||||
"Marketplace routing is inferred from the Amazon URL or domain. SurfSense supports public Amazon data from US, UK, Germany, Italy, and Spain. France is wired in and retried like the others, but remains best-effort because Amazon France is more sensitive to proxy-pool WAF challenges.",
|
||||
},
|
||||
],
|
||||
|
||||
related: [
|
||||
{ label: "Google Search API", href: "/google-search" },
|
||||
{ label: "Google Maps API", href: "/google-maps" },
|
||||
{ label: "Web Crawl API", href: "/web-crawl" },
|
||||
{ label: "Reddit API", href: "/reddit" },
|
||||
{ label: "SurfSense MCP Server", href: "/mcp-server" },
|
||||
{ label: "Read the docs", href: "/docs" },
|
||||
],
|
||||
};
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { amazon } from "./amazon";
|
||||
import { googleMaps } from "./google-maps";
|
||||
import { googleSearch } from "./google-search";
|
||||
import { instagram } from "./instagram";
|
||||
|
|
@ -17,6 +18,7 @@ const CONNECTOR_LIST: ConnectorPageContent[] = [
|
|||
tiktok,
|
||||
googleMaps,
|
||||
googleSearch,
|
||||
amazon,
|
||||
webCrawl,
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { ComponentType } from "react";
|
||||
import {
|
||||
AmazonIcon,
|
||||
GoogleMapsIcon,
|
||||
GoogleSearchIcon,
|
||||
InstagramIcon,
|
||||
|
|
@ -89,6 +90,12 @@ export const PLAYGROUND_PLATFORMS: PlaygroundPlatform[] = [
|
|||
icon: GoogleSearchIcon,
|
||||
verbs: [{ name: "google_search.scrape", verb: "scrape", label: "Scrape" }],
|
||||
},
|
||||
{
|
||||
id: "amazon",
|
||||
label: "Amazon",
|
||||
icon: AmazonIcon,
|
||||
verbs: [{ name: "amazon.scrape", verb: "scrape", label: "Scrape" }],
|
||||
},
|
||||
{
|
||||
id: "web",
|
||||
label: "Web",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ function brandIcon(src: string, alt: string) {
|
|||
};
|
||||
}
|
||||
|
||||
export const AmazonIcon = brandIcon("/connectors/amazon.svg", "Amazon");
|
||||
export const RedditIcon = brandIcon("/connectors/reddit.svg", "Reddit");
|
||||
export const YouTubeIcon = brandIcon("/connectors/youtube.svg", "YouTube");
|
||||
export const InstagramIcon = brandIcon("/connectors/instagram.svg", "Instagram");
|
||||
|
|
|
|||
38
surfsense_web/lib/playground/platform-overrides/amazon.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { Info } from "lucide-react";
|
||||
import type { FieldOption } from "@/app/dashboard/[workspace_id]/playground/components/schema-form";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import type { FormField } from "@/lib/playground/json-schema";
|
||||
|
||||
export const AMAZON_DOMAIN_OPTIONS: FieldOption[] = [
|
||||
{ label: "US", value: "www.amazon.com" },
|
||||
{ label: "UK", value: "www.amazon.co.uk" },
|
||||
{ label: "Germany", value: "www.amazon.de" },
|
||||
{ label: "Italy", value: "www.amazon.it" },
|
||||
{ label: "Spain", value: "www.amazon.es" },
|
||||
{ label: "France, best effort", value: "www.amazon.fr" },
|
||||
];
|
||||
|
||||
const AMAZON_SUPPORTED_COUNTRIES = "US, UK, Germany, Italy, Spain, France";
|
||||
|
||||
export function getAmazonFieldOptions(field: FormField): FieldOption[] | undefined {
|
||||
return field.name === "domain" ? AMAZON_DOMAIN_OPTIONS : undefined;
|
||||
}
|
||||
|
||||
export function hasAmazonFranceValue(values: Record<string, unknown>): boolean {
|
||||
return JSON.stringify(values).toLowerCase().includes("amazon.fr");
|
||||
}
|
||||
|
||||
export function AmazonMarketplaceHint({ showFranceWarning }: { showFranceWarning: boolean }) {
|
||||
return (
|
||||
<Alert>
|
||||
<Info />
|
||||
<AlertDescription className="flex flex-wrap items-baseline gap-x-1">
|
||||
<span className="font-medium text-foreground">Supported countries: </span>
|
||||
<span>{AMAZON_SUPPORTED_COUNTRIES}</span>
|
||||
{showFranceWarning
|
||||
? " France is more WAF-sensitive. If this run returns no results, retry later or use another marketplace."
|
||||
: null}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
22
surfsense_web/public/connectors/amazon.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<title>Amazon-color</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
|
||||
</defs>
|
||||
<g id="Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Color-" transform="translate(-601.000000, -560.000000)">
|
||||
<g id="Amazon" transform="translate(601.000000, 560.000000)">
|
||||
<path d="M25.4026553,25.9595294 C24.660417,27.4418824 23.3876054,28.3962353 22.0103725,28.7181176 C21.8015298,28.7181176 21.4826213,28.8225882 21.1637129,28.8225882 C18.835399,28.8225882 17.458166,27.0211765 17.458166,24.3727059 C17.458166,20.9788235 19.4703937,19.392 22.0103725,18.6465882 C23.3876054,18.3303529 24.9793255,18.2230588 26.5682233,18.2230588 L26.5682233,19.4964706 C26.5682233,21.9331765 26.6726447,23.8390588 25.4026553,25.9595294 L25.4026553,25.9595294 Z M26.5682233,13.3524706 C25.1909904,13.4569412 23.5992703,13.5614118 22.0103725,13.7703529 C19.574815,14.0922353 17.1392576,14.5157647 15.1298521,15.4701176 C11.2098182,17.0597647 8.55977364,20.4508235 8.55977364,25.4287059 C8.55977364,31.6856471 12.5842289,34.8621176 17.6726531,34.8621176 C19.3659723,34.8621176 20.7432053,34.6475294 22.0103725,34.3341176 C24.0282445,33.696 25.7187415,32.5298824 27.7309692,30.4094118 C28.8965372,31.9990588 29.2182679,32.7444706 31.2276733,34.4385882 C31.7582467,34.6475294 32.28882,34.6475294 32.7093276,34.3341176 C33.9821392,33.2724706 36.208854,31.3637647 37.3715998,30.3049412 C37.9021732,29.8814118 37.7977518,29.2432941 37.4760212,28.7181176 C36.3132753,27.2329412 35.1448851,25.9595294 35.1448851,23.0992941 L35.1448851,13.5614118 C35.1448851,9.53505882 35.4666157,5.82494118 32.5004849,3.072 C30.0649275,0.849882353 26.2493149,0 23.2831841,0 L22.0103725,0 C16.6115064,0.313411765 10.8937319,2.64564706 9.61809814,9.32329412 C9.40643324,10.1731765 10.0442501,10.4894118 10.4675799,10.5938824 L16.3998415,11.3364706 C17.0348362,11.2291765 17.3537447,10.6983529 17.458166,10.1731765 C17.9859172,7.84094118 19.8937235,6.67482353 22.0103725,6.46023529 L22.4365245,6.46023529 C23.7093361,6.46023529 25.086569,6.99105882 25.8259851,8.05270588 C26.6726447,9.32329412 26.5682233,11.0202353 26.5682233,12.5054118 L26.5682233,13.3524706 L26.5682233,13.3524706 Z" fill="#343B45">
|
||||
|
||||
</path>
|
||||
<path d="M47.9943556,35.9463529 L47.9943556,35.9435294 C47.971778,35.4437647 47.8673567,35.0625882 47.658514,34.7463529 L47.6359364,34.7152941 L47.6105366,34.6842353 C47.3988717,34.4527059 47.1956734,34.3651765 46.9755419,34.2691765 C46.3179696,34.0150588 45.3612442,33.8795294 44.2097872,33.8767059 C43.382883,33.8767059 42.4713128,33.9557647 41.5540982,34.1562353 L41.551276,34.0941176 L40.6284171,34.4018824 L40.6114839,34.4103529 L40.0893771,34.5797647 L40.0893771,34.6023529 C39.47696,34.8564706 38.9209869,35.1727059 38.4045245,35.5482353 C38.0827939,35.7882353 37.8175072,36.1072941 37.8033962,36.5957647 C37.7949296,36.8611765 37.9303952,37.1661176 38.1533489,37.3468235 C38.3763025,37.5275294 38.6359448,37.5896471 38.8645429,37.5896471 C38.9181647,37.5896471 38.9689643,37.5868235 39.0141194,37.5783529 L39.0592746,37.5755294 L39.093141,37.5698824 C39.5446928,37.4738824 40.2022651,37.4089412 40.9727253,37.3016471 C41.6331198,37.2282353 42.3330251,37.1745882 42.9397978,37.1745882 C43.368772,37.1717647 43.7554132,37.2028235 44.0206999,37.2592941 C44.1533432,37.2875294 44.2521202,37.3214118 44.3057419,37.3496471 C44.3254973,37.3552941 44.3396083,37.3637647 44.3480749,37.3694118 C44.3593637,37.4061176 44.3762969,37.5021176 44.3734747,37.6348235 C44.3791191,38.1430588 44.164632,39.0861176 43.8683012,40.0065882 C43.5804369,40.9270588 43.2304843,41.8503529 42.999064,42.4630588 C42.94262,42.6042353 42.9059314,42.7595294 42.9059314,42.9289412 C42.900287,43.1745882 43.0018862,43.4738824 43.2163733,43.6715294 C43.425216,43.8691765 43.696147,43.9482353 43.9219229,43.9482353 L43.9332117,43.9482353 C44.2718756,43.9454118 44.5597398,43.8098824 44.8080933,43.6150588 C47.1505182,41.5087059 47.9661336,38.1430588 48,36.2484706 L47.9943556,35.9463529 Z M41.0489247,38.8658824 C40.8090378,38.8630588 40.5635065,38.9195294 40.3349084,39.0268235 C40.0780883,39.1284706 39.8156239,39.2470588 39.5672704,39.3515294 L39.2032068,39.504 L38.7290774,39.6931765 L38.7290774,39.6988235 C33.5785648,41.7882353 28.16841,43.0136471 23.1618295,43.1209412 C22.9783866,43.1265882 22.7921215,43.1265882 22.614323,43.1265882 C14.7403887,43.1322353 8.31706456,39.4785882 1.83729642,35.8785882 C1.61152053,35.76 1.37727804,35.6978824 1.15150215,35.6978824 C0.860815683,35.6978824 0.561662624,35.808 0.344353327,36.0112941 C0.12704403,36.2174118 -0.00277710907,36.5138824 4.50895989e-05,36.816 C-0.00277710907,37.2084706 0.208887791,37.5698824 0.505218651,37.8042353 C6.58705678,43.0870588 13.25309,47.9943529 22.2192152,48 C22.3941915,48 22.57199,47.9943529 22.7497885,47.9915294 C28.453452,47.8644706 34.902176,45.936 39.9087564,42.7905882 L39.9398006,42.7708235 C40.5945507,42.3783529 41.2493008,41.9322353 41.8673623,41.4381176 C42.2511813,41.1529412 42.516468,40.7068235 42.516468,40.2437647 C42.4995348,39.4221176 41.8024517,38.8658824 41.0489247,38.8658824 Z" id="Fill-237" fill="#FF9A00">
|
||||
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256"><path fill="#fff" d="M195.368 60.632H60.632v134.736h134.736z"/><path fill="#ea4335" d="M195.368 256L256 195.368l-30.316-5.172l-30.316 5.172l-5.533 27.73z"/><path fill="#188038" d="M0 195.368v40.421C0 246.956 9.044 256 20.21 256h40.422l6.225-30.316l-6.225-30.316l-33.033-5.172z"/><path fill="#1967d2" d="M256 60.632V20.21C256 9.044 246.956 0 235.79 0h-40.422q-5.532 22.554-5.533 33.196q0 10.641 5.533 27.436q20.115 5.76 30.316 5.76T256 60.631"/><path fill="#fbbc04" d="M256 60.632h-60.632v134.736H256z"/><path fill="#34a853" d="M195.368 195.368H60.632V256h134.736z"/><path fill="#4285f4" d="M195.368 0H20.211C9.044 0 0 9.044 0 20.21v175.158h60.632V60.632h134.736z"/><path fill="#4285f4" d="M88.27 165.154c-5.036-3.402-8.523-8.37-10.426-14.94l11.689-4.816q1.59 6.063 5.558 9.398c2.627 2.223 5.827 3.318 9.566 3.318q5.734 0 9.852-3.487c2.746-2.324 4.127-5.288 4.127-8.875q0-5.508-4.345-8.994c-2.897-2.324-6.535-3.486-10.88-3.486h-6.754v-11.57h6.063q5.608 0 9.448-3.033c2.56-2.02 3.84-4.783 3.84-8.303c0-3.132-1.145-5.625-3.435-7.494c-2.29-1.87-5.188-2.813-8.708-2.813c-3.436 0-6.164.91-8.185 2.745a16.1 16.1 0 0 0-4.413 6.754l-11.57-4.817c1.532-4.345 4.345-8.185 8.471-11.503s9.398-4.985 15.798-4.985c4.733 0 8.994.91 12.767 2.745c3.772 1.836 6.736 4.379 8.875 7.613c2.14 3.25 3.2 6.888 3.2 10.93c0 4.126-.993 7.613-2.98 10.476s-4.43 5.052-7.327 6.585v.69a22.25 22.25 0 0 1 9.398 7.327c2.442 3.284 3.672 7.208 3.672 11.79c0 4.58-1.163 8.673-3.487 12.26c-2.324 3.588-5.54 6.417-9.617 8.472c-4.092 2.055-8.69 3.1-13.793 3.1c-5.912.016-11.369-1.685-16.405-5.087m71.797-58.005l-12.833 9.28l-6.417-9.734l23.023-16.607h8.825v78.333h-12.598z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" fill="none"><path fill="#bbe2ff" d="M32 36.8C32 20.894 44.894 8 60.8 8h70.4C147.106 8 160 20.894 160 36.8v30.4c0 15.906-12.894 28.8-28.8 28.8H60.8C44.894 96 32 83.106 32 67.2z"/><path fill="#3c90ff" d="M19.867 49.392C17.818 33.82 29.94 20 45.645 20h100.71c15.706 0 27.827 13.82 25.778 29.392L166 96l6.133 46.608C174.182 158.18 162.061 172 146.355 172H45.645c-15.706 0-27.827-13.82-25.778-29.392L26 96z"/><mask id="a" width="154" height="152" x="19" y="20" maskUnits="userSpaceOnUse" style="mask-type:alpha"><path fill="#3c90ff" d="M19.867 49.392C17.818 33.82 29.94 20 45.645 20h100.71c15.706 0 27.827 13.82 25.778 29.392L166 96l6.133 46.608C174.182 158.18 162.061 172 146.355 172H45.645c-15.706 0-27.827-13.82-25.778-29.392L26 96z"/></mask><g mask="url(#a)"><path fill="url(#b)" d="M0 0h166v76H0z" transform="matrix(1 0 0 -1 13 172)"/></g><mask id="c" width="154" height="152" x="19" y="20" maskUnits="userSpaceOnUse" style="mask-type:alpha"><path fill="#3186ff" d="M19.867 49.392C17.818 33.82 29.94 20 45.645 20h100.71c15.706 0 27.827 13.82 25.778 29.392L166 96l6.133 46.608C174.182 158.18 162.061 172 146.355 172H45.645c-15.706 0-27.827-13.82-25.778-29.392L26 96z"/></mask><g mask="url(#c)"><path fill="url(#d)" d="M32 27.2C32 16.596 40.596 8 51.2 8h89.6c10.604 0 19.2 8.596 19.2 19.2V96H32z" filter="url(#e)"/></g><path fill="#fff" d="M75.353 133.336q-6.282 0-10.777-2.043t-7.61-5.465q-3.065-3.474-4.342-6.793T51.603 115a2.07 2.07 0 0 1 1.021-1.124l5.67-2.247q.714-.357 1.43-.102.714.204 1.685 2.349 1.022 2.145 2.86 4.546a14.3 14.3 0 0 0 4.495 3.728q2.606 1.328 6.435 1.328 6.18 0 9.807-3.575 3.677-3.575 3.677-9.091 0-5.976-3.882-9.194-3.881-3.269-10.266-3.269h-5.362a1.9 1.9 0 0 1-1.328-.51q-.51-.562-.511-1.277v-5.465q0-.767.51-1.277a1.82 1.82 0 0 1 1.329-.562h4.647q5.721 0 9.194-3.116t3.473-8.07q0-4.902-3.116-7.916t-8.58-3.014q-3.065 0-5.312 1.022a11.5 11.5 0 0 0-3.882 2.86 22.7 22.7 0 0 0-2.809 3.78q-1.174 1.941-1.89 2.145-.714.153-1.379-.255l-5.363-2.605q-.664-.358-.868-1.124t1.226-3.575q1.481-2.86 4.494-5.823a21 21 0 0 1 7.049-4.597q4.035-1.635 9.398-1.634 9.96 0 15.782 5.26 5.823 5.21 5.823 13.791 0 5.925-2.86 10.266-2.81 4.34-7.968 6.13v.204q6.231 1.838 9.806 6.741 3.627 4.853 3.626 11.594 0 9.654-6.742 15.834-6.74 6.18-17.57 6.18zm51.25-1.175q-.868 0-1.533-.664a2.25 2.25 0 0 1-.612-1.583V73.118l-11.492 8.274q-.614.46-1.431.307a1.96 1.96 0 0 1-1.225-.766l-3.32-4.7a1.98 1.98 0 0 1-.358-1.43q.153-.816.817-1.276l20.379-14.557q.256-.204.562-.306.307-.153.715-.153h4.291q.868 0 1.379.613.562.56.562 1.43v69.36q0 .92-.664 1.583a2 2 0 0 1-1.533.664z"/><defs><linearGradient id="b" x1="83" x2="83" y1="76" gradientUnits="userSpaceOnUse"><stop stop-color="#4fa0ff"/><stop offset="1" stop-color="#3186ff"/></linearGradient><linearGradient id="d" x1="89.06" x2="89.06" y1="21.75" y2="96.39" gradientUnits="userSpaceOnUse"><stop stop-color="#a9a8ff"/><stop offset=".8" stop-color="#3c90ff"/></linearGradient><filter id="e" width="152" height="112" x="20" y="-4" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_37330_7673" stdDeviation="6"/></filter></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.3 KiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="229" viewBox="0 0 256 229"><path fill="#0066da" d="m19.354 196.034l11.29 19.5c2.346 4.106 5.718 7.332 9.677 9.678q17.009-21.591 23.68-33.137q6.77-11.717 16.641-36.655q-26.604-3.502-40.32-3.502q-13.165 0-40.322 3.502c0 4.545 1.173 9.09 3.519 13.196z"/><path fill="#ea4335" d="M215.681 225.212c3.96-2.346 7.332-5.572 9.677-9.677l4.692-8.064l22.434-38.855a26.57 26.57 0 0 0 3.518-13.196q-27.315-3.502-40.247-3.502q-13.899 0-40.248 3.502q9.754 25.075 16.422 36.655q6.724 11.683 23.752 33.137"/><path fill="#00832d" d="M128.001 73.311q19.68-23.768 27.125-36.655q5.996-10.377 13.196-33.137C164.363 1.173 159.818 0 155.126 0h-54.25C96.184 0 91.64 1.32 87.68 3.519q9.16 26.103 15.544 37.154q7.056 12.213 24.777 32.638"/><path fill="#2684fc" d="M175.36 155.42H80.642l-40.32 69.792c3.958 2.346 8.503 3.519 13.195 3.519h148.968c4.692 0 9.238-1.32 13.196-3.52z"/><path fill="#00ac47" d="M128.001 73.311L87.681 3.52c-3.96 2.346-7.332 5.571-9.678 9.677L3.519 142.224A26.57 26.57 0 0 0 0 155.42h80.642z"/><path fill="#ffba00" d="m215.242 77.71l-37.243-64.514c-2.345-4.106-5.718-7.331-9.677-9.677l-40.32 69.792l47.358 82.109h80.496c0-4.546-1.173-9.09-3.519-13.196z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" fill="none"><mask id="a" width="168" height="154" x="12" y="18" maskUnits="userSpaceOnUse" style="mask-type:alpha"><path fill="#b43333" d="M63.09 37c14.626-25.333 51.193-25.334 65.819 0l45.033 78c14.626 25.334-3.657 57.001-32.91 57.001H50.967c-29.253 0-47.536-31.667-32.91-57.001z"/></mask><g mask="url(#a)"><path fill="url(#b)" d="M206.905 172.02h-91.888l-19.015-32.934 45.944-79.578z"/><path fill="url(#c)" d="M-14.919 172.006 50.04 59.494v.002L31.032 92.422h38.02L115 172.004l-129.918.001z"/><path fill="url(#d)" d="M96.007-20.085 141.954 59.5l-19.011 32.928H31.048z"/></g><defs><linearGradient id="b" x1="193.6" x2="103.09" y1="165.6" y2="111.21" gradientUnits="userSpaceOnUse"><stop offset=".09" stop-color="#ffe921"/><stop offset="1" stop-color="#fec700"/></linearGradient><linearGradient id="c" x1="114.4" x2="15.53" y1="181.61" y2="121.8" gradientUnits="userSpaceOnUse"><stop offset=".15" stop-color="#a9a8ff"/><stop offset=".33" stop-color="#6d97ff"/><stop offset=".48" stop-color="#3186ff"/></linearGradient><linearGradient id="d" x1="128.88" x2="28.7" y1="37.88" y2="84.64" gradientUnits="userSpaceOnUse"><stop offset=".55" stop-color="#0ebc5f"/><stop offset=".85" stop-color="#78c9ff"/></linearGradient></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="193" viewBox="0 0 256 193"><path fill="#4285f4" d="M58.182 192.05V93.14L27.507 65.077L0 49.504v125.091c0 9.658 7.825 17.455 17.455 17.455z"/><path fill="#34a853" d="M197.818 192.05h40.727c9.659 0 17.455-7.826 17.455-17.455V49.505l-31.156 17.837l-27.026 25.798z"/><path fill="#ea4335" d="m58.182 93.14l-4.174-38.647l4.174-36.989L128 69.868l69.818-52.364l4.669 34.992l-4.669 40.644L128 145.504z"/><path fill="#fbbc04" d="M197.818 17.504V93.14L256 49.504V26.231c0-21.585-24.64-33.89-41.89-20.945z"/><path fill="#c5221f" d="m0 49.504l26.759 20.07L58.182 93.14V17.504L41.89 5.286C24.61-7.66 0 4.646 0 26.23z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" fill="none" viewBox="0 0 192 192"><path fill="url(#a)" d="M146 44h38v110c0 6.627-5.373 12-12 12h-20a6 6 0 0 1-6-6z"/><path fill="#fc413d" d="M46 44H8v110c0 6.627 5.373 12 12 12h20a6 6 0 0 0 6-6z"/><path fill="url(#b)" d="M39.226 30.456c-8.033-6.752-20.018-5.714-26.77 2.319-6.752 8.032-5.714 20.017 2.319 26.77l76.078 63.949a8 8 0 0 0 10.295 0l76.078-63.95c8.032-6.752 9.07-18.737 2.318-26.77-6.752-8.032-18.737-9.07-26.769-2.318L96 78.18z"/><defs><linearGradient id="a" x1="165" x2="165" y1="44" y2="166" gradientUnits="userSpaceOnUse"><stop stop-color="#60d673"/><stop offset=".17" stop-color="#42c868"/><stop offset=".39" stop-color="#0ebc5f"/><stop offset=".62" stop-color="#00a9bb"/><stop offset=".86" stop-color="#3c90ff"/><stop offset="1" stop-color="#3186ff"/></linearGradient><linearGradient id="b" x1="8" x2="184" y1="46.13" y2="46.13" gradientUnits="userSpaceOnUse"><stop offset=".08" stop-color="#ff63a0"/><stop offset=".3" stop-color="#fc413d"/><stop offset=".5" stop-color="#fc413d"/><stop offset=".65" stop-color="#fc413d"/><stop offset=".72" stop-color="#fc5c30"/><stop offset=".86" stop-color="#feb10c"/><stop offset=".91" stop-color="#fec700"/><stop offset=".96" stop-color="#ffdb0f"/></linearGradient></defs></svg>
|
||||
|
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 765 B After Width: | Height: | Size: 4.1 MiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><radialGradient id="prefix__b" cx="1.479" cy="12.788" fx="1.479" fy="12.788" r="9.655" gradientTransform="matrix(.8032 0 0 1.0842 2.459 -.293)" gradientUnits="userSpaceOnUse"><stop offset=".368" stop-color="#ffcf09"/><stop offset=".718" stop-color="#ffcf09" stop-opacity=".7"/><stop offset="1" stop-color="#ffcf09" stop-opacity="0"/></radialGradient><radialGradient id="prefix__c" cx="14.295" cy="23.291" fx="14.295" fy="23.291" r="11.878" gradientTransform="matrix(1.3272 0 0 1.0073 -3.434 -.672)" gradientUnits="userSpaceOnUse"><stop offset=".383" stop-color="#34a853"/><stop offset=".706" stop-color="#34a853" stop-opacity=".7"/><stop offset="1" stop-color="#34a853" stop-opacity="0"/></radialGradient><linearGradient id="prefix__d" x1="23.558" y1="6.286" x2="12.148" y2="20.299" gradientUnits="userSpaceOnUse"><stop offset=".671" stop-color="#4285f4"/><stop offset=".885" stop-color="#4285f4" stop-opacity="0"/></linearGradient><clipPath id="prefix__a"><path d="M22.36 10H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53h-.013l.013-.01c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09c.87-2.6 3.3-4.53 6.16-4.53 1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07 1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93v.01C3.99 20.53 7.7 23 12 23c2.97 0 5.46-.98 7.28-2.66 2.08-1.92 3.28-4.74 3.28-8.09 0-.78-.07-1.53-.2-2.25z" fill="none"/></clipPath></defs><path d="M22.36 10H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53h-.013l.013-.01c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09c.87-2.6 3.3-4.53 6.16-4.53 1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07 1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93v.01C3.99 20.53 7.7 23 12 23c2.97 0 5.46-.98 7.28-2.66 2.08-1.92 3.28-4.74 3.28-8.09 0-.78-.07-1.53-.2-2.25z" fill="#fc4c53"/><g clip-path="url(#prefix__a)"><ellipse cx="3.646" cy="13.572" rx="7.755" ry="10.469" fill="url(#prefix__b)"/><ellipse cx="15.538" cy="22.789" rx="15.765" ry="11.965" transform="rotate(-7.12 15.539 22.789)" fill="url(#prefix__c)"/><path fill="url(#prefix__d)" d="M11.105 8.28l.491 5.596.623 3.747 7.362 6.848 8.607-15.897-17.083-.294z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 705 B After Width: | Height: | Size: 2.2 KiB |
|
|
@ -1,6 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<path fill="#212121" fill-rule="evenodd" d="M10.904,6h26.191C39.804,6,42,8.196,42,10.909v26.191C42,39.804,39.804,42,37.096,42H10.904C8.196,42,6,39.804,6,37.091V10.909C6,8.196,8.196,6,10.904,6z" clip-rule="evenodd"/>
|
||||
<path fill="#ec407a" fill-rule="evenodd" d="M29.208,20.607c1.576,1.126,3.507,1.788,5.592,1.788v-4.011c-0.395,0-0.788-0.041-1.174-0.123v3.157c-2.085,0-4.015-0.663-5.592-1.788v8.184c0,4.094-3.321,7.413-7.417,7.413c-1.528,0-2.949-0.462-4.129-1.254c1.347,1.376,3.225,2.23,5.303,2.23c4.096,0,7.417-3.319,7.417-7.413L29.208,20.607L29.208,20.607z M30.657,16.561c-0.805-0.879-1.334-2.016-1.449-3.273v-0.516h-1.113C28.375,14.369,29.331,15.734,30.657,16.561L30.657,16.561z M19.079,30.832c-0.45-0.59-0.693-1.311-0.692-2.053c0-1.873,1.519-3.391,3.393-3.391c0.349,0,0.696,0.053,1.029,0.159v-4.1c-0.389-0.053-0.781-0.076-1.174-0.068v3.191c-0.333-0.106-0.68-0.16-1.03-0.159c-1.874,0-3.392,1.518-3.392,3.392C17.213,29.156,17.972,30.31,19.079,30.832z" clip-rule="evenodd"/>
|
||||
<path fill="#fff" fill-rule="evenodd" d="M28.034,19.63c1.576,1.126,3.507,1.788,5.592,1.788v-3.157c-1.164-0.248-2.194-0.856-2.969-1.701c-1.326-0.827-2.282-2.191-2.561-3.789h-2.923v16.018c-0.007,1.867-1.523,3.379-3.393,3.379c-1.102,0-2.081-0.525-2.701-1.338c-1.107-0.522-1.866-1.678-1.866-3.011c0-1.874,1.518-3.392,3.392-3.392c0.359,0,0.705,0.056,1.03,0.159v-3.191c-4.024,0.083-7.26,3.369-7.26,7.411c0,2.018,0.806,3.847,2.114,5.183c1.18,0.792,2.601,1.254,4.129,1.254c4.096,0,7.417-3.319,7.417-7.413L28.034,19.63z" clip-rule="evenodd"/>
|
||||
<path fill="#81ecec" fill-rule="evenodd" d="M33.626,18.261v-0.854c-1.05,0.002-2.078-0.292-2.969-0.848C31.445,17.423,32.483,18.018,33.626,18.261z M28.095,12.771c-0.027-0.153-0.047-0.306-0.061-0.461v-0.516h-4.036v16.019c-0.006,1.867-1.522,3.379-3.393,3.379c-0.549,0-1.068-0.13-1.527-0.362c0.62,0.813,1.599,1.338,2.701,1.338c1.87,0,3.386-1.512,3.393-3.379V12.771H28.095z M21.35,21.657v-0.909c-0.337-0.046-0.677-0.069-1.017-0.069c-4.097,0-7.418,3.319-7.418,7.413c0,2.567,1.305,4.829,3.289,6.159c-1.308-1.336-2.114-3.165-2.114-5.183C14.09,25.026,17.326,21.74,21.35,21.657z"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" id="tiktok">
|
||||
<path fill="#070201" fill-rule="evenodd" d="m60,12c0-4.42-3.58-8-8-8H12C7.58,4,4,7.58,4,12v40c0,4.42,3.58,8,8,8h40c4.42,0,8-3.58,8-8V12h0Z"></path>
|
||||
<path fill="#fe2c55" fill-rule="evenodd" d="m47.64,27.65c0,.3-.13.58-.37.77-.23.19-.53.22-.83.21-1.86-.05-4.77-.69-6.14-2v12.54c0,5.78-4.68,10.46-10.46,10.46h-1.08c-2.42,0-4.72-.88-6.58-2.39,1.43.71,3,1.13,4.63,1.13h1.08c5.78,0,10.46-4.68,10.46-10.46v-12.54c1.37,1.3,4.28,1.95,6.14,2,.3,0,.6-.02.83-.21.23-.19.37-.47.37-.77,0-1.42,0-3.78,0-5.02.38.11.77.2,1.16.29.46.1.79.5.79.97,0,1.24,0,3.61,0,5.02Zm-19.58,4.43c-.19.19-.44.29-.71.29-2.76,0-5,2.24-5,5,0,2.17,1.39,4,3.33,4.69-.85-.9-1.38-2.1-1.38-3.43,0-2.76,2.24-5,5-5,.27,0,.52-.1.71-.29.19-.19.29-.44.29-.71v-3c0-.26-.11-.52-.29-.71s-.44-.29-.71-.29h-.54c-.14,0-.27.04-.41.04v2.7c0,.27-.11.52-.29.71Zm13.67-12.69c-.83-.75-1.53-1.74-2.03-3.09-.15-.39-.52-.67-.94-.67h-.74c.87,1.91,2.16,3.03,3.71,3.75Z"></path>
|
||||
<path fill="#25f4ee" fill-rule="evenodd" d="m21.37,46.57c.25.25.55.45.82.67-1.01-.5-1.96-1.12-2.77-1.93-1.96-1.96-3.06-4.62-3.06-7.4v-.08c0-5.78,4.68-10.46,10.46-10.46h.54c.27,0,.52.11.71.29.19.19.29.44.29.71v.3c-5.58.22-10.05,4.78-10.05,10.42v.08c0,2.77,1.1,5.43,3.06,7.4Zm24.31-25.2h0c0-.47-.33-.88-.79-.97-1.12-.25-2.19-.55-3.17-1.01,1.11,1,2.47,1.57,3.95,1.98Zm-16.38,22.27c1.33,0,2.6-.53,3.54-1.46s1.46-2.21,1.46-3.54v-22c0-.55.45-1,1-1h2.72c-.09-.2-.19-.38-.27-.6-.15-.39-.52-.67-.94-.67h-3.46c-.55,0-1,.45-1,1v22c0,1.33-.53,2.6-1.46,3.54s-2.21,1.46-3.54,1.46c-.59,0-1.15-.12-1.67-.31.91.96,2.19,1.57,3.62,1.57Z"></path>
|
||||
<path fill="#fff" fill-rule="evenodd" d="m27.9,48.37c5.78,0,10.46-4.68,10.46-10.46v-12.54c1.37,1.3,4.28,1.95,6.14,2,.3,0,.6-.02.83-.21.23-.19.37-.47.37-.77,0-1.42,0-3.78,0-5.02-1.48-.41-2.84-.98-3.95-1.98-1.54-.72-2.84-1.85-3.71-3.75h-2.72c-.55,0-1,.45-1,1v22c0,1.33-.53,2.6-1.46,3.54s-2.21,1.46-3.54,1.46c-1.43,0-2.71-.61-3.62-1.57-1.93-.69-3.33-2.52-3.33-4.69,0-2.76,2.24-5,5-5,.27,0,.52-.1.71-.29.19-.19.29-.44.29-.71v-2.7c-5.58.22-10.05,4.78-10.05,10.42v.08c0,2.77,1.1,5.43,3.06,7.4.25.25.55.45.82.67,1.43.71,3,1.13,4.63,1.13h1.08Z"></path>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
1
surfsense_web/svgr.d.ts
vendored
|
|
@ -1,5 +1,6 @@
|
|||
declare module "*.svg" {
|
||||
import type { FC, SVGProps } from "react";
|
||||
|
||||
const content: FC<SVGProps<SVGSVGElement>>;
|
||||
export default content;
|
||||
}
|
||||
|
|
|
|||