Remove roocode.com web app (#12375)
Some checks failed
Code QA Roo Code / platform-unit-test (windows-latest) (push) Has been cancelled
Code QA Roo Code / check-translations (push) Has been cancelled
Code QA Roo Code / knip (push) Has been cancelled
Code QA Roo Code / compile (push) Has been cancelled
Code QA Roo Code / platform-unit-test (ubuntu-latest) (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy docs to GitHub Pages / build (push) Has been cancelled
Nightly Publish / publish-nightly (push) Has been cancelled
Deploy docs to GitHub Pages / deploy (push) Has been cancelled
59
.github/workflows/website-deploy.yml
vendored
|
|
@ -1,59 +0,0 @@
|
|||
name: Deploy roocode.com
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'apps/web-roo-code/**'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-roocode-com
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
|
||||
jobs:
|
||||
check-secrets:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
has-vercel-token: ${{ steps.check.outputs.has-vercel-token }}
|
||||
steps:
|
||||
- name: Check if VERCEL_TOKEN exists
|
||||
id: check
|
||||
run: |
|
||||
if [ -n "${{ secrets.VERCEL_TOKEN }}" ]; then
|
||||
echo "has-vercel-token=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has-vercel-token=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: check-secrets
|
||||
if: ${{ needs.check-secrets.outputs.has-vercel-token == 'true' }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js and pnpm
|
||||
uses: ./.github/actions/setup-node-pnpm
|
||||
- name: Run lint
|
||||
run: pnpm lint
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run type check
|
||||
run: pnpm check-types
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run build
|
||||
run: pnpm build
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Install Vercel CLI
|
||||
run: npm install --global vercel@latest
|
||||
- name: Pull Vercel Environment Information
|
||||
run: npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
|
||||
- name: Build Project Artifacts
|
||||
run: npx vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
|
||||
- name: Deploy Project Artifacts to Vercel
|
||||
run: npx vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
|
||||
102
.github/workflows/website-preview.yml
vendored
|
|
@ -1,102 +0,0 @@
|
|||
name: Preview roocode.com
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- main
|
||||
paths:
|
||||
- "apps/web-roo-code/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "apps/web-roo-code/**"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: preview-roocode-com-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
|
||||
jobs:
|
||||
check-secrets:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
has-vercel-token: ${{ steps.check.outputs.has-vercel-token }}
|
||||
steps:
|
||||
- name: Check if VERCEL_TOKEN exists
|
||||
id: check
|
||||
run: |
|
||||
if [ -n "${{ secrets.VERCEL_TOKEN }}" ]; then
|
||||
echo "has-vercel-token=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has-vercel-token=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
preview:
|
||||
runs-on: ubuntu-latest
|
||||
needs: check-secrets
|
||||
if: ${{ needs.check-secrets.outputs.has-vercel-token == 'true' }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js and pnpm
|
||||
uses: ./.github/actions/setup-node-pnpm
|
||||
- name: Run lint
|
||||
run: pnpm lint
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run type check
|
||||
run: pnpm check-types
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run build
|
||||
run: pnpm build
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Install Vercel CLI
|
||||
run: npm install --global vercel@latest
|
||||
- name: Pull Vercel Environment Information
|
||||
run: npx vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
|
||||
- name: Build Project Artifacts
|
||||
run: npx vercel build --token=${{ secrets.VERCEL_TOKEN }}
|
||||
- name: Deploy Project Artifacts to Vercel
|
||||
id: deploy
|
||||
run: |
|
||||
DEPLOYMENT_URL=$(npx vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})
|
||||
echo "deployment_url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT
|
||||
echo "Preview deployed to: $DEPLOYMENT_URL"
|
||||
|
||||
- name: Comment PR with preview link
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const deploymentUrl = '${{ steps.deploy.outputs.deployment_url }}';
|
||||
const commentIdentifier = '<!-- roo-preview-comment -->';
|
||||
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
});
|
||||
|
||||
const existingComment = comments.find(comment =>
|
||||
comment.body.includes(commentIdentifier)
|
||||
);
|
||||
|
||||
const comment = commentIdentifier + '\n🚀 **Preview deployed!**\n\nYour changes have been deployed to Vercel:\n\n**Preview URL:** ' + deploymentUrl + '\n\nThis preview will be updated automatically when you push new commits to this PR.';
|
||||
|
||||
if (existingComment) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existingComment.id,
|
||||
body: comment
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: comment
|
||||
});
|
||||
}
|
||||
46
apps/web-roo-code/.gitignore
vendored
|
|
@ -1,46 +0,0 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
!.env.example
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# generated files
|
||||
/public/sitemap*.xml
|
||||
/public/robots.txt
|
||||
|
|
@ -1 +0,0 @@
|
|||
enable-pre-post-scripts=true
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# @roo-code/web-roo-code
|
||||
|
||||
## 0.0.1
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/app/globals.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { nextJsConfig } from "@roo-code/config-eslint/next-js"
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
export default [...nextJsConfig]
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const matter = require('gray-matter');
|
||||
|
||||
/**
|
||||
* Get published blog posts for sitemap
|
||||
* Note: This runs at build time, so recently-scheduled posts may lag
|
||||
*/
|
||||
function getPublishedBlogPosts() {
|
||||
const BLOG_DIR = path.join(process.cwd(), 'src/content/blog');
|
||||
|
||||
if (!fs.existsSync(BLOG_DIR)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(BLOG_DIR).filter(f => f.endsWith('.md'));
|
||||
const posts = [];
|
||||
|
||||
// Get current time in PT for publish check
|
||||
const formatter = new Intl.DateTimeFormat('en-US', {
|
||||
timeZone: 'America/Los_Angeles',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false,
|
||||
});
|
||||
|
||||
const parts = formatter.formatToParts(new Date());
|
||||
const get = (type) => parts.find(p => p.type === type)?.value ?? '';
|
||||
const nowDate = `${get('year')}-${get('month')}-${get('day')}`;
|
||||
const nowMinutes = parseInt(get('hour')) * 60 + parseInt(get('minute'));
|
||||
|
||||
for (const file of files) {
|
||||
const filepath = path.join(BLOG_DIR, file);
|
||||
const raw = fs.readFileSync(filepath, 'utf8');
|
||||
const { data } = matter(raw);
|
||||
|
||||
// Check if post is published
|
||||
if (data.status !== 'published') continue;
|
||||
|
||||
// Parse publish time
|
||||
const timeMatch = data.publish_time_pt?.match(/^(1[0-2]|[1-9]):([0-5][0-9])(am|pm)$/i);
|
||||
if (!timeMatch) continue;
|
||||
|
||||
let hours = parseInt(timeMatch[1]);
|
||||
const mins = parseInt(timeMatch[2]);
|
||||
const isPm = timeMatch[3].toLowerCase() === 'pm';
|
||||
if (hours === 12) hours = isPm ? 12 : 0;
|
||||
else if (isPm) hours += 12;
|
||||
const postMinutes = hours * 60 + mins;
|
||||
|
||||
// Check if post is past publish date/time
|
||||
const isPublished = nowDate > data.publish_date ||
|
||||
(nowDate === data.publish_date && nowMinutes >= postMinutes);
|
||||
|
||||
if (isPublished && data.slug) {
|
||||
posts.push(data.slug);
|
||||
}
|
||||
}
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
/** @type {import('next-sitemap').IConfig} */
|
||||
module.exports = {
|
||||
siteUrl: process.env.NEXT_PUBLIC_SITE_URL || 'https://roocode.com',
|
||||
generateRobotsTxt: true,
|
||||
generateIndexSitemap: false, // We don't need index sitemap for a small site
|
||||
changefreq: 'monthly',
|
||||
priority: 0.7,
|
||||
sitemapSize: 5000,
|
||||
exclude: [
|
||||
'/api/*',
|
||||
'/server-sitemap-index.xml',
|
||||
'/404',
|
||||
'/500',
|
||||
'/_not-found',
|
||||
],
|
||||
robotsTxtOptions: {
|
||||
policies: [
|
||||
{
|
||||
userAgent: '*',
|
||||
allow: '/',
|
||||
},
|
||||
],
|
||||
additionalSitemaps: [
|
||||
// Add any additional sitemaps here if needed in the future
|
||||
],
|
||||
},
|
||||
// Custom transform function to set specific priorities and change frequencies
|
||||
transform: async (config, path) => {
|
||||
// Set custom priority for specific pages
|
||||
let priority = config.priority;
|
||||
let changefreq = config.changefreq;
|
||||
|
||||
if (path === '/') {
|
||||
priority = 1.0;
|
||||
changefreq = 'yearly';
|
||||
} else if (path === '/privacy' || path === '/terms') {
|
||||
priority = 0.5;
|
||||
changefreq = 'yearly';
|
||||
} else if (path === '/blog') {
|
||||
priority = 0.8;
|
||||
changefreq = 'weekly';
|
||||
} else if (path.startsWith('/blog/')) {
|
||||
priority = 0.7;
|
||||
changefreq = 'monthly';
|
||||
}
|
||||
|
||||
return {
|
||||
loc: path,
|
||||
changefreq,
|
||||
priority,
|
||||
lastmod: config.autoLastmod ? new Date().toISOString() : undefined,
|
||||
alternateRefs: config.alternateRefs ?? [],
|
||||
};
|
||||
},
|
||||
additionalPaths: async (config) => {
|
||||
const result = [];
|
||||
|
||||
// Add /blog index
|
||||
result.push({
|
||||
loc: '/blog',
|
||||
changefreq: 'weekly',
|
||||
priority: 0.8,
|
||||
lastmod: new Date().toISOString(),
|
||||
});
|
||||
|
||||
// Add published blog posts
|
||||
try {
|
||||
const slugs = getPublishedBlogPosts();
|
||||
for (const slug of slugs) {
|
||||
result.push({
|
||||
loc: `/blog/${slug}`,
|
||||
changefreq: 'monthly',
|
||||
priority: 0.7,
|
||||
lastmod: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Could not load blog posts for sitemap:', e.message);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import path from "path"
|
||||
import type { NextConfig } from "next"
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
turbopack: {
|
||||
root: path.join(__dirname, "../.."),
|
||||
},
|
||||
async redirects() {
|
||||
return [
|
||||
{
|
||||
source: "/:path*",
|
||||
destination: "https://roomote.dev",
|
||||
permanent: true,
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
"name": "@roo-code/web-roo-code",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"lint": "eslint src --ext=ts,tsx --max-warnings=0",
|
||||
"check-types": "tsc --noEmit",
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"postbuild": "next-sitemap --config next-sitemap.config.cjs",
|
||||
"start": "next start",
|
||||
"clean": "rimraf .next .turbo",
|
||||
"test": "vitest run --passWithNoTests",
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.14",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@roo-code/types": "^1.108.0",
|
||||
"@tanstack/react-query": "^5.90.20",
|
||||
"@vercel/og": "^0.8.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"embla-carousel-auto-scroll": "^8.6.0",
|
||||
"embla-carousel-autoplay": "^8.6.0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"framer-motion": "^12.29.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"lucide-react": "^0.563.0",
|
||||
"next": "^16.1.6",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^18.3.1",
|
||||
"react-cookie-consent": "^9.0.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-markdown": "^9.0.3",
|
||||
"recharts": "^2.15.3",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tldts": "^6.1.86",
|
||||
"zod": "^3.25.61"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@roo-code/config-eslint": "workspace:^",
|
||||
"@roo-code/config-typescript": "workspace:^",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@types/node": "20.x",
|
||||
"@types/react": "^18.3.23",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"next-sitemap": "^4.2.3",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"vitest": "^4.0.18"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<svg width="120" height="21" viewBox="0 0 120 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M27.6939 0.698856L27.0853 2.88004C27.0531 2.99552 26.9315 3.06224 26.8157 3.02799L16.6072 0.00893058C16.5393 -0.0111487 16.4658 0.00308892 16.4106 0.047029L6.30049 8.08333C6.27097 8.10679 6.23575 8.12215 6.19836 8.12786L0.18292 9.04674C0.0715357 9.06375 -0.0078759 9.16286 0.000622655 9.27425L0.0267609 9.61687C0.035109 9.72631 0.125665 9.81172 0.236347 9.81456L7.22353 9.99359L7.30322 9.9958L12.4661 7.2622C12.5383 7.22393 12.6263 7.22955 12.693 7.27669L16.3507 9.86111C16.408 9.90164 16.4418 9.96737 16.4412 10.0372L16.4103 13.4664C16.4099 13.5108 16.4235 13.5542 16.4491 13.5906L21.5943 20.9084C21.6346 20.9658 21.7007 21 21.7713 21H23.4001C23.5626 21 23.6668 20.8287 23.5909 20.6863L19.9237 13.8002C19.8878 13.7328 19.8908 13.6516 19.9315 13.5871L21.8435 10.551C21.8643 10.5179 21.8939 10.4912 21.9289 10.4735L28.7648 7.03514C28.8342 7.00021 28.9173 7.00508 28.9821 7.0479L30.9355 8.33851C30.971 8.36193 31.0126 8.37442 31.0552 8.37442H32.83C33.0019 8.37442 33.1047 8.18497 33.0101 8.04276L28.082 0.63809C27.98 0.484786 27.7433 0.521844 27.6939 0.698856Z" fill="black"/>
|
||||
<path d="M46.6228 8.1575H49.66C50.2957 8.1575 50.7725 8.0175 51.0903 7.7375C51.4082 7.4575 51.5671 7.0025 51.5671 6.3725C51.5671 5.76583 51.4082 5.32833 51.0903 5.06C50.7725 4.78 50.2957 4.64 49.66 4.64H46.6228V8.1575ZM43.8504 2.505H50.6489C51.2139 2.505 51.7201 2.59833 52.1675 2.785C52.6266 2.96 53.0151 3.205 53.3329 3.52C53.6625 3.835 53.9097 4.2025 54.0745 4.6225C54.2511 5.03083 54.3394 5.47417 54.3394 5.9525C54.3394 6.6875 54.1805 7.32333 53.8627 7.86C53.5566 8.39667 53.0504 8.805 52.344 9.085V9.12C52.6854 9.21333 52.968 9.35917 53.1916 9.5575C53.4153 9.74417 53.5978 9.97167 53.739 10.24C53.8803 10.4967 53.9804 10.7825 54.0392 11.0975C54.1099 11.4125 54.157 11.7275 54.1805 12.0425C54.1923 12.2408 54.204 12.4742 54.2158 12.7425C54.2276 13.0108 54.2452 13.285 54.2688 13.565C54.3041 13.845 54.3512 14.1133 54.4101 14.37C54.4807 14.615 54.5808 14.825 54.7102 15H51.9379C51.7849 14.6033 51.6907 14.1308 51.6554 13.5825C51.6201 13.0342 51.5671 12.5092 51.4964 12.0075C51.4023 11.3542 51.2021 10.8758 50.8961 10.5725C50.59 10.2692 50.0897 10.1175 49.3951 10.1175H46.6228V15H43.8504V2.505Z" fill="black"/>
|
||||
<path d="M57.6712 10.485C57.6712 10.8467 57.7065 11.2025 57.7771 11.5525C57.8478 11.8908 57.9655 12.2 58.1303 12.48C58.3069 12.7483 58.5364 12.9642 58.819 13.1275C59.1015 13.2908 59.4547 13.3725 59.8785 13.3725C60.3023 13.3725 60.6554 13.2908 60.9379 13.1275C61.2322 12.9642 61.4618 12.7483 61.6266 12.48C61.8032 12.2 61.9268 11.8908 61.9974 11.5525C62.0681 11.2025 62.1034 10.8467 62.1034 10.485C62.1034 10.1233 62.0681 9.7675 61.9974 9.4175C61.9268 9.0675 61.8032 8.75833 61.6266 8.49C61.4618 8.22167 61.2322 8.00583 60.9379 7.8425C60.6554 7.6675 60.3023 7.58 59.8785 7.58C59.4547 7.58 59.1015 7.6675 58.819 7.8425C58.5364 8.00583 58.3069 8.22167 58.1303 8.49C57.9655 8.75833 57.8478 9.0675 57.7771 9.4175C57.7065 9.7675 57.6712 10.1233 57.6712 10.485ZM55.1637 10.485C55.1637 9.76167 55.2755 9.10833 55.4992 8.525C55.7229 7.93 56.0407 7.42833 56.4528 7.02C56.8648 6.6 57.3592 6.27917 57.936 6.0575C58.5129 5.82417 59.1604 5.7075 59.8785 5.7075C60.5966 5.7075 61.244 5.82417 61.8209 6.0575C62.4095 6.27917 62.9098 6.6 63.3218 7.02C63.7338 7.42833 64.0517 7.93 64.2754 8.525C64.499 9.10833 64.6109 9.76167 64.6109 10.485C64.6109 11.2083 64.499 11.8617 64.2754 12.445C64.0517 13.0283 63.7338 13.53 63.3218 13.95C62.9098 14.3583 62.4095 14.6733 61.8209 14.895C61.244 15.1167 60.5966 15.2275 59.8785 15.2275C59.1604 15.2275 58.5129 15.1167 57.936 14.895C57.3592 14.6733 56.8648 14.3583 56.4528 13.95C56.0407 13.53 55.7229 13.0283 55.4992 12.445C55.2755 11.8617 55.1637 11.2083 55.1637 10.485Z" fill="black"/>
|
||||
<path d="M67.5832 10.485C67.5832 10.8467 67.6185 11.2025 67.6892 11.5525C67.7598 11.8908 67.8775 12.2 68.0424 12.48C68.2189 12.7483 68.4485 12.9642 68.731 13.1275C69.0135 13.2908 69.3667 13.3725 69.7905 13.3725C70.2143 13.3725 70.5675 13.2908 70.85 13.1275C71.1443 12.9642 71.3739 12.7483 71.5387 12.48C71.7153 12.2 71.8389 11.8908 71.9095 11.5525C71.9801 11.2025 72.0155 10.8467 72.0155 10.485C72.0155 10.1233 71.9801 9.7675 71.9095 9.4175C71.8389 9.0675 71.7153 8.75833 71.5387 8.49C71.3739 8.22167 71.1443 8.00583 70.85 7.8425C70.5675 7.6675 70.2143 7.58 69.7905 7.58C69.3667 7.58 69.0135 7.6675 68.731 7.8425C68.4485 8.00583 68.2189 8.22167 68.0424 8.49C67.8775 8.75833 67.7598 9.0675 67.6892 9.4175C67.6185 9.7675 67.5832 10.1233 67.5832 10.485ZM65.0758 10.485C65.0758 9.76167 65.1876 9.10833 65.4113 8.525C65.6349 7.93 65.9528 7.42833 66.3648 7.02C66.7768 6.6 67.2713 6.27917 67.8481 6.0575C68.4249 5.82417 69.0724 5.7075 69.7905 5.7075C70.5086 5.7075 71.1561 5.82417 71.7329 6.0575C72.3215 6.27917 72.8218 6.6 73.2339 7.02C73.6459 7.42833 73.9637 7.93 74.1874 8.525C74.4111 9.10833 74.5229 9.76167 74.5229 10.485C74.5229 11.2083 74.4111 11.8617 74.1874 12.445C73.9637 13.0283 73.6459 13.53 73.2339 13.95C72.8218 14.3583 72.3215 14.6733 71.7329 14.895C71.1561 15.1167 70.5086 15.2275 69.7905 15.2275C69.0724 15.2275 68.4249 15.1167 67.8481 14.895C67.2713 14.6733 66.7768 14.3583 66.3648 13.95C65.9528 13.53 65.6349 13.0283 65.4113 12.445C65.1876 11.8617 65.0758 11.2083 65.0758 10.485Z" fill="black"/>
|
||||
<path d="M87.9723 6.705C87.9252 6.39 87.8192 6.10417 87.6544 5.8475C87.4896 5.57917 87.2836 5.34583 87.0364 5.1475C86.7892 4.94917 86.5067 4.7975 86.1888 4.6925C85.8827 4.57583 85.559 4.5175 85.2176 4.5175C84.5937 4.5175 84.0639 4.64 83.6284 4.885C83.1928 5.11833 82.8396 5.43917 82.5689 5.8475C82.2981 6.24417 82.098 6.69917 81.9685 7.2125C81.8508 7.72583 81.7919 8.25667 81.7919 8.805C81.7919 9.33 81.8508 9.84333 81.9685 10.345C82.098 10.835 82.2981 11.2783 82.5689 11.675C82.8396 12.0717 83.1928 12.3925 83.6284 12.6375C84.0639 12.8708 84.5937 12.9875 85.2176 12.9875C86.0652 12.9875 86.7244 12.7308 87.1953 12.2175C87.678 11.7042 87.9723 11.0275 88.0782 10.1875H90.7623C90.6916 10.9692 90.5092 11.675 90.2149 12.305C89.9206 12.935 89.5321 13.4717 89.0494 13.915C88.5668 14.3583 88.0017 14.6967 87.3542 14.93C86.7068 15.1633 85.9946 15.28 85.2176 15.28C84.2523 15.28 83.3811 15.1167 82.6042 14.79C81.839 14.4517 81.1915 13.9908 80.6618 13.4075C80.132 12.8242 79.7259 12.1417 79.4434 11.36C79.1608 10.5667 79.0196 9.715 79.0196 8.805C79.0196 7.87167 79.1608 7.00833 79.4434 6.215C79.7259 5.41 80.132 4.71 80.6618 4.115C81.1915 3.52 81.839 3.05333 82.6042 2.715C83.3811 2.37667 84.2523 2.2075 85.2176 2.2075C85.9122 2.2075 86.5655 2.30667 87.1777 2.505C87.8016 2.70333 88.3549 2.995 88.8375 3.38C89.332 3.75333 89.7381 4.22 90.056 4.78C90.3738 5.34 90.5739 5.98167 90.6563 6.705H87.9723Z" fill="black"/>
|
||||
<path d="M93.7326 10.485C93.7326 10.8467 93.7679 11.2025 93.8385 11.5525C93.9092 11.8908 94.0269 12.2 94.1917 12.48C94.3683 12.7483 94.5978 12.9642 94.8804 13.1275C95.1629 13.2908 95.5161 13.3725 95.9399 13.3725C96.3637 13.3725 96.7168 13.2908 96.9994 13.1275C97.2937 12.9642 97.5232 12.7483 97.688 12.48C97.8646 12.2 97.9882 11.8908 98.0589 11.5525C98.1295 11.2025 98.1648 10.8467 98.1648 10.485C98.1648 10.1233 98.1295 9.7675 98.0589 9.4175C97.9882 9.0675 97.8646 8.75833 97.688 8.49C97.5232 8.22167 97.2937 8.00583 96.9994 7.8425C96.7168 7.6675 96.3637 7.58 95.9399 7.58C95.5161 7.58 95.1629 7.6675 94.8804 7.8425C94.5978 8.00583 94.3683 8.22167 94.1917 8.49C94.0269 8.75833 93.9092 9.0675 93.8385 9.4175C93.7679 9.7675 93.7326 10.1233 93.7326 10.485ZM91.2251 10.485C91.2251 9.76167 91.337 9.10833 91.5606 8.525C91.7843 7.93 92.1021 7.42833 92.5142 7.02C92.9262 6.6 93.4206 6.27917 93.9975 6.0575C94.5743 5.82417 95.2218 5.7075 95.9399 5.7075C96.658 5.7075 97.3054 5.82417 97.8823 6.0575C98.4709 6.27917 98.9712 6.6 99.3832 7.02C99.7953 7.42833 100.113 7.93 100.337 8.525C100.56 9.10833 100.672 9.76167 100.672 10.485C100.672 11.2083 100.56 11.8617 100.337 12.445C100.113 13.0283 99.7953 13.53 99.3832 13.95C98.9712 14.3583 98.4709 14.6733 97.8823 14.895C97.3054 15.1167 96.658 15.2275 95.9399 15.2275C95.2218 15.2275 94.5743 15.1167 93.9975 14.895C93.4206 14.6733 92.9262 14.3583 92.5142 13.95C92.1021 13.53 91.7843 13.0283 91.5606 12.445C91.337 11.8617 91.2251 11.2083 91.2251 10.485Z" fill="black"/>
|
||||
<path d="M107.9 10.45C107.9 10.0767 107.865 9.72083 107.794 9.3825C107.724 9.0325 107.6 8.72917 107.424 8.4725C107.259 8.20417 107.041 7.98833 106.77 7.825C106.499 7.66167 106.158 7.58 105.746 7.58C105.334 7.58 104.987 7.66167 104.704 7.825C104.422 7.98833 104.192 8.20417 104.015 8.4725C103.851 8.74083 103.727 9.05 103.645 9.4C103.574 9.73833 103.539 10.0942 103.539 10.4675C103.539 10.8175 103.58 11.1675 103.662 11.5175C103.745 11.8675 103.874 12.1825 104.051 12.4625C104.239 12.7308 104.469 12.9525 104.739 13.1275C105.022 13.2908 105.357 13.3725 105.746 13.3725C106.158 13.3725 106.499 13.2908 106.77 13.1275C107.053 12.9642 107.276 12.7483 107.441 12.48C107.606 12.2 107.724 11.885 107.794 11.535C107.865 11.185 107.9 10.8233 107.9 10.45ZM107.936 13.845H107.9C107.606 14.335 107.218 14.6908 106.735 14.9125C106.264 15.1225 105.728 15.2275 105.128 15.2275C104.445 15.2275 103.845 15.0992 103.327 14.8425C102.809 14.5742 102.379 14.2183 102.038 13.775C101.708 13.32 101.455 12.8008 101.278 12.2175C101.114 11.6342 101.031 11.0275 101.031 10.3975C101.031 9.79083 101.114 9.2075 101.278 8.6475C101.455 8.07583 101.708 7.57417 102.038 7.1425C102.379 6.71083 102.803 6.36667 103.309 6.11C103.815 5.84167 104.404 5.7075 105.075 5.7075C105.616 5.7075 106.129 5.82417 106.611 6.0575C107.106 6.27917 107.494 6.61167 107.777 7.055H107.812V2.505H110.319V15H107.936V13.845Z" fill="black"/>
|
||||
<path d="M117.477 9.505C117.359 8.875 117.147 8.39667 116.841 8.07C116.547 7.74333 116.094 7.58 115.481 7.58C115.081 7.58 114.746 7.65 114.475 7.79C114.216 7.91833 114.004 8.08167 113.839 8.28C113.686 8.47833 113.574 8.68833 113.504 8.91C113.445 9.13167 113.41 9.33 113.398 9.505H117.477ZM113.398 11.08C113.433 11.885 113.639 12.4683 114.016 12.83C114.393 13.1917 114.934 13.3725 115.64 13.3725C116.147 13.3725 116.582 13.25 116.947 13.005C117.312 12.7483 117.536 12.48 117.618 12.2H119.825C119.472 13.285 118.931 14.0608 118.201 14.5275C117.471 14.9942 116.588 15.2275 115.552 15.2275C114.834 15.2275 114.187 15.1167 113.61 14.895C113.033 14.6617 112.544 14.335 112.144 13.915C111.744 13.495 111.432 12.9933 111.208 12.41C110.996 11.8267 110.89 11.185 110.89 10.485C110.89 9.80833 111.002 9.17833 111.226 8.595C111.449 8.01167 111.767 7.51 112.179 7.09C112.591 6.65833 113.08 6.32 113.645 6.075C114.222 5.83 114.858 5.7075 115.552 5.7075C116.329 5.7075 117.006 5.85917 117.583 6.1625C118.16 6.45417 118.631 6.85083 118.995 7.3525C119.372 7.85417 119.643 8.42583 119.808 9.0675C119.973 9.70917 120.031 10.38 119.984 11.08H113.398Z" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 10 KiB |
|
|
@ -1,10 +0,0 @@
|
|||
<svg width="120" height="21" viewBox="0 0 120 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M27.6939 0.698856L27.0853 2.88004C27.0531 2.99552 26.9315 3.06224 26.8157 3.02799L16.6072 0.00893058C16.5393 -0.0111487 16.4658 0.00308892 16.4106 0.047029L6.30049 8.08333C6.27097 8.10679 6.23575 8.12215 6.19836 8.12786L0.18292 9.04674C0.0715357 9.06375 -0.0078759 9.16286 0.000622655 9.27425L0.0267609 9.61687C0.035109 9.72631 0.125665 9.81172 0.236347 9.81456L7.22353 9.99359L7.30322 9.9958L12.4661 7.2622C12.5383 7.22393 12.6263 7.22955 12.693 7.27669L16.3507 9.86111C16.408 9.90164 16.4418 9.96737 16.4412 10.0372L16.4103 13.4664C16.4099 13.5108 16.4235 13.5542 16.4491 13.5906L21.5943 20.9084C21.6346 20.9658 21.7007 21 21.7713 21H23.4001C23.5626 21 23.6668 20.8287 23.5909 20.6863L19.9237 13.8002C19.8878 13.7328 19.8908 13.6516 19.9315 13.5871L21.8435 10.551C21.8643 10.5179 21.8939 10.4912 21.9289 10.4735L28.7648 7.03514C28.8342 7.00021 28.9173 7.00508 28.9821 7.0479L30.9355 8.33851C30.971 8.36193 31.0126 8.37442 31.0552 8.37442H32.83C33.0019 8.37442 33.1047 8.18497 33.0101 8.04276L28.082 0.63809C27.98 0.484786 27.7433 0.521844 27.6939 0.698856Z" fill="white"/>
|
||||
<path d="M46.6228 8.1575H49.66C50.2957 8.1575 50.7725 8.0175 51.0903 7.7375C51.4082 7.4575 51.5671 7.0025 51.5671 6.3725C51.5671 5.76583 51.4082 5.32833 51.0903 5.06C50.7725 4.78 50.2957 4.64 49.66 4.64H46.6228V8.1575ZM43.8504 2.505H50.6489C51.2139 2.505 51.7201 2.59833 52.1675 2.785C52.6266 2.96 53.0151 3.205 53.3329 3.52C53.6625 3.835 53.9097 4.2025 54.0745 4.6225C54.2511 5.03083 54.3394 5.47417 54.3394 5.9525C54.3394 6.6875 54.1805 7.32333 53.8627 7.86C53.5566 8.39667 53.0504 8.805 52.344 9.085V9.12C52.6854 9.21333 52.968 9.35917 53.1916 9.5575C53.4153 9.74417 53.5978 9.97167 53.739 10.24C53.8803 10.4967 53.9804 10.7825 54.0392 11.0975C54.1099 11.4125 54.157 11.7275 54.1805 12.0425C54.1923 12.2408 54.204 12.4742 54.2158 12.7425C54.2276 13.0108 54.2452 13.285 54.2688 13.565C54.3041 13.845 54.3512 14.1133 54.4101 14.37C54.4807 14.615 54.5808 14.825 54.7102 15H51.9379C51.7849 14.6033 51.6907 14.1308 51.6554 13.5825C51.6201 13.0342 51.5671 12.5092 51.4964 12.0075C51.4023 11.3542 51.2021 10.8758 50.8961 10.5725C50.59 10.2692 50.0897 10.1175 49.3951 10.1175H46.6228V15H43.8504V2.505Z" fill="white"/>
|
||||
<path d="M57.6712 10.485C57.6712 10.8467 57.7065 11.2025 57.7771 11.5525C57.8478 11.8908 57.9655 12.2 58.1303 12.48C58.3069 12.7483 58.5364 12.9642 58.819 13.1275C59.1015 13.2908 59.4547 13.3725 59.8785 13.3725C60.3023 13.3725 60.6554 13.2908 60.9379 13.1275C61.2322 12.9642 61.4618 12.7483 61.6266 12.48C61.8032 12.2 61.9268 11.8908 61.9974 11.5525C62.0681 11.2025 62.1034 10.8467 62.1034 10.485C62.1034 10.1233 62.0681 9.7675 61.9974 9.4175C61.9268 9.0675 61.8032 8.75833 61.6266 8.49C61.4618 8.22167 61.2322 8.00583 60.9379 7.8425C60.6554 7.6675 60.3023 7.58 59.8785 7.58C59.4547 7.58 59.1015 7.6675 58.819 7.8425C58.5364 8.00583 58.3069 8.22167 58.1303 8.49C57.9655 8.75833 57.8478 9.0675 57.7771 9.4175C57.7065 9.7675 57.6712 10.1233 57.6712 10.485ZM55.1637 10.485C55.1637 9.76167 55.2755 9.10833 55.4992 8.525C55.7229 7.93 56.0407 7.42833 56.4528 7.02C56.8648 6.6 57.3592 6.27917 57.936 6.0575C58.5129 5.82417 59.1604 5.7075 59.8785 5.7075C60.5966 5.7075 61.244 5.82417 61.8209 6.0575C62.4095 6.27917 62.9098 6.6 63.3218 7.02C63.7338 7.42833 64.0517 7.93 64.2754 8.525C64.499 9.10833 64.6109 9.76167 64.6109 10.485C64.6109 11.2083 64.499 11.8617 64.2754 12.445C64.0517 13.0283 63.7338 13.53 63.3218 13.95C62.9098 14.3583 62.4095 14.6733 61.8209 14.895C61.244 15.1167 60.5966 15.2275 59.8785 15.2275C59.1604 15.2275 58.5129 15.1167 57.936 14.895C57.3592 14.6733 56.8648 14.3583 56.4528 13.95C56.0407 13.53 55.7229 13.0283 55.4992 12.445C55.2755 11.8617 55.1637 11.2083 55.1637 10.485Z" fill="white"/>
|
||||
<path d="M67.5832 10.485C67.5832 10.8467 67.6185 11.2025 67.6892 11.5525C67.7598 11.8908 67.8775 12.2 68.0424 12.48C68.2189 12.7483 68.4485 12.9642 68.731 13.1275C69.0135 13.2908 69.3667 13.3725 69.7905 13.3725C70.2143 13.3725 70.5675 13.2908 70.85 13.1275C71.1443 12.9642 71.3739 12.7483 71.5387 12.48C71.7153 12.2 71.8389 11.8908 71.9095 11.5525C71.9801 11.2025 72.0155 10.8467 72.0155 10.485C72.0155 10.1233 71.9801 9.7675 71.9095 9.4175C71.8389 9.0675 71.7153 8.75833 71.5387 8.49C71.3739 8.22167 71.1443 8.00583 70.85 7.8425C70.5675 7.6675 70.2143 7.58 69.7905 7.58C69.3667 7.58 69.0135 7.6675 68.731 7.8425C68.4485 8.00583 68.2189 8.22167 68.0424 8.49C67.8775 8.75833 67.7598 9.0675 67.6892 9.4175C67.6185 9.7675 67.5832 10.1233 67.5832 10.485ZM65.0758 10.485C65.0758 9.76167 65.1876 9.10833 65.4113 8.525C65.6349 7.93 65.9528 7.42833 66.3648 7.02C66.7768 6.6 67.2713 6.27917 67.8481 6.0575C68.4249 5.82417 69.0724 5.7075 69.7905 5.7075C70.5086 5.7075 71.1561 5.82417 71.7329 6.0575C72.3215 6.27917 72.8218 6.6 73.2339 7.02C73.6459 7.42833 73.9637 7.93 74.1874 8.525C74.4111 9.10833 74.5229 9.76167 74.5229 10.485C74.5229 11.2083 74.4111 11.8617 74.1874 12.445C73.9637 13.0283 73.6459 13.53 73.2339 13.95C72.8218 14.3583 72.3215 14.6733 71.7329 14.895C71.1561 15.1167 70.5086 15.2275 69.7905 15.2275C69.0724 15.2275 68.4249 15.1167 67.8481 14.895C67.2713 14.6733 66.7768 14.3583 66.3648 13.95C65.9528 13.53 65.6349 13.0283 65.4113 12.445C65.1876 11.8617 65.0758 11.2083 65.0758 10.485Z" fill="white"/>
|
||||
<path d="M87.9723 6.705C87.9252 6.39 87.8192 6.10417 87.6544 5.8475C87.4896 5.57917 87.2836 5.34583 87.0364 5.1475C86.7892 4.94917 86.5067 4.7975 86.1888 4.6925C85.8827 4.57583 85.559 4.5175 85.2176 4.5175C84.5937 4.5175 84.0639 4.64 83.6284 4.885C83.1928 5.11833 82.8396 5.43917 82.5689 5.8475C82.2981 6.24417 82.098 6.69917 81.9685 7.2125C81.8508 7.72583 81.7919 8.25667 81.7919 8.805C81.7919 9.33 81.8508 9.84333 81.9685 10.345C82.098 10.835 82.2981 11.2783 82.5689 11.675C82.8396 12.0717 83.1928 12.3925 83.6284 12.6375C84.0639 12.8708 84.5937 12.9875 85.2176 12.9875C86.0652 12.9875 86.7244 12.7308 87.1953 12.2175C87.678 11.7042 87.9723 11.0275 88.0782 10.1875H90.7623C90.6916 10.9692 90.5092 11.675 90.2149 12.305C89.9206 12.935 89.5321 13.4717 89.0494 13.915C88.5668 14.3583 88.0017 14.6967 87.3542 14.93C86.7068 15.1633 85.9946 15.28 85.2176 15.28C84.2523 15.28 83.3811 15.1167 82.6042 14.79C81.839 14.4517 81.1915 13.9908 80.6618 13.4075C80.132 12.8242 79.7259 12.1417 79.4434 11.36C79.1608 10.5667 79.0196 9.715 79.0196 8.805C79.0196 7.87167 79.1608 7.00833 79.4434 6.215C79.7259 5.41 80.132 4.71 80.6618 4.115C81.1915 3.52 81.839 3.05333 82.6042 2.715C83.3811 2.37667 84.2523 2.2075 85.2176 2.2075C85.9122 2.2075 86.5655 2.30667 87.1777 2.505C87.8016 2.70333 88.3549 2.995 88.8375 3.38C89.332 3.75333 89.7381 4.22 90.056 4.78C90.3738 5.34 90.5739 5.98167 90.6563 6.705H87.9723Z" fill="white"/>
|
||||
<path d="M93.7326 10.485C93.7326 10.8467 93.7679 11.2025 93.8385 11.5525C93.9092 11.8908 94.0269 12.2 94.1917 12.48C94.3683 12.7483 94.5978 12.9642 94.8804 13.1275C95.1629 13.2908 95.5161 13.3725 95.9399 13.3725C96.3637 13.3725 96.7168 13.2908 96.9994 13.1275C97.2937 12.9642 97.5232 12.7483 97.688 12.48C97.8646 12.2 97.9882 11.8908 98.0589 11.5525C98.1295 11.2025 98.1648 10.8467 98.1648 10.485C98.1648 10.1233 98.1295 9.7675 98.0589 9.4175C97.9882 9.0675 97.8646 8.75833 97.688 8.49C97.5232 8.22167 97.2937 8.00583 96.9994 7.8425C96.7168 7.6675 96.3637 7.58 95.9399 7.58C95.5161 7.58 95.1629 7.6675 94.8804 7.8425C94.5978 8.00583 94.3683 8.22167 94.1917 8.49C94.0269 8.75833 93.9092 9.0675 93.8385 9.4175C93.7679 9.7675 93.7326 10.1233 93.7326 10.485ZM91.2251 10.485C91.2251 9.76167 91.337 9.10833 91.5606 8.525C91.7843 7.93 92.1021 7.42833 92.5142 7.02C92.9262 6.6 93.4206 6.27917 93.9975 6.0575C94.5743 5.82417 95.2218 5.7075 95.9399 5.7075C96.658 5.7075 97.3054 5.82417 97.8823 6.0575C98.4709 6.27917 98.9712 6.6 99.3832 7.02C99.7953 7.42833 100.113 7.93 100.337 8.525C100.56 9.10833 100.672 9.76167 100.672 10.485C100.672 11.2083 100.56 11.8617 100.337 12.445C100.113 13.0283 99.7953 13.53 99.3832 13.95C98.9712 14.3583 98.4709 14.6733 97.8823 14.895C97.3054 15.1167 96.658 15.2275 95.9399 15.2275C95.2218 15.2275 94.5743 15.1167 93.9975 14.895C93.4206 14.6733 92.9262 14.3583 92.5142 13.95C92.1021 13.53 91.7843 13.0283 91.5606 12.445C91.337 11.8617 91.2251 11.2083 91.2251 10.485Z" fill="white"/>
|
||||
<path d="M107.9 10.45C107.9 10.0767 107.865 9.72083 107.794 9.3825C107.724 9.0325 107.6 8.72917 107.424 8.4725C107.259 8.20417 107.041 7.98833 106.77 7.825C106.499 7.66167 106.158 7.58 105.746 7.58C105.334 7.58 104.987 7.66167 104.704 7.825C104.422 7.98833 104.192 8.20417 104.015 8.4725C103.851 8.74083 103.727 9.05 103.645 9.4C103.574 9.73833 103.539 10.0942 103.539 10.4675C103.539 10.8175 103.58 11.1675 103.662 11.5175C103.745 11.8675 103.874 12.1825 104.051 12.4625C104.239 12.7308 104.469 12.9525 104.739 13.1275C105.022 13.2908 105.357 13.3725 105.746 13.3725C106.158 13.3725 106.499 13.2908 106.77 13.1275C107.053 12.9642 107.276 12.7483 107.441 12.48C107.606 12.2 107.724 11.885 107.794 11.535C107.865 11.185 107.9 10.8233 107.9 10.45ZM107.936 13.845H107.9C107.606 14.335 107.218 14.6908 106.735 14.9125C106.264 15.1225 105.728 15.2275 105.128 15.2275C104.445 15.2275 103.845 15.0992 103.327 14.8425C102.809 14.5742 102.379 14.2183 102.038 13.775C101.708 13.32 101.455 12.8008 101.278 12.2175C101.114 11.6342 101.031 11.0275 101.031 10.3975C101.031 9.79083 101.114 9.2075 101.278 8.6475C101.455 8.07583 101.708 7.57417 102.038 7.1425C102.379 6.71083 102.803 6.36667 103.309 6.11C103.815 5.84167 104.404 5.7075 105.075 5.7075C105.616 5.7075 106.129 5.82417 106.611 6.0575C107.106 6.27917 107.494 6.61167 107.777 7.055H107.812V2.505H110.319V15H107.936V13.845Z" fill="white"/>
|
||||
<path d="M117.477 9.505C117.359 8.875 117.147 8.39667 116.841 8.07C116.547 7.74333 116.094 7.58 115.481 7.58C115.081 7.58 114.746 7.65 114.475 7.79C114.216 7.91833 114.004 8.08167 113.839 8.28C113.686 8.47833 113.574 8.68833 113.504 8.91C113.445 9.13167 113.41 9.33 113.398 9.505H117.477ZM113.398 11.08C113.433 11.885 113.639 12.4683 114.016 12.83C114.393 13.1917 114.934 13.3725 115.64 13.3725C116.147 13.3725 116.582 13.25 116.947 13.005C117.312 12.7483 117.536 12.48 117.618 12.2H119.825C119.472 13.285 118.931 14.0608 118.201 14.5275C117.471 14.9942 116.588 15.2275 115.552 15.2275C114.834 15.2275 114.187 15.1167 113.61 14.895C113.033 14.6617 112.544 14.335 112.144 13.915C111.744 13.495 111.432 12.9933 111.208 12.41C110.996 11.8267 110.89 11.185 110.89 10.485C110.89 9.80833 111.002 9.17833 111.226 8.595C111.449 8.01167 111.767 7.51 112.179 7.09C112.591 6.65833 113.08 6.32 113.645 6.075C114.222 5.83 114.858 5.7075 115.552 5.7075C116.329 5.7075 117.006 5.85917 117.583 6.1625C118.16 6.45417 118.631 6.85083 118.995 7.3525C119.372 7.85417 119.643 8.42583 119.808 9.0675C119.973 9.70917 120.031 10.38 119.984 11.08H113.398Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 470 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 600 B |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 586 KiB |
|
Before Width: | Height: | Size: 442 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Anthropic</title><path d="M13.827 3.52h3.603L24 20h-3.603l-6.57-16.48zm-7.258 0h3.767L16.906 20h-3.674l-1.343-3.461H5.017l-1.344 3.46H0L6.57 3.522zm4.132 9.959L8.453 7.687 6.205 13.48H10.7z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 368 B |
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="256px" height="315px" viewBox="0 0 256 315" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M213.803394,167.030943 C214.2452,214.609646 255.542482,230.442639 256,230.644727 C255.650812,231.761357 249.401383,253.208293 234.24263,275.361446 C221.138555,294.513969 207.538253,313.596333 186.113759,313.991545 C165.062051,314.379442 158.292752,301.507828 134.22469,301.507828 C110.163898,301.507828 102.642899,313.596301 82.7151126,314.379442 C62.0350407,315.16201 46.2873831,293.668525 33.0744079,274.586162 C6.07529317,235.552544 -14.5576169,164.286328 13.147166,116.18047 C26.9103111,92.2909053 51.5060917,77.1630356 78.2026125,76.7751096 C98.5099145,76.3877456 117.677594,90.4371851 130.091705,90.4371851 C142.497945,90.4371851 165.790755,73.5415029 190.277627,76.0228474 C200.528668,76.4495055 229.303509,80.1636878 247.780625,107.209389 C246.291825,108.132333 213.44635,127.253405 213.803394,167.030988 M174.239142,50.1987033 C185.218331,36.9088319 192.607958,18.4081019 190.591988,0 C174.766312,0.636050225 155.629514,10.5457909 144.278109,23.8283506 C134.10507,35.5906758 125.195775,54.4170275 127.599657,72.4607932 C145.239231,73.8255433 163.259413,63.4970262 174.239142,50.1987249" fill="currentColor"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Bedrock</title><path d="M13.05 15.513h3.08c.214 0 .389.177.389.394v1.82a1.704 1.704 0 011.296 1.661c0 .943-.755 1.708-1.685 1.708-.931 0-1.686-.765-1.686-1.708 0-.807.554-1.484 1.297-1.662v-1.425h-2.69v4.663a.395.395 0 01-.188.338l-2.69 1.641a.385.385 0 01-.405-.002l-4.926-3.086a.395.395 0 01-.185-.336V16.3L2.196 14.87A.395.395 0 012 14.555L2 14.528V9.406c0-.14.073-.27.192-.34l2.465-1.462V4.448c0-.129.062-.249.165-.322l.021-.014L9.77 1.058a.385.385 0 01.407 0l2.69 1.675a.395.395 0 01.185.336V7.6h3.856V5.683a1.704 1.704 0 01-1.296-1.662c0-.943.755-1.708 1.685-1.708.931 0 1.685.765 1.685 1.708 0 .807-.553 1.484-1.296 1.662v2.311a.391.391 0 01-.389.394h-4.245v1.806h6.624a1.69 1.69 0 011.64-1.313c.93 0 1.685.764 1.685 1.707 0 .943-.754 1.708-1.685 1.708a1.69 1.69 0 01-1.64-1.314H13.05v1.937h4.953l.915 1.18a1.66 1.66 0 01.84-.227c.931 0 1.685.764 1.685 1.707 0 .943-.754 1.708-1.685 1.708-.93 0-1.685-.765-1.685-1.708 0-.346.102-.668.276-.937l-.724-.935H13.05v1.806zM9.973 1.856L7.93 3.122V6.09h-.778V3.604L5.435 4.669v2.945l2.11 1.36L9.712 7.61V5.334h.778V7.83c0 .136-.07.263-.184.335L7.963 9.638v2.081l1.422 1.009-.446.646-1.406-.998-1.53 1.005-.423-.66 1.605-1.055v-1.99L5.038 8.29l-2.26 1.34v1.676l1.972-1.189.398.677-2.37 1.429V14.3l2.166 1.258 2.27-1.368.397.677-2.176 1.311V19.3l1.876 1.175 2.365-1.426.398.678-2.017 1.216 1.918 1.201 2.298-1.403v-5.78l-4.758 2.893-.4-.675 5.158-3.136V3.289L9.972 1.856zM16.13 18.47a.913.913 0 00-.908.92c0 .507.406.918.908.918a.913.913 0 00.907-.919.913.913 0 00-.907-.92zm3.63-3.81a.913.913 0 00-.908.92c0 .508.406.92.907.92a.913.913 0 00.908-.92.913.913 0 00-.908-.92zm1.555-4.99a.913.913 0 00-.908.92c0 .507.407.918.908.918a.913.913 0 00.907-.919.913.913 0 00-.907-.92zM17.296 3.1a.913.913 0 00-.907.92c0 .508.406.92.907.92a.913.913 0 00.908-.92.913.913 0 00-.908-.92z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 116 24" xmlns="http://www.w3.org/2000/svg"><title>ByteDance</title><path d="M31.574 4.626V7.43h.893c.674 0 .84.015.88.49l.012.53-.013.53c-.04.474-.205.49-.88.49h-.892l.003 5c.018 2.842.164 2.902 1.298 2.902.357 0 .46.137.48.837l.004 1.534-1.428-.179c-.79-.076-1.631-.28-1.912-.408-.693-.382-.96-1.705-.991-5.188l-.003-4.499h-2.958l-3.187 7.266L19.72 24h-2.423l.484-1.198c.28-.688.74-1.785 1.02-2.447l.536-1.25-4.768-11.344c-.102-.255.255-.331 1.25-.331h1.376l2.633 6.613c.738 1.81.936 2.113 1.094 1.82l1.857-4.584 1.53-3.722 4.716-.153V4.626h2.55zm68.557 3.773c.306.229.23.407-.383 1.121l-.765.867-1.121-.612c-2.04-1.07-3.978-.408-4.895 1.657-.587 1.3-.51 2.83.178 4.181.918 1.733 3.34 2.294 5.048 1.147l.892-.612.663.689c.357.382.663.79.663.943 0 .637-3.493 2.065-4.564 1.86l-1.045-.203c-1.886-.383-3.467-1.683-4.181-3.39-.255-.561-.408-1.709-.408-2.83 0-1.657.102-2.014.841-3.238 1.81-3.033 5.94-3.747 9.077-1.58zM42.92 7.455c2.09.561 3.951 3.263 3.951 5.685v.918l-7.175.008c-2.97.039-2.837.26-2.08 1.521 1.25 2.116 4.539 2.346 6.63.46.586-.536 1.172-.409 1.86.433.281.331.23.51-.382 1.147-1.3 1.351-4.181 2.269-5.864 1.86-2.269-.535-3.62-1.503-4.538-3.237-.765-1.453-.74-4.435.026-5.94 1.35-2.6 4.36-3.747 7.572-2.855zm64.604-.28c3.595 0 5.966 2.065 6.323 5.506l.153 1.377h-9.765v.663c0 .433.306.968.893 1.53 1.53 1.452 3.722 1.478 5.685.101l1.096-.765.765.51c.408.306.74.638.74.74 0 .102-.306.484-.689.866-1.402 1.326-4.232 2.116-6.195 1.734-2.932-.586-4.844-3.008-4.844-6.17 0-3.466 2.524-6.067 5.838-6.092zm-34.01.918l.55.367c.508.32.584.263.595-.18l.002-.213c0-.49.078-.61.713-.633L76.7 7.43v11.726h-1.148c-.847 0-1.09-.058-1.137-.363l-.01-.146c0-.638-.127-.638-1.198.025-1.377.867-3.697.918-5.329.153-2.422-1.173-3.62-3.39-3.34-6.297.179-1.963 1.097-3.594 2.55-4.435 1.989-1.173 4.691-1.173 6.425 0zM2 19.182V2l4.892.212c2.05.11 2.655.253 3.496.706 2.498 1.274 3.136 4.563 1.275 6.526-.357.382-.485.663-.306.714 1.3.433 2.6 2.523 2.626 4.155 0 1.351-.97 3.059-2.244 3.951l-1.122.765L2 19.182zM87.995 8.985c.69.928.914 2.167.94 5.644l.003 4.527h-2.294v-3.365l-.02-1.404c-.11-4.106-.676-5.045-2.683-5.045-.994 0-1.274.127-1.912.841l-.74.816v8.157h-2.294V7.43h1.147c.743 0 1.056.075 1.13.289l.018.119c0 .23.076.357.204.306 2.855-1.479 4.946-1.198 6.501.84zm-36.33-6.909c8.285 0 11.778 2.805 11.472 9.203-.255 5.456-3.39 7.877-10.172 7.877H49.93V2.076h1.733zm17.005 7.75c-1.683 1.122-2.244 4.053-1.071 5.787 1.147 1.733 3.646 2.243 5.252 1.07 2.294-1.733 2.192-5.404-.23-6.806-1.045-.612-3.033-.637-3.951-.05zM4.55 11.713v5.2l4.09-.15c1.333-.067 1.473-.209 2.054-.87.459-.51.74-1.096.74-1.58s-.281-1.07-.74-1.58l-.283-.312c-.518-.531-.864-.54-3.159-.606l-2.702-.102zm47.675-7.419v12.62l2.244-.103c1.606-.076 2.498-.255 3.263-.663 2.04-1.045 2.907-2.676 2.907-5.404 0-2.141-.434-3.314-1.632-4.461-1.09-1.066-2.052-1.48-4.23-1.737l-2.552-.252zM39.962 9.342c-1.173.204-2.779 1.606-2.779 2.422l.017.171c.077.273.477.327 2.443.336l4.704.002-.153-.56c-.484-1.58-2.422-2.677-4.232-2.371zm66.568.102c-1.07.306-2.295 1.555-2.295 2.345 0 .402.176.471 2.44.482l4.674.002-.255-.764c-.587-1.683-2.703-2.626-4.564-2.065zM4.55 4.294V9.47h1.657c.918 0 2.04-.153 2.498-.331 1.147-.484 1.53-1.045 1.53-2.243 0-.79-.179-1.199-.663-1.708-.47-.45-.775-.604-1.858-.7L4.55 4.294z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
|
@ -1,50 +0,0 @@
|
|||
<svg version="1.1" id="Layer_1" xmlns:x="ns_extend;" xmlns:i="ns_ai;" xmlns:graph="ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 287.1 65" style="enable-background:new 0 0 287.1 65;" xml:space="preserve" fill="currentColor">
|
||||
<g>
|
||||
<path class="st0" d="M179.8,37.7L172.4,19H166l0.4,0.9l10.9,26.5h4.8L193.4,19h-6.2L179.8,37.7 M246.4,35.7l-12.9-16.7h-5.2v27.2
|
||||
h5.8V28.8l13.3,17.2h4.7V18.9h-5.8V35.7z M205.7,18.8l-12,27.4h6l5-11.5l0,0l3.5-8.3l0,0v-0.1l3.2,7.7l-2.2,5h4.3l1.5,3.6l1.4,3.5
|
||||
h6.2l-11.9-27.2H205.7z M275.1,18.8H270l-12,27.4h6l5-11.5l0,0l3.5-8.1l0,0l0.1-0.2l3.2,7.7l-2.2,5.1h4.3l1.5,3.6l1.4,3.5h6.2
|
||||
L275.1,18.8z">
|
||||
</path>
|
||||
<path class="st0" d="M99.1,40.2c-1.1,1.1-2.4,2.1-3.8,2.9c-1.5,0.8-3.2,1.2-5,1.1c-1.5,0-3-0.3-4.4-1c-1.3-0.6-2.5-1.4-3.4-2.4
|
||||
c-1-1.1-1.8-2.4-2.3-3.8c-0.6-1.4-0.8-3-0.8-4.5l0,0c0-1.5,0.3-3.1,0.8-4.5c0.5-1.4,1.3-2.7,2.3-3.8c1-1,2.1-1.9,3.4-2.5
|
||||
c1.4-0.6,2.8-0.9,4.3-0.9c0.9,0,1.9,0.1,2.8,0.3c0.8,0.2,1.6,0.5,2.3,0.8c0.7,0.3,1.3,0.7,1.9,1.2c0.6,0.4,1.1,0.9,1.7,1.4l0.5,0.4
|
||||
l1.8-1.9l-0.5-0.4c-0.7-0.6-1.3-1.2-2-1.7c-0.7-0.5-1.5-1-2.3-1.4c-0.9-0.4-1.8-0.7-2.8-0.9c-1.1-0.2-2.2-0.3-3.4-0.3
|
||||
c-1.9,0-3.7,0.4-5.4,1.1c-1.6,0.7-3,1.8-4.2,3.1c-1.2,1.3-2.1,2.8-2.8,4.5c-0.7,1.7-1,3.5-1,5.4l0,0c0,1.9,0.3,3.7,1,5.4
|
||||
c0.6,1.7,1.5,3.2,2.8,4.5c1.2,1.3,2.6,2.3,4.2,3c1.7,0.7,3.5,1.1,5.3,1.1c1.1,0,2.2-0.1,3.3-0.4c1-0.2,1.9-0.6,2.9-1
|
||||
c0.9-0.4,1.7-0.9,2.4-1.5c0.7-0.6,1.4-1.2,2-1.9l0.5-0.5l-1.9-1.7L99.1,40.2 M119.1,18.8l-12.9,27.3h2.6l11.3-23.8l6.3,13.4
|
||||
l-1.6,3.4h3.2l3.3,7h2.6l-12.8-27.3H119.1 M153.6,34.7c0.8-0.1,1.6-0.3,2.3-0.6c1-0.4,2-0.9,2.8-1.6c0.8-0.7,1.4-1.5,1.9-2.4
|
||||
c0.4-1,0.7-2.1,0.7-3.2l0,0c0-1-0.2-2-0.5-2.9c-0.4-0.9-0.9-1.7-1.5-2.3c-1-0.9-2.1-1.6-3.4-2.1c-1.5-0.5-3-0.7-4.6-0.7h-11.3v27.2
|
||||
h2.5V35h8.2l8.4,11.1h3.2L153.6,34.7 M142.4,32.6V21.4h8.7c2-0.1,4,0.4,5.6,1.5c1.3,1,2,2.5,1.9,4.1l0,0c0,0.8-0.2,1.5-0.5,2.3
|
||||
c-0.3,0.7-0.8,1.3-1.5,1.8c-0.7,0.5-1.5,0.9-2.4,1.2c-1.1,0.3-2.2,0.5-3.4,0.5L142.4,32.6">
|
||||
</path>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M40,36.9c-0.1,0-3.1-0.1-7.4-0.1c-4.4,0-7.4,0.1-7.5,0.1c-1,0-0.4,1.5-0.4,1.5c2.3,0.2,5.7,0.2,7.8,0.2
|
||||
c2,0,5.4,0,7.8-0.2l0,0.1C40.3,38.4,40.9,37,40,36.9z">
|
||||
</path>
|
||||
<path class="st0" d="M21.8,35.2c-0.7-0.5-1.5-0.8-2.3-1.1c-0.6-0.1-1.2,0.2-1.4,0.7c-0.2,0.6-0.3,1.3-0.2,2c0,0,0.1,0.5,0.8,0.7
|
||||
c1.5,0.3,3,0.5,4.5,0.7C23.3,38.2,23.2,35.9,21.8,35.2z">
|
||||
</path>
|
||||
<path class="st0" d="M26.7,18.1c2,0.3,4,0.5,6,0.5c1.8,0,3.6-0.1,5.4-0.4c0.8-0.1,1.6-0.3,2.4-0.6h-0.2c-0.5-0.2-1.1-0.4-1.7-0.5
|
||||
c-2-0.3-4-0.5-6-0.5v0c-1.8,0-3.6,0.1-5.4,0.4c-0.8,0.1-1.7,0.3-2.4,0.7H25C25.5,17.8,26.1,18,26.7,18.1z">
|
||||
</path>
|
||||
<path class="st0" d="M22.7,29.8h19.7c0,0,0.5,0,0.3-0.6c-0.8-1.7-1.7-3.3-2.8-4.9c0,0-2.3-0.1-5.3-0.1l0.1,0.2V25c0,0,0,0,0,0
|
||||
c0,0.2-0.2,0.3-0.4,0.3h-3.5c-0.2,0-0.4-0.2-0.4-0.4v-0.5v-0.2c-3,0-5.3,0.1-5.3,0.1c-1,1.5-1.9,3.2-2.7,4.9
|
||||
C22.2,29.8,22.7,29.8,22.7,29.8z">
|
||||
</path>
|
||||
<path class="st0" d="M32.5,0C14.6,0,0,14.6,0,32.5C0,50.4,14.6,65,32.5,65C50.4,65,65,50.4,65,32.5c0,0,0,0,0,0
|
||||
C65,14.5,50.4,0,32.5,0z M23.7,16.9c0.2-0.2,0.4-0.3,0.7-0.5c0.6-0.3,1.3-0.4,2-0.6c2.1-0.4,4.1-0.5,6.2-0.5c1.9,0,3.8,0.1,5.6,0.4
|
||||
c1.2,0.1,2.3,0.5,3.3,1.2c0.2,0.2,0.4,0.5,0.4,0.8c0,0.3-0.2,0.6-0.4,0.8c-0.2,0.2-0.4,0.3-0.7,0.4c-0.6,0.3-1.3,0.5-2,0.6
|
||||
c-2,0.3-4.1,0.5-6.2,0.5v0c-1.9,0-3.8-0.1-5.6-0.4c-1.2-0.1-2.3-0.5-3.3-1.1c-0.2-0.2-0.3-0.5-0.4-0.8
|
||||
C23.4,17.3,23.5,17.1,23.7,16.9z M47.9,46.2c0,0.3-0.2,0.5-0.4,0.5h-4c0,0,0,0,0,0c-0.3,0-0.4-0.3-0.4-0.5v-0.6H21.9v0.6
|
||||
c0,0,0,0,0,0c0,0.3-0.2,0.5-0.4,0.5h-4c0,0,0,0,0,0c-0.3,0-0.4-0.3-0.4-0.5v-5c0,0-0.1-4-0.1-4.9c0-0.6,0.1-1.1,0.3-1.7
|
||||
c0.3-0.5,0.6-1,1-1.4c0.7-0.9,1.3-1.8,1.9-2.8h-0.2c0,0-3.5-0.2-2.9-1.4c0,0,0.7-1.4,3.2-1.4h0.3c0.1,0,0.4,0.1,0.4,0.9
|
||||
c0.8-1.9,2-3.5,3.6-4.7c0.4-0.2,0.8-0.4,1.2-0.4c0.7-0.2,6.3-0.2,6.7-0.2s6,0.1,6.7,0.2c0.4,0.1,0.8,0.2,1.2,0.4
|
||||
c1.6,1.3,2.8,2.9,3.6,4.7c0.1-0.9,0.2-0.9,0.3-0.9h0.4c2.6,0,3.2,1.4,3.2,1.4c0.6,1.2-2.9,1.4-2.9,1.4h-0.2c0.6,1,1.2,1.9,1.9,2.8
|
||||
c0.4,0.4,0.7,0.9,1,1.4c0.2,0.5,0.3,1.1,0.3,1.7c0,0.9-0.1,4.9-0.1,4.9L47.9,46.2C47.9,46.2,47.9,46.2,47.9,46.2z">
|
||||
</path>
|
||||
<path class="st0" d="M46.9,34.9c-0.2-0.5-0.8-0.8-1.4-0.7c-0.8,0.3-1.6,0.6-2.3,1.1c-1.3,0.7-1.5,3-1.5,3c1.5-0.1,3.1-0.4,4.6-0.7
|
||||
c0.6-0.2,0.8-0.5,0.8-0.6C47.2,36.2,47.1,35.5,46.9,34.9z">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.2 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>DeepSeek</title><path d="M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Gemini</title><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 651 B |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Grok</title><path d="M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815"></path></svg>
|
||||
|
Before Width: | Height: | Size: 756 B |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Kimi</title><path d="M19.738 5.776c.163-.209.306-.4.457-.585.07-.087.064-.153-.004-.244-.655-.861-.717-1.817-.34-2.787.283-.73.909-1.072 1.674-1.145.477-.045.945.004 1.379.236.57.305.902.77 1.01 1.412.086.512.07 1.012-.075 1.508-.257.878-.888 1.333-1.753 1.448-.718.096-1.446.108-2.17.157-.056.004-.113 0-.178 0z"></path><path d="M17.962 1.844h-4.326l-3.425 7.81H5.369V1.878H1.5V22h3.87v-8.477h6.824a3.025 3.025 0 002.743-1.75V22h3.87v-8.477a3.87 3.87 0 00-3.588-3.86v-.01h-2.125a3.94 3.94 0 002.323-2.12l2.545-5.689z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 696 B |
|
Before Width: | Height: | Size: 9.3 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Mistral</title><path clip-rule="evenodd" d="M3.428 3.4h3.429v3.428h3.429v3.429h-.002 3.431V6.828h3.427V3.4h3.43v13.714H24v3.429H13.714v-3.428h-3.428v-3.429h-3.43v3.428h3.43v3.429H0v-3.429h3.428V3.4zm10.286 13.715h3.428v-3.429h-3.427v3.429z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 418 B |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>MoonshotAI</title><path d="M1.052 16.916l9.539 2.552a21.007 21.007 0 00.06 2.033l5.956 1.593a11.997 11.997 0 01-5.586.865l-.18-.016-.044-.004-.084-.009-.094-.01a11.605 11.605 0 01-.157-.02l-.107-.014-.11-.016a11.962 11.962 0 01-.32-.051l-.042-.008-.075-.013-.107-.02-.07-.015-.093-.019-.075-.016-.095-.02-.097-.023-.094-.022-.068-.017-.088-.022-.09-.024-.095-.025-.082-.023-.109-.03-.062-.02-.084-.025-.093-.028-.105-.034-.058-.019-.08-.026-.09-.031-.066-.024a6.293 6.293 0 01-.044-.015l-.068-.025-.101-.037-.057-.022-.08-.03-.087-.035-.088-.035-.079-.032-.095-.04-.063-.028-.063-.027a5.655 5.655 0 01-.041-.018l-.066-.03-.103-.047-.052-.024-.096-.046-.062-.03-.084-.04-.086-.044-.093-.047-.052-.027-.103-.055-.057-.03-.058-.032a6.49 6.49 0 01-.046-.026l-.094-.053-.06-.034-.051-.03-.072-.041-.082-.05-.093-.056-.052-.032-.084-.053-.061-.039-.079-.05-.07-.047-.053-.035a7.785 7.785 0 01-.054-.036l-.044-.03-.044-.03a6.066 6.066 0 01-.04-.028l-.057-.04-.076-.054-.069-.05-.074-.054-.056-.042-.076-.057-.076-.059-.086-.067-.045-.035-.064-.052-.074-.06-.089-.073-.046-.039-.046-.039a7.516 7.516 0 01-.043-.037l-.045-.04-.061-.053-.07-.062-.068-.06-.062-.058-.067-.062-.053-.05-.088-.084a13.28 13.28 0 01-.099-.097l-.029-.028-.041-.042-.069-.07-.05-.051-.05-.053a6.457 6.457 0 01-.168-.179l-.08-.088-.062-.07-.071-.08-.042-.049-.053-.062-.058-.068-.046-.056a7.175 7.175 0 01-.027-.033l-.045-.055-.066-.082-.041-.052-.05-.064-.02-.025a11.99 11.99 0 01-1.44-2.402zm-1.02-5.794l11.353 3.037a20.468 20.468 0 00-.469 2.011l10.817 2.894a12.076 12.076 0 01-1.845 2.005L.657 15.923l-.016-.046-.035-.104a11.965 11.965 0 01-.05-.153l-.007-.023a11.896 11.896 0 01-.207-.741l-.03-.126-.018-.08-.021-.097-.018-.081-.018-.09-.017-.084-.018-.094c-.026-.141-.05-.283-.071-.426l-.017-.118-.011-.083-.013-.102a12.01 12.01 0 01-.019-.161l-.005-.047a12.12 12.12 0 01-.034-2.145zm1.593-5.15l11.948 3.196c-.368.605-.705 1.231-1.01 1.875l11.295 3.022c-.142.82-.368 1.612-.668 2.365l-11.55-3.09L.124 10.26l.015-.1.008-.049.01-.067.015-.087.018-.098c.026-.148.056-.295.088-.442l.028-.124.02-.085.024-.097c.022-.09.045-.18.07-.268l.028-.102.023-.083.03-.1.025-.082.03-.096.026-.082.031-.095a11.896 11.896 0 011.01-2.232zm4.442-4.4L17.352 4.59a20.77 20.77 0 00-1.688 1.721l7.823 2.093c.267.852.442 1.744.513 2.665L2.106 5.213l.045-.065.027-.04.04-.055.046-.065.055-.076.054-.072.064-.086.05-.065.057-.073.055-.07.06-.074.055-.069.065-.077.054-.066.066-.077.053-.06.072-.082.053-.06.067-.074.054-.058.073-.078.058-.06.063-.067.168-.17.1-.098.059-.056.076-.071a12.084 12.084 0 012.272-1.677zM12.017 0h.097l.082.001.069.001.054.002.068.002.046.001.076.003.047.002.06.003.054.002.087.005.105.007.144.011.088.007.044.004.077.008.082.008.047.005.102.012.05.006.108.014.081.01.042.006.065.01.207.032.07.012.065.011.14.026.092.018.11.022.046.01.075.016.041.01L14.7.3l.042.01.065.015.049.012.071.017.096.024.112.03.113.03.113.032.05.015.07.02.078.024.073.023.05.016.05.016.076.025.099.033.102.036.048.017.064.023.093.034.11.041.116.045.1.04.047.02.06.024.041.018.063.026.04.018.057.025.11.048.1.046.074.035.075.036.06.028.092.046.091.045.102.052.053.028.049.026.046.024.06.033.041.022.052.029.088.05.106.06.087.051.057.034.053.032.096.059.088.055.098.062.036.024.064.041.084.056.04.027.062.042.062.043.023.017c.054.037.108.075.161.114l.083.06.065.048.056.043.086.065.082.064.04.03.05.041.086.069.079.065.085.071c.712.6 1.353 1.283 1.909 2.031L7.222.994l.062-.027.065-.028.081-.034.086-.035c.113-.045.227-.09.341-.131l.096-.035.093-.033.084-.03.096-.031c.087-.03.176-.058.264-.085l.091-.027.086-.025.102-.03.085-.023.1-.026L9.04.37l.09-.023.091-.022.095-.022.09-.02.098-.021.091-.02.095-.018.092-.018.1-.018.091-.016.098-.017.092-.014.097-.015.092-.013.102-.013.091-.012.105-.012.09-.01.105-.01c.093-.01.186-.018.28-.024l.106-.008.09-.005.11-.006.093-.004.1-.004.097-.002.099-.002.197-.002z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 3.9 KiB |
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="512px" height="138px" viewBox="0 0 512 138" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M340.657183,0 L340.657183,100.203061 C353.016406,100.778079 365.344207,101.473198 377.637095,102.293306 L377.637095,123.537553 C358.204486,122.242243 338.690182,121.253471 319.094879,120.57923 L319.094879,0 L340.657183,0 Z M512,0.0118710746 L483.922918,65.1060972 L511.993017,137.54371 L511.961595,137.557485 C503.784957,136.3909 495.597845,135.289637 487.386294,134.233936 L471.623048,93.5776798 L455.709676,130.459835 C448.168455,129.627123 440.61676,128.839275 433.047609,128.100899 L460.419447,64.6708546 L435.351871,0.0118710746 L458.677285,0.0118710746 L472.712335,36.1957639 L488.318473,0.0118710746 L512,0.0118710746 Z M245.093161,119.526252 L245.092462,0.0114869428 L305.282574,0.0114869428 L305.282574,21.4467074 L266.654767,21.4467074 L266.654767,49.2277266 L295.881884,49.2277266 L295.881884,70.4719734 L266.654767,70.4719734 L266.654767,119.521329 L245.093161,119.526252 Z M164.580156,21.448488 L164.579458,0.0103695593 L231.270382,0.0103695593 L231.270382,21.4469875 L208.705375,21.4469875 L208.705375,120.107799 C201.508397,120.296154 194.3191,120.519389 187.144466,120.790104 L187.144466,21.448488 L164.580156,21.448488 Z M90.8682168,126.966224 L90.8682168,0.0139657936 L150.758077,0.0139657936 L150.758077,21.4491862 L112.42703,21.4491862 L112.42703,50.4849807 C121.233151,50.3722116 133.754021,50.2444297 141.543822,50.2632828 L141.543822,71.5092753 C131.792954,71.388127 120.786264,71.6429923 112.42703,71.7264345 L112.42703,103.88974 C125.166805,102.887736 137.944984,102.011069 150.758077,101.270912 L150.758077,122.517253 C130.704017,123.672422 110.740031,125.160591 90.8682168,126.966224 Z M48.5710466,77.8540254 L48.5696502,0.0104745953 L70.1319549,0.0104745953 L70.1319549,128.968837 C62.2496338,129.779728 54.3823252,130.642465 46.5286328,131.553346 L21.5609083,59.8244682 L21.5609083,134.625696 C14.3597408,135.563565 7.17323695,136.54141 0,137.562338 L0,0.0118710746 L20.4911722,0.0118710746 L48.5710466,77.8540254 Z M395.425298,124.819071 L395.425298,124.819211 L395.425298,0.0120101224 L416.987603,0.0120101224 L416.987603,126.599777 C409.809478,125.960833 402.624371,125.369895 395.425298,124.819071 Z" fill="currentColor" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Ollama</title><path d="M7.905 1.09c.216.085.411.225.588.41.295.306.544.744.734 1.263.191.522.315 1.1.362 1.68a5.054 5.054 0 012.049-.636l.051-.004c.87-.07 1.73.087 2.48.474.101.053.2.11.297.17.05-.569.172-1.134.36-1.644.19-.52.439-.957.733-1.264a1.67 1.67 0 01.589-.41c.257-.1.53-.118.796-.042.401.114.745.368 1.016.737.248.337.434.769.561 1.287.23.934.27 2.163.115 3.645l.053.04.026.019c.757.576 1.284 1.397 1.563 2.35.435 1.487.216 3.155-.534 4.088l-.018.021.002.003c.417.762.67 1.567.724 2.4l.002.03c.064 1.065-.2 2.137-.814 3.19l-.007.01.01.024c.472 1.157.62 2.322.438 3.486l-.006.039a.651.651 0 01-.747.536.648.648 0 01-.54-.742c.167-1.033.01-2.069-.48-3.123a.643.643 0 01.04-.617l.004-.006c.604-.924.854-1.83.8-2.72-.046-.779-.325-1.544-.8-2.273a.644.644 0 01.18-.886l.009-.006c.243-.159.467-.565.58-1.12a4.229 4.229 0 00-.095-1.974c-.205-.7-.58-1.284-1.105-1.683-.595-.454-1.383-.673-2.38-.61a.653.653 0 01-.632-.371c-.314-.665-.772-1.141-1.343-1.436a3.288 3.288 0 00-1.772-.332c-1.245.099-2.343.801-2.67 1.686a.652.652 0 01-.61.425c-1.067.002-1.893.252-2.497.703-.522.39-.878.935-1.066 1.588a4.07 4.07 0 00-.068 1.886c.112.558.331 1.02.582 1.269l.008.007c.212.207.257.53.109.785-.36.622-.629 1.549-.673 2.44-.05 1.018.186 1.902.719 2.536l.016.019a.643.643 0 01.095.69c-.576 1.236-.753 2.252-.562 3.052a.652.652 0 01-1.269.298c-.243-1.018-.078-2.184.473-3.498l.014-.035-.008-.012a4.339 4.339 0 01-.598-1.309l-.005-.019a5.764 5.764 0 01-.177-1.785c.044-.91.278-1.842.622-2.59l.012-.026-.002-.002c-.293-.418-.51-.953-.63-1.545l-.005-.024a5.352 5.352 0 01.093-2.49c.262-.915.777-1.701 1.536-2.269.06-.045.123-.09.186-.132-.159-1.493-.119-2.73.112-3.67.127-.518.314-.95.562-1.287.27-.368.614-.622 1.015-.737.266-.076.54-.059.797.042zm4.116 9.09c.936 0 1.8.313 2.446.855.63.527 1.005 1.235 1.005 1.94 0 .888-.406 1.58-1.133 2.022-.62.375-1.451.557-2.403.557-1.009 0-1.871-.259-2.493-.734-.617-.47-.963-1.13-.963-1.845 0-.707.398-1.417 1.056-1.946.668-.537 1.55-.849 2.485-.849zm0 .896a3.07 3.07 0 00-1.916.65c-.461.37-.722.835-.722 1.25 0 .428.21.829.61 1.134.455.347 1.124.548 1.943.548.799 0 1.473-.147 1.932-.426.463-.28.7-.686.7-1.257 0-.423-.246-.89-.683-1.256-.484-.405-1.14-.643-1.864-.643zm.662 1.21l.004.004c.12.151.095.37-.056.49l-.292.23v.446a.375.375 0 01-.376.373.375.375 0 01-.376-.373v-.46l-.271-.218a.347.347 0 01-.052-.49.353.353 0 01.494-.051l.215.172.22-.174a.353.353 0 01.49.051zm-5.04-1.919c.478 0 .867.39.867.871a.87.87 0 01-.868.871.87.87 0 01-.867-.87.87.87 0 01.867-.872zm8.706 0c.48 0 .868.39.868.871a.87.87 0 01-.868.871.87.87 0 01-.867-.87.87.87 0 01.867-.872zM7.44 2.3l-.003.002a.659.659 0 00-.285.238l-.005.006c-.138.189-.258.467-.348.832-.17.692-.216 1.631-.124 2.782.43-.128.899-.208 1.404-.237l.01-.001.019-.034c.046-.082.095-.161.148-.239.123-.771.022-1.692-.253-2.444-.134-.364-.297-.65-.453-.813a.628.628 0 00-.107-.09L7.44 2.3zm9.174.04l-.002.001a.628.628 0 00-.107.09c-.156.163-.32.45-.453.814-.29.794-.387 1.776-.23 2.572l.058.097.008.014h.03a5.184 5.184 0 011.466.212c.086-1.124.038-2.043-.128-2.722-.09-.365-.21-.643-.349-.832l-.004-.006a.659.659 0 00-.285-.239h-.004z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 3.2 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenAI</title><path d="M21.55 10.004a5.416 5.416 0 00-.478-4.501c-1.217-2.09-3.662-3.166-6.05-2.66A5.59 5.59 0 0010.831 1C8.39.995 6.224 2.546 5.473 4.838A5.553 5.553 0 001.76 7.496a5.487 5.487 0 00.691 6.5 5.416 5.416 0 00.477 4.502c1.217 2.09 3.662 3.165 6.05 2.66A5.586 5.586 0 0013.168 23c2.443.006 4.61-1.546 5.361-3.84a5.553 5.553 0 003.715-2.66 5.488 5.488 0 00-.693-6.497v.001zm-8.381 11.558a4.199 4.199 0 01-2.675-.954c.034-.018.093-.05.132-.074l4.44-2.53a.71.71 0 00.364-.623v-6.176l1.877 1.069c.02.01.033.029.036.05v5.115c-.003 2.274-1.87 4.118-4.174 4.123zM4.192 17.78a4.059 4.059 0 01-.498-2.763c.032.02.09.055.131.078l4.44 2.53c.225.13.504.13.73 0l5.42-3.088v2.138a.068.068 0 01-.027.057L9.9 19.288c-1.999 1.136-4.552.46-5.707-1.51h-.001zM3.023 8.216A4.15 4.15 0 015.198 6.41l-.002.151v5.06a.711.711 0 00.364.624l5.42 3.087-1.876 1.07a.067.067 0 01-.063.005l-4.489-2.559c-1.995-1.14-2.679-3.658-1.53-5.63h.001zm15.417 3.54l-5.42-3.088L14.896 7.6a.067.067 0 01.063-.006l4.489 2.557c1.998 1.14 2.683 3.662 1.529 5.633a4.163 4.163 0 01-2.174 1.807V12.38a.71.71 0 00-.363-.623zm1.867-2.773a6.04 6.04 0 00-.132-.078l-4.44-2.53a.731.731 0 00-.729 0l-5.42 3.088V7.325a.068.068 0 01.027-.057L14.1 4.713c2-1.137 4.555-.46 5.707 1.513.487.833.664 1.809.499 2.757h.001zm-11.741 3.81l-1.877-1.068a.065.065 0 01-.036-.051V6.559c.001-2.277 1.873-4.122 4.181-4.12.976 0 1.92.338 2.671.954-.034.018-.092.05-.131.073l-4.44 2.53a.71.71 0 00-.365.623l-.003 6.173v.002zm1.02-2.168L12 9.25l2.414 1.375v2.75L12 14.75l-2.415-1.375v-2.75z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenRouter</title><path d="M16.804 1.957l7.22 4.105v.087L16.73 10.21l.017-2.117-.821-.03c-1.059-.028-1.611.002-2.268.11-1.064.175-2.038.577-3.147 1.352L8.345 11.03c-.284.195-.495.336-.68.455l-.515.322-.397.234.385.23.53.338c.476.314 1.17.796 2.701 1.866 1.11.775 2.083 1.177 3.147 1.352l.3.045c.694.091 1.375.094 2.825.033l.022-2.159 7.22 4.105v.087L16.589 22l.014-1.862-.635.022c-1.386.042-2.137.002-3.138-.162-1.694-.28-3.26-.926-4.881-2.059l-2.158-1.5a21.997 21.997 0 00-.755-.498l-.467-.28a55.927 55.927 0 00-.76-.43C2.908 14.73.563 14.116 0 14.116V9.888l.14.004c.564-.007 2.91-.622 3.809-1.124l1.016-.58.438-.274c.428-.28 1.072-.726 2.686-1.853 1.621-1.133 3.186-1.78 4.881-2.059 1.152-.19 1.974-.213 3.814-.138l.02-1.907z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 906 B |
|
|
@ -1 +0,0 @@
|
|||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Qwen</title><path d="M12.604 1.34c.393.69.784 1.382 1.174 2.075a.18.18 0 00.157.091h5.552c.174 0 .322.11.446.327l1.454 2.57c.19.337.24.478.024.837-.26.43-.513.864-.76 1.3l-.367.658c-.106.196-.223.28-.04.512l2.652 4.637c.172.301.111.494-.043.77-.437.785-.882 1.564-1.335 2.34-.159.272-.352.375-.68.37-.777-.016-1.552-.01-2.327.016a.099.099 0 00-.081.05 575.097 575.097 0 01-2.705 4.74c-.169.293-.38.363-.725.364-.997.003-2.002.004-3.017.002a.537.537 0 01-.465-.271l-1.335-2.323a.09.09 0 00-.083-.049H4.982c-.285.03-.553-.001-.805-.092l-1.603-2.77a.543.543 0 01-.002-.54l1.207-2.12a.198.198 0 000-.197 550.951 550.951 0 01-1.875-3.272l-.79-1.395c-.16-.31-.173-.496.095-.965.465-.813.927-1.625 1.387-2.436.132-.234.304-.334.584-.335a338.3 338.3 0 012.589-.001.124.124 0 00.107-.063l2.806-4.895a.488.488 0 01.422-.246c.524-.001 1.053 0 1.583-.006L11.704 1c.341-.003.724.032.9.34zm-3.432.403a.06.06 0 00-.052.03L6.254 6.788a.157.157 0 01-.135.078H3.253c-.056 0-.07.025-.041.074l5.81 10.156c.025.042.013.062-.034.063l-2.795.015a.218.218 0 00-.2.116l-1.32 2.31c-.044.078-.021.118.068.118l5.716.008c.046 0 .08.02.104.061l1.403 2.454c.046.081.092.082.139 0l5.006-8.76.783-1.382a.055.055 0 01.096 0l1.424 2.53a.122.122 0 00.107.062l2.763-.02a.04.04 0 00.035-.02.041.041 0 000-.04l-2.9-5.086a.108.108 0 010-.113l.293-.507 1.12-1.977c.024-.041.012-.062-.035-.062H9.2c-.059 0-.073-.026-.043-.077l1.434-2.505a.107.107 0 000-.114L9.225 1.774a.06.06 0 00-.053-.031zm6.29 8.02c.046 0 .058.02.034.06l-.832 1.465-2.613 4.585a.056.056 0 01-.05.029.058.058 0 01-.05-.029L8.498 9.841c-.02-.034-.01-.052.028-.054l.216-.012 6.722-.012z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
|
@ -1,35 +0,0 @@
|
|||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1333.3333 398.01334" height="398.01334" width="1333.3333" xml:space="preserve" id="svg2" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<metadata id="metadata8">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>
|
||||
image/svg+xml
|
||||
</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage">
|
||||
</dc:type>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs6">
|
||||
</defs>
|
||||
<g transform="matrix(1.3333333,0,0,-1.3333333,0,398.01333)" id="g10">
|
||||
<g transform="scale(0.1)" id="g12">
|
||||
<path id="path14" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 8050.11,483.41 H 2000.01 L 2481.94,-0.0117188 Z">
|
||||
</path>
|
||||
<path id="path16" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 2209.42,1148.07 c -209,0 -362.03,206.45 -362.03,467.22 0,260.58 153.03,467.05 362.03,467.05 209.25,0 356.74,-206.47 356.74,-467.05 0,-260.77 -147.49,-467.22 -356.74,-467.22 z m 351.04,1290.63 v -73.07 c -112.33,71.76 -213.09,113.52 -351.04,113.52 -423.86,0 -745.85,-387.7 -745.85,-863.86 0,-476.29 321.99,-863.759 745.85,-863.759 137.95,0 238.71,41.571 351.04,113.469 v -73.02 h 372.56 V 2438.7 h -372.56">
|
||||
</path>
|
||||
<path id="path18" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 5545.12,2438.7 v -967.35 c 0,-181.45 -124.27,-334.7 -305.3,-334.7 -180.86,0 -305.24,153.25 -305.24,334.7 v 967.35 h -372.59 v -967.35 c 0,-396.92 270.69,-719.819 666.45,-719.819 183.26,0 316.68,101.668 316.68,101.668 V 791.98 h 372.59 V 2438.7 h -372.59">
|
||||
</path>
|
||||
<path id="path20" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 9016.88,791.98 v 967.36 c 0,181.45 124.26,334.7 305.29,334.7 180.86,0 305.24,-153.25 305.24,-334.7 V 791.98 H 10000 v 967.36 c 0,396.91 -270.69,719.82 -666.45,719.82 -183.27,0 -316.67,-101.68 -316.67,-101.68 v 61.22 h -372.6 V 791.98 h 372.6">
|
||||
</path>
|
||||
<path id="path22" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 389.684,2458.49 h 254.293 c 174.976,0 318.086,-142.78 318.086,-318.65 0,-176.33 -143.11,-319.01 -318.086,-319.01 H 389.684 Z m 0,-1666.51 v 637.98 H 665.305 L 1142.46,791.98 h 487.8 l -576.58,769.82 c 179.68,129.37 297.7,339.74 297.7,578.04 0,391.36 -317.25,709.22 -707.403,709.22 L 0,2849.06 V 791.98 h 389.684">
|
||||
</path>
|
||||
<path id="path24" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 6921.92,1181.63 c -33.46,-22.77 -75.7,-40.5 -124.59,-40.5 -60.87,0 -175.64,46.65 -175.64,202.04 v 704.69 h 318.64 v 390.86 h -318.64 l -0.03,410.36 h -372.59 l 0.02,-410.36 h -197.11 v -390.86 h 197.11 v -710.4 c -0.1,-367.71 276.09,-587.351 553.94,-587.351 103.53,0 247.22,34.012 364.47,103.653 l -245.58,327.868">
|
||||
</path>
|
||||
<path id="path26" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 3859.35,1666.81 639.11,771.89 h -522.3 l -447,-573.66 V 2985.07 H 3145.48 V 791.98 h 383.68 v 676.44 l 549.53,-676.44 h 522.03 l -741.37,874.83">
|
||||
</path>
|
||||
<path id="path28" style="fill:#232121;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 8107.81,1827.89 h -671.06 c 78.42,385.69 598.46,407.82 671.06,0 z m -325.26,652.6 c -431.23,0 -740.57,-380.12 -740.57,-865.15 0,-509.99 388.27,-865.281 777.59,-865.281 196.51,0 448.32,67.589 659.85,368.621 l -329.08,190.64 C 7895.82,932.98 7471.65,1123.99 7422.68,1500.3 l 1073.26,-0.24 c 91.82,591.45 -289.44,980.43 -713.39,980.43">
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
|
|
@ -1,4 +0,0 @@
|
|||
<svg width="612" height="144" viewBox="0 0 612 144" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M38.4082 51.0957C38.2324 51.5337 38.074 51.9778 37.9326 52.4268C37.8382 52.7264 37.7517 53.0283 37.6729 53.332C37.6335 53.4836 37.596 53.6356 37.5605 53.7881C37.525 53.941 37.4907 54.0943 37.459 54.248C37.2061 55.476 37.0787 56.73 37.0801 57.9902C37.0804 76.1002 78.0401 103.5 124.8 103.47C125.123 103.47 125.446 103.468 125.767 103.464C126.408 103.456 127.045 103.442 127.676 103.419C129.254 103.362 130.799 103.258 132.306 103.108C132.607 103.078 132.907 103.047 133.205 103.014C142.151 102.004 149.676 99.3331 154.668 95.1621C154.834 95.023 154.998 94.8826 155.159 94.7402C155.32 94.5979 155.478 94.4542 155.633 94.3086C155.943 94.0174 156.241 93.7195 156.527 93.415C159.536 90.2172 161.23 86.2939 161.23 81.7002C161.23 80.7552 161.23 79.9784 160.071 74.3125L159.52 71.5703C179.349 80.1902 190.349 94.6297 190.35 107.35C190.35 123.52 178.93 144 133.65 144C74.5904 144 0 105.2 0 73.7197C0.000207427 54.5 21.7699 51.5002 38.5898 50.6602C38.5275 50.8047 38.4668 50.9498 38.4082 51.0957ZM97.0098 0C103.26 0 124.39 8.19039 134.09 13.1504C146.59 19.4004 148.1 22.63 149.82 29.75L157.27 62.1104C157.482 63.0929 157.589 64.0951 157.587 65.0996C157.586 65.2297 157.584 65.3601 157.58 65.4902C157.58 80.3699 139.48 82.9502 126.97 82.9502C123.93 82.9502 120.938 82.8321 118 82.6084C116.899 82.5245 115.805 82.4254 114.719 82.3125C108.564 81.6727 102.663 80.5774 97.0723 79.1465C95.7567 78.8098 94.4583 78.4543 93.1777 78.082C92.5379 77.896 91.9023 77.7061 91.2715 77.5117C90.6402 77.3172 90.0136 77.1184 89.3916 76.916C88.7698 76.7137 88.1525 76.5077 87.54 76.2979C86.3148 75.878 85.1084 75.4437 83.9219 74.9961C81.5493 74.101 79.2558 73.1534 77.0469 72.166C75.9424 71.6723 74.8592 71.1683 73.7979 70.6562C66.8992 67.3278 60.9266 63.644 56.0811 60.0342C55.3355 59.4787 54.6163 58.9254 53.9248 58.375C53.2334 57.8247 52.5695 57.2775 51.9336 56.7354C49.7079 54.8378 47.8271 52.9999 46.3223 51.2891C45.2474 50.0671 44.3643 48.9099 43.6846 47.8418C43.5487 47.6283 43.4213 47.4181 43.3018 47.2119C42.8831 46.4898 42.5648 45.814 42.3516 45.1924C42.2907 45.015 42.238 44.8421 42.1943 44.6738C42.1505 44.5051 42.1162 44.3409 42.0898 44.1816C42.0503 43.9433 42.0303 43.7159 42.0303 43.5C42.0085 42.8592 42.0824 42.2184 42.25 41.5996L42.2236 41.6641C42.2324 41.6294 42.2406 41.5941 42.25 41.5596C43.3284 38.1249 51.7073 14.4932 51.7402 14.4004C54.7602 5.99043 58.67 1.90043 64.6699 1.90039C70.9198 1.90039 75.8798 7.49976 82.5596 7.5C89.4995 7.5 91.19 0.000203185 97.0098 0Z" fill="black"/>
|
||||
<path d="M579.24 92.36C579.24 104.25 586.39 110.03 599.43 110.03C603.445 109.93 607.435 109.366 611.32 108.35V94.56C608.837 95.347 606.245 95.7384 603.64 95.72C598.27 95.72 596.28 94.04 596.28 88.99V67.86H611.84V53.66H596.28V35.66L579.28 39.34V53.66H567.99V67.86H579.24V92.36ZM526.24 92.68C526.24 89 529.93 87.21 535.5 87.21C538.905 87.2298 542.295 87.6527 545.6 88.47V95.62C542.343 97.399 538.681 98.3051 534.97 98.25C529.51 98.25 526.24 96.15 526.24 92.68ZM531.44 110.24C537.44 110.24 542.28 108.98 546.8 105.93V109.3H563.62V73.64C563.62 60.08 554.48 52.64 539.23 52.64C530.71 52.64 522.29 54.64 513.23 58.74L519.33 71.26C525.85 68.52 531.33 66.84 536.16 66.84C543.16 66.84 546.78 69.57 546.78 75.15V77.88C542.659 76.8132 538.417 76.2821 534.16 76.3C519.85 76.3 511.23 82.3 511.23 93.03C511.23 102.81 519.01 110.27 531.42 110.27L531.44 110.24ZM438.98 109.33H457.07V80.48H487.36V109.3H505.5V35.68H487.43V63.97H457.14V35.68H439.05L438.98 109.33ZM370.12 81.43C370.12 73.43 376.43 67.33 384.74 67.33C389.063 67.2423 393.261 68.7845 396.5 71.65V91.1C394.931 92.5825 393.084 93.7398 391.066 94.5053C389.047 95.2707 386.897 95.6292 384.74 95.56C376.54 95.56 370.12 89.46 370.12 81.47V81.43ZM396.73 109.34H413.56V32L396.56 35.68V56.61C392.232 54.1566 387.334 52.8873 382.36 52.93C366.17 52.93 353.44 65.44 353.44 81.43C353.393 85.1818 354.095 88.9054 355.503 92.3832C356.911 95.8611 358.998 99.0235 361.642 101.686C364.286 104.348 367.434 106.458 370.902 107.89C374.369 109.323 378.088 110.05 381.84 110.03C387.205 110.056 392.437 108.363 396.77 105.2L396.73 109.34ZM319.5 66.56C324.86 66.56 329.38 70.03 331.17 75.39H307.97C309.65 69.86 313.86 66.56 319.5 66.56ZM290.83 81.56C290.83 97.76 304.08 110.38 321.11 110.38C330.47 110.38 337.31 107.85 344.36 101.96L333.1 91.96C330.47 94.7 326.58 96.17 321.96 96.17C319.055 96.2518 316.193 95.452 313.751 93.8759C311.309 92.2997 309.402 90.0211 308.28 87.34H347.93V83.11C347.93 65.44 336.05 52.72 319.85 52.72C316.042 52.6625 312.261 53.3671 308.729 54.7922C305.197 56.2173 301.985 58.3342 299.283 61.0184C296.581 63.7026 294.444 66.9 292.995 70.4225C291.547 73.945 290.818 77.7215 290.85 81.53L290.83 81.56ZM261.5 51.14C267.5 51.14 270.86 54.92 270.86 59.45C270.86 63.98 267.5 67.76 261.5 67.76H243.61V51.14H261.5ZM225.5 109.3H243.59V82.48H257.36L271.25 109.3H291.5L275.3 79.85C279.417 78.1756 282.939 75.3077 285.412 71.6152C287.886 67.9226 289.198 63.5744 289.18 59.13C289.18 45.88 278.77 35.68 263.18 35.68H225.5V109.3Z" fill="black"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 428 KiB |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
|
||||
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
|
@ -1,165 +0,0 @@
|
|||
import { ImageResponse } from "next/og"
|
||||
import { NextRequest } from "next/server"
|
||||
|
||||
export const runtime = "edge"
|
||||
|
||||
async function fetchWithTimeout(url: string, init?: RequestInit, timeoutMs = 3000) {
|
||||
const controller = new AbortController()
|
||||
const id = setTimeout(() => controller.abort(), timeoutMs)
|
||||
try {
|
||||
return await fetch(url, { ...init, signal: controller.signal })
|
||||
} finally {
|
||||
clearTimeout(id)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadGoogleFont(font: string, text: string): Promise<ArrayBuffer | null> {
|
||||
try {
|
||||
const url = `https://fonts.googleapis.com/css2?family=${font}&text=${encodeURIComponent(text)}`
|
||||
const cssRes = await fetchWithTimeout(url)
|
||||
if (!cssRes.ok) return null
|
||||
const css = await cssRes.text()
|
||||
|
||||
const match =
|
||||
css.match(/src:\s*url\(([^)]+)\)\s*format\('(?:woff2|woff|opentype|truetype)'\)/i) ||
|
||||
css.match(/url\(([^)]+)\)/i)
|
||||
|
||||
const fontUrl = match && match[1] ? match[1].replace(/^['"]|['"]$/g, "") : null
|
||||
if (!fontUrl) return null
|
||||
|
||||
const res = await fetchWithTimeout(fontUrl, undefined, 5000)
|
||||
if (!res.ok) return null
|
||||
return await res.arrayBuffer()
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const requestUrl = new URL(request.url)
|
||||
const { searchParams } = requestUrl
|
||||
|
||||
// Get title and description from query params
|
||||
const title = searchParams.get("title") || "Roo Code"
|
||||
const description = searchParams.get("description") || ""
|
||||
|
||||
// Combine all text that will be displayed for font loading
|
||||
const displayText = title + description
|
||||
|
||||
// Check if we should try to use the background image
|
||||
const useBackgroundImage = searchParams.get("bg") !== "false"
|
||||
|
||||
// Dynamically get the base URL from the current request
|
||||
// This ensures it works correctly in development, preview, and production environments
|
||||
const baseUrl = `${requestUrl.protocol}//${requestUrl.host}`
|
||||
const variant = title.length % 2 === 0 ? "a" : "b"
|
||||
const backgroundUrl = `${baseUrl}/og/base_${variant}.png`
|
||||
|
||||
// Preload fonts with graceful fallbacks
|
||||
const regularFont = await loadGoogleFont("Inter", displayText)
|
||||
const boldFont = await loadGoogleFont("Inter:wght@700", displayText)
|
||||
const fonts: { name: string; data: ArrayBuffer; style?: "normal" | "italic"; weight?: 400 | 700 }[] = []
|
||||
if (regularFont) {
|
||||
fonts.push({ name: "Inter", data: regularFont, style: "normal", weight: 400 })
|
||||
}
|
||||
if (boldFont) {
|
||||
fonts.push({ name: "Inter", data: boldFont, style: "normal", weight: 700 })
|
||||
}
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
position: "relative",
|
||||
// Use gradient background as default/fallback
|
||||
background: "linear-gradient(135deg, #1e3a5f 0%, #0f1922 50%, #1a2332 100%)",
|
||||
}}>
|
||||
{/* Optional Background Image - only render if explicitly requested */}
|
||||
{useBackgroundImage && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
}}>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={backgroundUrl}
|
||||
alt=""
|
||||
width={1200}
|
||||
height={630}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "cover",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Text Content */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "flex-end",
|
||||
top: "220px",
|
||||
left: "80px",
|
||||
right: "80px",
|
||||
bottom: "80px",
|
||||
}}>
|
||||
{/* Main Title */}
|
||||
<h1
|
||||
style={{
|
||||
fontSize: 70,
|
||||
fontWeight: 700,
|
||||
fontFamily: "Inter, Helvetica Neue, Helvetica, sans-serif",
|
||||
color: "white",
|
||||
lineHeight: 1.2,
|
||||
margin: 0,
|
||||
maxHeight: "2.4em",
|
||||
overflow: "hidden",
|
||||
}}>
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
{/* Secondary Description */}
|
||||
{description && (
|
||||
<h2
|
||||
style={{
|
||||
fontSize: 70,
|
||||
fontWeight: 400,
|
||||
fontFamily: "Inter, Helvetica Neue, Helvetica, Arial, sans-serif",
|
||||
color: "rgba(255, 255, 255, 0.9)",
|
||||
lineHeight: 1.2,
|
||||
margin: 0,
|
||||
maxHeight: "2.4em",
|
||||
overflow: "hidden",
|
||||
}}>
|
||||
{description}
|
||||
</h2>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
fonts: fonts.length ? fonts : undefined,
|
||||
// Cache for 7 days in production, 3 seconds in development
|
||||
headers: {
|
||||
"Cache-Control":
|
||||
process.env.NODE_ENV === "production"
|
||||
? "public, max-age=604800, s-maxage=604800, stale-while-revalidate=86400"
|
||||
: "public, max-age=3, s-maxage=3",
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -1,329 +0,0 @@
|
|||
/**
|
||||
* Blog Post Page
|
||||
* MKT-69: Blog Post Page
|
||||
*
|
||||
* Renders a single blog post from Markdown.
|
||||
* Uses dynamic rendering (force-dynamic) for request-time publish gating.
|
||||
* Does NOT use generateStaticParams to avoid static generation.
|
||||
*
|
||||
* AEO Enhancement: Parses FAQ sections from markdown, renders as accordion,
|
||||
* and generates FAQPage JSON-LD schema for AI search optimization.
|
||||
*/
|
||||
|
||||
import type { Metadata } from "next"
|
||||
import Link from "next/link"
|
||||
import { notFound } from "next/navigation"
|
||||
import Script from "next/script"
|
||||
import { ChevronLeft, ChevronRight, Clock } from "lucide-react"
|
||||
import {
|
||||
getBlogPostBySlug,
|
||||
getAdjacentPosts,
|
||||
formatPostDatePt,
|
||||
calculateReadingTime,
|
||||
formatReadingTime,
|
||||
} from "@/lib/blog"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
import { BlogContent } from "@/components/blog/BlogContent"
|
||||
import { BlogFAQ, type FAQItem } from "@/components/blog/BlogFAQ"
|
||||
|
||||
// Force dynamic rendering for request-time publish gating
|
||||
export const dynamic = "force-dynamic"
|
||||
export const runtime = "nodejs"
|
||||
|
||||
interface Props {
|
||||
params: Promise<{ slug: string }>
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse FAQ section from markdown content
|
||||
*
|
||||
* Looks for a section starting with "## Frequently asked questions"
|
||||
* and extracts H3 questions with their content as answers.
|
||||
*
|
||||
* Returns the FAQ items and the content with FAQ section removed.
|
||||
*/
|
||||
function parseFAQFromMarkdown(content: string): {
|
||||
faqItems: FAQItem[]
|
||||
contentWithoutFAQ: string
|
||||
} {
|
||||
// Match FAQ section: ## Frequently asked questions (case-insensitive)
|
||||
const faqSectionRegex = /^## Frequently asked questions\s*$/im
|
||||
const faqMatch = content.match(faqSectionRegex)
|
||||
|
||||
if (!faqMatch || faqMatch.index === undefined) {
|
||||
return { faqItems: [], contentWithoutFAQ: content }
|
||||
}
|
||||
|
||||
const faqStartIndex = faqMatch.index
|
||||
const beforeFAQ = content.slice(0, faqStartIndex).trim()
|
||||
const faqSection = content.slice(faqStartIndex)
|
||||
|
||||
// Find where FAQ section ends (next H2 or end of content)
|
||||
const nextH2Match = faqSection.slice(faqMatch[0].length).match(/^## /m)
|
||||
const faqContent =
|
||||
nextH2Match && nextH2Match.index !== undefined
|
||||
? faqSection.slice(0, faqMatch[0].length + nextH2Match.index)
|
||||
: faqSection
|
||||
|
||||
const afterFAQ =
|
||||
nextH2Match && nextH2Match.index !== undefined ? faqSection.slice(faqMatch[0].length + nextH2Match.index) : ""
|
||||
|
||||
// Parse individual FAQ items (### Question followed by content)
|
||||
const faqItems: FAQItem[] = []
|
||||
const questionRegex = /^### (.+?)$\s*([\s\S]*?)(?=^### |$(?![\s\S]))/gm
|
||||
let match
|
||||
|
||||
while ((match = questionRegex.exec(faqContent)) !== null) {
|
||||
const question = match[1]?.trim()
|
||||
const answer = match[2]?.trim()
|
||||
if (question && answer) {
|
||||
faqItems.push({ question, answer })
|
||||
}
|
||||
}
|
||||
|
||||
const contentWithoutFAQ = (beforeFAQ + "\n\n" + afterFAQ).trim()
|
||||
|
||||
return { faqItems, contentWithoutFAQ }
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const { slug } = await params
|
||||
const post = getBlogPostBySlug(slug)
|
||||
|
||||
if (!post) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const path = `/blog/${post.slug}`
|
||||
|
||||
return {
|
||||
title: post.title,
|
||||
description: post.description,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${path}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: post.title,
|
||||
description: post.description,
|
||||
url: `${SEO.url}${path}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(post.title, post.description),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: post.title,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "article",
|
||||
publishedTime: post.publish_date,
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: post.title,
|
||||
description: post.description,
|
||||
images: [ogImageUrl(post.title, post.description)],
|
||||
},
|
||||
keywords: [...SEO.keywords, ...post.tags],
|
||||
}
|
||||
}
|
||||
|
||||
export default async function BlogPostPage({ params }: Props) {
|
||||
const { slug } = await params
|
||||
const post = getBlogPostBySlug(slug)
|
||||
|
||||
if (!post) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const { previous, next } = getAdjacentPosts(slug)
|
||||
|
||||
// Calculate reading time
|
||||
const readingTime = calculateReadingTime(post.content)
|
||||
const readingTimeDisplay = formatReadingTime(readingTime)
|
||||
|
||||
// Parse FAQ section from markdown content
|
||||
const { faqItems, contentWithoutFAQ } = parseFAQFromMarkdown(post.content)
|
||||
const hasFAQ = faqItems.length > 0
|
||||
|
||||
// BlogPosting JSON-LD schema (more specific than Article for SEO)
|
||||
const articleSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
headline: post.title,
|
||||
description: post.description,
|
||||
datePublished: post.publish_date,
|
||||
image: ogImageUrl(post.title, post.description),
|
||||
wordCount: post.content.split(/\s+/).filter(Boolean).length,
|
||||
mainEntityOfPage: {
|
||||
"@type": "WebPage",
|
||||
"@id": `${SEO.url}/blog/${post.slug}`,
|
||||
},
|
||||
url: `${SEO.url}/blog/${post.slug}`,
|
||||
author: {
|
||||
"@type": "Organization",
|
||||
"@id": `${SEO.url}#org`,
|
||||
name: SEO.name,
|
||||
},
|
||||
publisher: {
|
||||
"@type": "Organization",
|
||||
"@id": `${SEO.url}#org`,
|
||||
name: SEO.name,
|
||||
logo: {
|
||||
"@type": "ImageObject",
|
||||
url: `${SEO.url}/android-chrome-512x512.png`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Breadcrumb schema
|
||||
const breadcrumbSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 1,
|
||||
name: "Home",
|
||||
item: SEO.url,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: "Blog",
|
||||
item: `${SEO.url}/blog`,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 3,
|
||||
name: post.title,
|
||||
item: `${SEO.url}/blog/${post.slug}`,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
// FAQPage schema (only if post has FAQ section) - AEO optimization
|
||||
const faqSchema = hasFAQ
|
||||
? {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
mainEntity: faqItems.map((item) => ({
|
||||
"@type": "Question",
|
||||
name: item.question,
|
||||
acceptedAnswer: {
|
||||
"@type": "Answer",
|
||||
text: item.answer,
|
||||
},
|
||||
})),
|
||||
}
|
||||
: null
|
||||
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
id="article-schema"
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(articleSchema) }}
|
||||
/>
|
||||
<Script
|
||||
id="breadcrumb-schema"
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
|
||||
/>
|
||||
{faqSchema && (
|
||||
<Script
|
||||
id="faq-schema"
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<article className="container mx-auto px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
{/* Visual Breadcrumb Navigation */}
|
||||
<nav aria-label="Breadcrumb" className="mb-8">
|
||||
<ol className="flex items-center gap-1 text-sm text-muted-foreground">
|
||||
<li>
|
||||
<Link href="/blog" className="transition-colors hover:text-foreground">
|
||||
Blog
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</li>
|
||||
<li className="truncate text-foreground" aria-current="page">
|
||||
{post.title}
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div className="prose prose-lg dark:prose-invert">
|
||||
<header className="not-prose mb-8">
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">{post.title}</h1>
|
||||
<div className="mt-4 flex flex-wrap items-center gap-3 text-sm text-muted-foreground">
|
||||
<span>{formatPostDatePt(post.publish_date)}</span>
|
||||
<span className="text-border">•</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="h-4 w-4" />
|
||||
{readingTimeDisplay}
|
||||
</span>
|
||||
</div>
|
||||
{post.tags.length > 0 && (
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
{post.tags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="rounded bg-muted px-2 py-1 text-xs text-muted-foreground">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
|
||||
<BlogContent content={contentWithoutFAQ} />
|
||||
|
||||
{/* FAQ Section rendered as accordion */}
|
||||
{hasFAQ && <BlogFAQ items={faqItems} />}
|
||||
</div>
|
||||
|
||||
{/* Previous/Next Post Navigation */}
|
||||
{(previous || next) && (
|
||||
<nav aria-label="Post navigation" className="mt-12 border-t border-border pt-8">
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:justify-between">
|
||||
{previous ? (
|
||||
<Link
|
||||
href={`/blog/${previous.slug}`}
|
||||
className="group flex items-center gap-2 text-sm text-muted-foreground transition-colors hover:text-foreground">
|
||||
<ChevronLeft className="h-4 w-4 transition-transform group-hover:-translate-x-1" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs uppercase tracking-wide">Previous</span>
|
||||
<span className="font-medium text-foreground">{previous.title}</span>
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
{next ? (
|
||||
<Link
|
||||
href={`/blog/${next.slug}`}
|
||||
className="group flex items-center gap-2 text-sm text-muted-foreground transition-colors hover:text-foreground sm:flex-row-reverse sm:text-right">
|
||||
<ChevronRight className="h-4 w-4 transition-transform group-hover:translate-x-1" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs uppercase tracking-wide">Next</span>
|
||||
<span className="font-medium text-foreground">{next.title}</span>
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
/**
|
||||
* Blog Index Page
|
||||
* MKT-68: Blog Index Page
|
||||
*
|
||||
* Lists published blog posts with two views:
|
||||
* - Featured (default): Curated 24 posts aligned with Roo Code positioning
|
||||
* - All: Full list with pagination (12 posts per page)
|
||||
*
|
||||
* Uses dynamic rendering (force-dynamic) for request-time publish gating.
|
||||
*/
|
||||
|
||||
import type { Metadata } from "next"
|
||||
import Script from "next/script"
|
||||
import { Suspense } from "react"
|
||||
import { getPaginatedBlogPosts, getAllBlogPosts, getCuratedBlogPosts } from "@/lib/blog"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
import { BlogPostList } from "@/components/blog/BlogPostList"
|
||||
import { BlogPagination } from "@/components/blog/BlogPagination"
|
||||
|
||||
import { BlogViewToggle } from "@/components/blog/BlogViewToggle"
|
||||
|
||||
// Force dynamic rendering for request-time publish gating
|
||||
export const dynamic = "force-dynamic"
|
||||
export const runtime = "nodejs"
|
||||
|
||||
const TITLE = "Blog"
|
||||
const DESCRIPTION = "How teams use agents to iterate, review, and ship PRs with proof."
|
||||
const PATH = "/blog"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${PATH}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${PATH}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(TITLE, DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: TITLE,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: [ogImageUrl(TITLE, DESCRIPTION)],
|
||||
},
|
||||
keywords: [...SEO.keywords, "blog", "articles", "engineering", "AI development"],
|
||||
}
|
||||
|
||||
interface Props {
|
||||
searchParams: Promise<{ view?: string; page?: string }>
|
||||
}
|
||||
|
||||
export default async function BlogIndexPage({ searchParams }: Props) {
|
||||
const params = await searchParams
|
||||
const view = params.view === "all" ? "all" : "featured"
|
||||
const pageParam = params.page ? parseInt(params.page, 10) : 1
|
||||
|
||||
// Get all posts for counts and schema
|
||||
const allPosts = getAllBlogPosts()
|
||||
const curatedPosts = getCuratedBlogPosts()
|
||||
|
||||
// Determine which posts to display based on view
|
||||
let displayPosts
|
||||
let currentPage = 1
|
||||
let totalPages = 1
|
||||
let showPagination = false
|
||||
|
||||
if (view === "all") {
|
||||
const paginated = getPaginatedBlogPosts(pageParam)
|
||||
displayPosts = paginated.posts
|
||||
currentPage = paginated.currentPage
|
||||
totalPages = paginated.totalPages
|
||||
showPagination = totalPages > 1
|
||||
} else {
|
||||
// Featured view shows curated posts without pagination
|
||||
displayPosts = curatedPosts
|
||||
}
|
||||
|
||||
// Schema.org CollectionPage + ItemList (includes all posts for SEO)
|
||||
const blogSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "CollectionPage",
|
||||
name: TITLE,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${PATH}`,
|
||||
mainEntity: {
|
||||
"@type": "ItemList",
|
||||
itemListElement: allPosts.map((post, index) => ({
|
||||
"@type": "ListItem",
|
||||
position: index + 1,
|
||||
url: `${SEO.url}/blog/${post.slug}`,
|
||||
name: post.title,
|
||||
})),
|
||||
},
|
||||
}
|
||||
|
||||
// Breadcrumb schema
|
||||
const breadcrumbSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 1,
|
||||
name: "Home",
|
||||
item: SEO.url,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: "Blog",
|
||||
item: `${SEO.url}${PATH}`,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
id="blog-schema"
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(blogSchema) }}
|
||||
/>
|
||||
<Script
|
||||
id="breadcrumb-schema"
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
|
||||
/>
|
||||
|
||||
<div className="container mx-auto px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">Blog</h1>
|
||||
<p className="mt-4 text-lg text-muted-foreground">{DESCRIPTION}</p>
|
||||
|
||||
{/* View Toggle */}
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="mt-6 flex items-center gap-4">
|
||||
<div className="h-11 w-64 animate-pulse rounded-lg bg-muted" />
|
||||
</div>
|
||||
}>
|
||||
<BlogViewToggle curatedCount={curatedPosts.length} totalCount={allPosts.length} />
|
||||
</Suspense>
|
||||
|
||||
{/* Post count indicator for "all" view */}
|
||||
{view === "all" && totalPages > 1 && (
|
||||
<p className="mt-4 text-sm text-muted-foreground">
|
||||
Showing {displayPosts.length} of {allPosts.length} posts
|
||||
</p>
|
||||
)}
|
||||
|
||||
<BlogPostList posts={displayPosts} />
|
||||
|
||||
{/* Pagination only for "all" view */}
|
||||
{showPagination && (
|
||||
<BlogPagination currentPage={currentPage} totalPages={totalPages} useQueryParams />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
/**
|
||||
* Blog Paginated Index Page
|
||||
* Handles pages 2+ of the blog listing
|
||||
*
|
||||
* URL structure: /blog/page/2, /blog/page/3, etc.
|
||||
* Page 1 redirects to /blog for canonical URL consistency.
|
||||
*/
|
||||
|
||||
import type { Metadata } from "next"
|
||||
import { notFound, redirect } from "next/navigation"
|
||||
import Script from "next/script"
|
||||
import { getPaginatedBlogPosts, getAllBlogPosts, POSTS_PER_PAGE } from "@/lib/blog"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
import { BlogPostList } from "@/components/blog/BlogPostList"
|
||||
import { BlogPagination } from "@/components/blog/BlogPagination"
|
||||
|
||||
// Force dynamic rendering for request-time publish gating
|
||||
export const dynamic = "force-dynamic"
|
||||
export const runtime = "nodejs"
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ page: string }>
|
||||
}
|
||||
|
||||
const BASE_TITLE = "Blog"
|
||||
const DESCRIPTION = "How teams use agents to iterate, review, and ship PRs with proof."
|
||||
const BASE_PATH = "/blog"
|
||||
|
||||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||||
const { page: pageParam } = await params
|
||||
const pageNumber = parseInt(pageParam, 10)
|
||||
const title = `${BASE_TITLE} - Page ${pageNumber}`
|
||||
const path = `${BASE_PATH}/page/${pageNumber}`
|
||||
|
||||
return {
|
||||
title,
|
||||
description: DESCRIPTION,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${path}`,
|
||||
},
|
||||
openGraph: {
|
||||
title,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${path}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(title, DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: title,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title,
|
||||
description: DESCRIPTION,
|
||||
images: [ogImageUrl(title, DESCRIPTION)],
|
||||
},
|
||||
keywords: [...SEO.keywords, "blog", "articles", "engineering", "AI development"],
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate static params for known pages at build time
|
||||
* This helps with initial page load performance
|
||||
*/
|
||||
export async function generateStaticParams() {
|
||||
const allPosts = getAllBlogPosts()
|
||||
const totalPages = Math.ceil(allPosts.length / POSTS_PER_PAGE)
|
||||
|
||||
// Generate params for pages 2 through totalPages
|
||||
const params = []
|
||||
for (let page = 2; page <= totalPages; page++) {
|
||||
params.push({ page: page.toString() })
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
export default async function BlogPaginatedPage({ params }: PageProps) {
|
||||
const { page: pageParam } = await params
|
||||
const pageNumber = parseInt(pageParam, 10)
|
||||
|
||||
// Validate page number
|
||||
if (isNaN(pageNumber) || pageNumber < 1) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
// Redirect page 1 to /blog for canonical URL
|
||||
if (pageNumber === 1) {
|
||||
redirect("/blog")
|
||||
}
|
||||
|
||||
const { posts, currentPage, totalPages, totalPosts } = getPaginatedBlogPosts(pageNumber)
|
||||
|
||||
// If page is beyond total pages, 404
|
||||
if (pageNumber > totalPages && totalPages > 0) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const title = `${BASE_TITLE} - Page ${pageNumber}`
|
||||
const path = `${BASE_PATH}/page/${pageNumber}`
|
||||
|
||||
// Breadcrumb schema
|
||||
const breadcrumbSchema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 1,
|
||||
name: "Home",
|
||||
item: SEO.url,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: "Blog",
|
||||
item: `${SEO.url}${BASE_PATH}`,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 3,
|
||||
name: `Page ${pageNumber}`,
|
||||
item: `${SEO.url}${path}`,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
// Calculate post range for display
|
||||
const startPost = (currentPage - 1) * POSTS_PER_PAGE + 1
|
||||
const endPost = Math.min(currentPage * POSTS_PER_PAGE, totalPosts)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
id="breadcrumb-schema"
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbSchema) }}
|
||||
/>
|
||||
|
||||
<div className="container mx-auto px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">{title}</h1>
|
||||
<p className="mt-4 text-lg text-muted-foreground">{DESCRIPTION}</p>
|
||||
|
||||
<p className="mt-2 text-sm text-muted-foreground">
|
||||
Showing posts {startPost}-{endPost} of {totalPosts}
|
||||
</p>
|
||||
|
||||
<BlogPostList posts={posts} />
|
||||
|
||||
<BlogPagination currentPage={currentPage} totalPages={totalPages} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
--radius: 0.5rem;
|
||||
|
||||
--chart-1: 0 100% 50%;
|
||||
--chart-2: 29 100% 50%;
|
||||
--chart-3: 51 100% 50%;
|
||||
--chart-4: 83 100% 50%;
|
||||
--chart-5: 115 100% 50%;
|
||||
--chart-6: 147 100% 50%;
|
||||
--chart-7: 168 100% 50%;
|
||||
--chart-8: 196 100% 50%;
|
||||
--chart-9: 224 100% 50%;
|
||||
--chart-10: 261 100% 50%;
|
||||
--chart-11: 279 100% 50%;
|
||||
--chart-12: 298 100% 50%;
|
||||
--chart-13: 324 100% 50%;
|
||||
--chart-14: 358 100% 50%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 0 0% 0%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
import React from "react"
|
||||
import type { Metadata } from "next"
|
||||
import { Inter } from "next/font/google"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
import { CookieConsentWrapper } from "@/components/CookieConsentWrapper"
|
||||
import { RoomoteAnnouncementBanner } from "@/components/RoomoteAnnouncementBanner"
|
||||
|
||||
import { Providers } from "@/components/providers"
|
||||
|
||||
import Shell from "./shell"
|
||||
|
||||
import "./globals.css"
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] })
|
||||
|
||||
const OG_TITLE = "Meet Roo Code"
|
||||
const OG_DESCRIPTION = "Your AI Software Engineering Team in the IDE and the Cloud."
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SEO.url),
|
||||
title: {
|
||||
template: "%s | Roo Code",
|
||||
default: SEO.title,
|
||||
},
|
||||
description: SEO.description,
|
||||
alternates: {
|
||||
canonical: SEO.url,
|
||||
},
|
||||
icons: {
|
||||
icon: [
|
||||
{ url: "/favicon.ico" },
|
||||
{ url: "/favicon-16x16.png", sizes: "16x16", type: "image/png" },
|
||||
{ url: "/favicon-32x32.png", sizes: "32x32", type: "image/png" },
|
||||
],
|
||||
apple: [{ url: "/apple-touch-icon.png" }],
|
||||
other: [
|
||||
{
|
||||
rel: "android-chrome-192x192",
|
||||
url: "/android-chrome-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png",
|
||||
},
|
||||
{
|
||||
rel: "android-chrome-512x512",
|
||||
url: "/android-chrome-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
},
|
||||
],
|
||||
},
|
||||
openGraph: {
|
||||
title: SEO.title,
|
||||
description: SEO.description,
|
||||
url: SEO.url,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(OG_TITLE, OG_DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: OG_TITLE,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: SEO.title,
|
||||
description: SEO.description,
|
||||
images: [ogImageUrl(OG_TITLE, OG_DESCRIPTION)],
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
googleBot: {
|
||||
index: true,
|
||||
follow: true,
|
||||
"max-snippet": -1,
|
||||
"max-image-preview": "large",
|
||||
"max-video-preview": -1,
|
||||
},
|
||||
},
|
||||
keywords: [...SEO.keywords],
|
||||
applicationName: SEO.name,
|
||||
category: SEO.category,
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css"
|
||||
/>
|
||||
</head>
|
||||
<body className={inter.className}>
|
||||
<RoomoteAnnouncementBanner />
|
||||
<div itemScope itemType="https://schema.org/WebSite">
|
||||
<link itemProp="url" href={SEO.url} />
|
||||
<meta itemProp="name" content={SEO.name} />
|
||||
</div>
|
||||
<Providers>
|
||||
<Shell>{children}</Shell>
|
||||
<CookieConsentWrapper />
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
import type { Metadata } from "next"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
|
||||
const TITLE = "Our Cookie Policy"
|
||||
const DESCRIPTION = "Learn about how Roo Code uses cookies to enhance your experience and provide our services."
|
||||
const OG_DESCRIPTION = ""
|
||||
const PATH = "/legal/cookies"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${PATH}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${PATH}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(TITLE, OG_DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: TITLE,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "article",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
|
||||
},
|
||||
keywords: [...SEO.keywords, "cookies", "privacy", "tracking", "analytics"],
|
||||
}
|
||||
|
||||
export default function CookiePolicy() {
|
||||
return (
|
||||
<>
|
||||
<div className="container mx-auto px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="prose prose-lg mx-auto max-w-4xl dark:prose-invert">
|
||||
<p className="text-muted-foreground">Updated: September 18, 2025</p>
|
||||
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">Cookie Policy</h1>
|
||||
|
||||
<p className="lead">
|
||||
This Cookie Policy explains how Roo Code uses cookies and similar technologies to recognize you
|
||||
when you visit our website.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">What are cookies?</h2>
|
||||
<p>
|
||||
Cookies are small data files that are placed on your computer or mobile device when you visit a
|
||||
website. Cookies help make websites work more efficiently and provide reporting information.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Cookies we use</h2>
|
||||
<p>
|
||||
We use a minimal number of cookies to provide essential functionality and improve your
|
||||
experience.
|
||||
</p>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full border-collapse border border-border">
|
||||
<thead>
|
||||
<tr className="bg-muted/50">
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">Provider</th>
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">Purpose</th>
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">Type</th>
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">Duration</th>
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">
|
||||
Example Cookies
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Clerk</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Authentication and session management
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">Essential</td>
|
||||
<td className="border border-border px-4 py-3">1 year and 1 month</td>
|
||||
<td className="border border-border px-4 py-3 font-mono text-sm">
|
||||
__client_uat*, __clerk_*
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Analytics</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Product analytics and feature usage tracking
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Analytics (only with your consent)
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">1 year</td>
|
||||
<td className="border border-border px-4 py-3 font-mono text-sm">ph_*</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">HubSpot</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Marketing automation and visitor tracking
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Analytics (only with your consent)
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">13 months</td>
|
||||
<td className="border border-border px-4 py-3 font-mono text-sm">
|
||||
hubspotutk, __hstc, __hssrc, __hssc
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p className="mt-4">
|
||||
<a
|
||||
href="https://clerk.com/legal/privacy"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline">
|
||||
Clerk Privacy Policy
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a
|
||||
href="https://legal.hubspot.com/privacy-policy"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline">
|
||||
HubSpot Privacy Policy
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Essential cookies</h2>
|
||||
<p>
|
||||
Essential cookies are required for our website to operate. These include authentication cookies
|
||||
from Clerk that allow you to stay logged in to your account. These cookies cannot be disabled
|
||||
without losing core website functionality. The lawful basis for processing these cookies is our
|
||||
legitimate interest in providing secure access to our services.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Analytics cookies</h2>
|
||||
<p>
|
||||
We use HubSpot analytics cookies to understand how visitors interact with our website. This
|
||||
helps us improve our services, user experience, and marketing efforts. Analytics cookies are
|
||||
placed only if you give consent through our cookie banner. The lawful basis for processing these
|
||||
cookies is your consent, which you can withdraw at any time.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Third-party services</h2>
|
||||
<p>
|
||||
Our blog at{" "}
|
||||
<a
|
||||
href="https://blog.roocode.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline">
|
||||
blog.roocode.com
|
||||
</a>{" "}
|
||||
is hosted on Substack. When you visit it, Substack may set cookies for analytics,
|
||||
personalization, and advertising/marketing. These cookies are managed directly by Substack and
|
||||
are outside our control. You can read more in{" "}
|
||||
<a
|
||||
href="https://substack.com/privacy"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline">
|
||||
Substack's Cookie Policy
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">How to control cookies</h2>
|
||||
<p>You can control and manage cookies through your browser settings. Most browsers allow you to:</p>
|
||||
<ul>
|
||||
<li>View what cookies are stored on your device</li>
|
||||
<li>Delete cookies individually or all at once</li>
|
||||
<li>Block third-party cookies</li>
|
||||
<li>Block cookies from specific websites</li>
|
||||
<li>Block all cookies from being set</li>
|
||||
<li>Delete all cookies when you close your browser</li>
|
||||
</ul>
|
||||
<p>
|
||||
Please note that blocking essential cookies may prevent you from using certain features of our
|
||||
website, such as staying logged in to your account.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Changes to this policy</h2>
|
||||
<p>
|
||||
We may update this Cookie Policy from time to time. When we make changes, we will update the
|
||||
date at the top of this policy. We encourage you to periodically review this policy to stay
|
||||
informed about our use of cookies.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Contact us</h2>
|
||||
<p>
|
||||
If you have questions about our use of cookies, please contact us at{" "}
|
||||
<a href="mailto:privacy@roocode.com" className="text-primary hover:underline">
|
||||
privacy@roocode.com
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
import type { Metadata } from "next"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
|
||||
const TITLE = "Subprocessors"
|
||||
const DESCRIPTION = "List of third-party subprocessors used by Roo Code to process customer data."
|
||||
const OG_DESCRIPTION = ""
|
||||
const PATH = "/legal/subprocessors"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${PATH}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${PATH}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(TITLE, OG_DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: TITLE,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "article",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
|
||||
},
|
||||
keywords: [...SEO.keywords, "subprocessors", "data processing", "GDPR", "privacy", "third-party services"],
|
||||
}
|
||||
|
||||
export default function SubProcessors() {
|
||||
return (
|
||||
<>
|
||||
<div className="container mx-auto px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="prose prose-lg mx-auto max-w-5xl dark:prose-invert">
|
||||
<p className="text-muted-foreground">Updated: October 17, 2025</p>
|
||||
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">Subprocessors</h1>
|
||||
|
||||
<p className="lead">Roo Code engages the following third parties to process Customer Data.</p>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full border-collapse border border-border">
|
||||
<thead>
|
||||
<tr className="bg-muted/50">
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">
|
||||
Entity Name
|
||||
</th>
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">
|
||||
Product or Service
|
||||
</th>
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">
|
||||
Location of Processing
|
||||
</th>
|
||||
<th className="border border-border px-4 py-3 text-left font-semibold">
|
||||
Purpose of Processing
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Census</td>
|
||||
<td className="border border-border px-4 py-3">Data Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Data activation and reverse ETL</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Clerk</td>
|
||||
<td className="border border-border px-4 py-3">Authentication Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">User authentication</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">ClickHouse</td>
|
||||
<td className="border border-border px-4 py-3">Data Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Real-time analytics database</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Cloudflare</td>
|
||||
<td className="border border-border px-4 py-3">All Services</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Processing at data center closest to End User
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Content delivery network and security
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Fivetran</td>
|
||||
<td className="border border-border px-4 py-3">Data Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">ETL and data integration</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Fly.io</td>
|
||||
<td className="border border-border px-4 py-3">Backend Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Application hosting and deployment
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">HubSpot</td>
|
||||
<td className="border border-border px-4 py-3">Customer Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">CRM and marketing automation</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Intercom</td>
|
||||
<td className="border border-border px-4 py-3">Communication Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Customer messaging and support</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Loops</td>
|
||||
<td className="border border-border px-4 py-3">Communication Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Email and customer communication</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Metabase</td>
|
||||
<td className="border border-border px-4 py-3">Data Analytics</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Business intelligence and reporting
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Analytics</td>
|
||||
<td className="border border-border px-4 py-3">Data Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Product analytics</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Sentry</td>
|
||||
<td className="border border-border px-4 py-3">All Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Error tracking and monitoring</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Snowflake</td>
|
||||
<td className="border border-border px-4 py-3">Data Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Data warehousing and analytics</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Stripe</td>
|
||||
<td className="border border-border px-4 py-3">Payment Services</td>
|
||||
<td className="border border-border px-4 py-3">United States, Europe</td>
|
||||
<td className="border border-border px-4 py-3">Payment processing and billing</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Supabase</td>
|
||||
<td className="border border-border px-4 py-3">Data Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Database management and storage</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-3 font-medium">Upstash</td>
|
||||
<td className="border border-border px-4 py-3">Infrastructure Services</td>
|
||||
<td className="border border-border px-4 py-3">United States</td>
|
||||
<td className="border border-border px-4 py-3">Serverless database services</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">Vercel</td>
|
||||
<td className="border border-border px-4 py-3">Customer-facing Services</td>
|
||||
<td className="border border-border px-4 py-3">United States, Europe</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Web application hosting and deployment
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
import { Button } from "@/components/ui"
|
||||
import {
|
||||
AnimatedBackground,
|
||||
CodeExample,
|
||||
CompanyLogos,
|
||||
FAQSection,
|
||||
Features,
|
||||
Testimonials,
|
||||
CTASection,
|
||||
PillarsSection,
|
||||
} from "@/components/homepage"
|
||||
import { EXTERNAL_LINKS } from "@/lib/constants"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { StructuredData } from "@/components/structured-data"
|
||||
|
||||
// Invalidate cache when a request comes in, at most once every hour.
|
||||
export const revalidate = 3600
|
||||
|
||||
export default async function Home() {
|
||||
return (
|
||||
<>
|
||||
<StructuredData />
|
||||
<section className="relative flex h-[calc(125vh-theme(spacing.12))] items-center overflow-hidden md:h-[calc(80svh-theme(spacing.12))]">
|
||||
<AnimatedBackground />
|
||||
<div className="container relative flex items-center h-full z-10 mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid h-full relative gap-8 md:gap-12 lg:grid-cols-2 lg:gap-16">
|
||||
<div className="flex flex-col justify-center space-y-4 sm:space-y-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold tracking-tight mt-8 text-center md:text-left md:text-4xl lg:text-5xl lg:mt-0">
|
||||
The Open Source AI Coding Assistant for serious work.
|
||||
</h1>
|
||||
<p className="mt-4 max-w-lg text-lg text-muted-foreground text-center md:text-left sm:mt-6">
|
||||
Specialized modes stay on task and ship great code.
|
||||
<br />
|
||||
Fully model-agnostic so you can use the best (or most cost-effective) model for each
|
||||
task.
|
||||
</p>
|
||||
<p className="max-w-lg text-lg text-muted-foreground text-center md:text-left sm:mt-6">
|
||||
Stop chasing this week's hot new model or CLI tool and go deep with Roo Code.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-3 sm:flex-row sm:space-x-4 sm:space-y-0">
|
||||
<Button
|
||||
size="lg"
|
||||
className="w-full hover:bg-gray-200 dark:bg-white dark:text-black sm:w-auto">
|
||||
<a
|
||||
href={EXTERNAL_LINKS.MARKETPLACE}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex w-full items-center justify-center">
|
||||
Install VS Code Extension
|
||||
<ArrowRight className="ml-2" />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="md:max-h-[70px] md:overflow-clip text-center md:text-left pt-6 md:pt-0">
|
||||
<CompanyLogos />
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative flex items-center mx-auto h-full mt-8 lg:mt-0">
|
||||
<div className="flex items-center justify-center">
|
||||
<CodeExample />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<PillarsSection />
|
||||
<div id="product">
|
||||
<Features />
|
||||
</div>
|
||||
<div id="testimonials">
|
||||
<Testimonials />
|
||||
</div>
|
||||
<div id="faq">
|
||||
<FAQSection />
|
||||
</div>
|
||||
<CTASection />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,320 +0,0 @@
|
|||
import type { Metadata } from "next"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
|
||||
const TITLE = "Our Privacy Policy"
|
||||
const DESCRIPTION =
|
||||
"Privacy policy for Roo Code Cloud and marketing website. Learn how we handle your data and protect your privacy."
|
||||
const OG_DESCRIPTION = ""
|
||||
const PATH = "/privacy"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${PATH}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${PATH}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(TITLE, OG_DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: TITLE,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "article",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
|
||||
},
|
||||
keywords: [...SEO.keywords, "privacy", "data protection", "GDPR", "security"],
|
||||
}
|
||||
|
||||
export default function Privacy() {
|
||||
return (
|
||||
<>
|
||||
<div className="container mx-auto px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="prose prose-lg mx-auto max-w-4xl dark:prose-invert">
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">
|
||||
Roo Code Cloud Privacy Policy
|
||||
</h1>
|
||||
<p className="text-muted-foreground">Last Updated: September 19, 2025</p>
|
||||
|
||||
<p className="lead">
|
||||
This Privacy Policy explains how Roo Code, Inc. ("Roo Code," "we,"
|
||||
"our," or "us") collects, uses, and shares information when you:
|
||||
</p>
|
||||
<ul className="lead">
|
||||
<li>
|
||||
browse any page under <strong>roocode.com</strong> (the <em>Marketing Site</em>); and/or
|
||||
</li>
|
||||
<li>
|
||||
create an account for, sign in to, or otherwise use <strong>Roo Code Cloud</strong> at{" "}
|
||||
<strong>app.roocode.com</strong> or through the Roo Code extension while authenticated to
|
||||
that Cloud account (the <em>Cloud Service</em>).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className="my-8 rounded-lg border border-border bg-muted/50 p-6">
|
||||
<h3 className="mt-0 text-lg font-semibold">Extension‑Only Usage</h3>
|
||||
<p className="mb-0">
|
||||
If you run the Roo Code extension <strong>without</strong> connecting to a Cloud account,
|
||||
your data is governed by the standalone{" "}
|
||||
<a
|
||||
href="https://github.com/RooCodeInc/Roo-Code/blob/main/PRIVACY.md"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline">
|
||||
Roo Code Extension Privacy Policy
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Quick Summary</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>
|
||||
Your source code does not transit Roo Code servers unless you explicitly choose Roo Code
|
||||
as a model provider (proxy mode).
|
||||
</strong>{" "}
|
||||
When Roo Code Cloud is your model provider, your code briefly transits Roo Code servers only
|
||||
to forward it to the upstream model, is not stored, and is deleted immediately after
|
||||
forwarding. Otherwise, your code is sent <strong>directly</strong>—via client‑to‑provider
|
||||
TLS—to the model you select. Roo Code never stores, inspects, or trains on your code.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Prompts and chat snippets are collected by default</strong> in Roo Code Cloud so you
|
||||
can search and re‑use past conversations. Organization admins can disable this collection at
|
||||
any time.
|
||||
</li>
|
||||
<li>
|
||||
We collect only the data needed to operate Roo Code Cloud, do <strong>not</strong> sell
|
||||
customer data, and do <strong>not</strong> use your content to train models.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">1. Information We Collect</h2>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full border-collapse border border-border">
|
||||
<thead>
|
||||
<tr className="bg-muted/50">
|
||||
<th className="border border-border px-4 py-2 text-left font-semibold">Category</th>
|
||||
<th className="border border-border px-4 py-2 text-left font-semibold">Examples</th>
|
||||
<th className="border border-border px-4 py-2 text-left font-semibold">Source</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-2 font-medium">Account Information</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Name, email, organization, auth tokens
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">You</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-2 font-medium">
|
||||
Workspace Configuration
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Org settings, allow‑lists, rules files, modes, dashboards
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">You / Extension (when signed in)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-2 font-medium">
|
||||
Prompts, Chat Snippets & Token Counts
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Text prompts, model outputs, token counts
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">Extension (when signed in)</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-2 font-medium">Usage Data</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Feature clicks, error logs, performance metrics
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">Services automatically</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-2 font-medium">Payment Data</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Tokenized card details, billing address, invoices
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">Payment processor (Stripe)</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-2 font-medium">Marketing Data</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Cookies, IP address, browser type, page views,{" "}
|
||||
<strong>voluntary form submissions</strong> (e.g., newsletter or wait‑list
|
||||
sign‑ups)
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Marketing Site automatically / You
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">2. How We Use Information</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Operate & secure Roo Code Cloud</strong> (authentication, completions, abuse
|
||||
prevention)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Provide support & improve features</strong> (debugging, analytics, product
|
||||
decisions)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Process payments & manage subscriptions</strong>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Send product updates and roadmap communications</strong> (opt‑out available)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Send onboarding, educational, and promotional communications</strong>. We may use
|
||||
your account information (such as your name and email address) to send you onboarding
|
||||
messages, product tutorials, feature announcements, newsletters, and other marketing
|
||||
communications. You can opt out of non‑transactional emails at any time (see “Your Choices”
|
||||
below).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">3. Where Your Data Goes (And Doesn't)</h2>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full border-collapse border border-border">
|
||||
<thead>
|
||||
<tr className="bg-muted/50">
|
||||
<th className="border border-border px-4 py-2 text-left font-semibold">Data</th>
|
||||
<th className="border border-border px-4 py-2 text-left font-semibold">Sent To</th>
|
||||
<th className="border border-border px-4 py-2 text-left font-semibold">
|
||||
<strong>Not</strong> Sent To
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-2 font-medium">
|
||||
Code & files you work on
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Your chosen model provider (direct client → provider TLS), or Roo Code (proxy
|
||||
mode; transit‑only) when you select Roo Code as the provider
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Roo Code servers (except proxy mode; transit‑only, no storage); ad networks;
|
||||
model‑training pipelines
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-2 font-medium">
|
||||
Prompts, chat snippets & token counts (Cloud)
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Roo Code Cloud (encrypted at rest)
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">Any third‑party</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-2 font-medium">
|
||||
Workspace Configuration
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Roo Code Cloud (encrypted at rest)
|
||||
</td>
|
||||
<td className="border border-border px-4 py-2">Any third-party</td>
|
||||
</tr>
|
||||
<tr className="bg-muted/25">
|
||||
<td className="border border-border px-4 py-2 font-medium">Usage & Telemetry</td>
|
||||
<td className="border border-border px-4 py-2">None</td>
|
||||
<td className="border border-border px-4 py-2">Ad networks or data brokers</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-2 font-medium">Payment Data</td>
|
||||
<td className="border border-border px-4 py-2">Stripe (PCI‑DSS Level 1)</td>
|
||||
<td className="border border-border px-4 py-2">
|
||||
Roo Code servers (we store only the Stripe customer ID)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">4. Data Retention</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Source Code:</strong> Never stored on Roo Code servers.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Prompts & Chat Snippets:</strong> Persist in your Cloud workspace until you or your
|
||||
organization admin deletes them or disables collection.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Operational Logs & Analytics:</strong> Retained only as needed to operate and secure
|
||||
Roo Code Cloud.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">5. Your Choices</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Manage cookies:</strong> You can block or delete cookies in your browser settings;
|
||||
some site features may not function without them.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Disable prompt collection</strong> in Organization settings.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Delete your Cloud account</strong> at any time from{" "}
|
||||
<strong>Security Settings</strong> inside Roo Code Cloud (User Menu → My Settings
|
||||
→ Open Profile).
|
||||
</li>
|
||||
<li>
|
||||
<strong>Marketing communications:</strong> You can unsubscribe from marketing and
|
||||
promotional emails by clicking the unsubscribe link in those emails. Transactional or
|
||||
service‑related emails (such as password resets, billing notices, or security alerts) will
|
||||
continue even if you opt out.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">6. Security Practices</h2>
|
||||
<p>
|
||||
We use TLS for all data in transit, AES‑256 encryption at rest, least‑privilege IAM, continuous
|
||||
monitoring, routine penetration testing, and maintain a SOC 2 program.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">7. Updates to This Policy</h2>
|
||||
<p>
|
||||
If our privacy practices change, we will update this policy and note the new{" "}
|
||||
<strong>Last Updated</strong> date at the top. For material changes that affect Cloud
|
||||
workspaces, we will also email registered workspace owners before the changes take effect.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">8. Contact Us</h2>
|
||||
<p>
|
||||
Questions or concerns? Email{" "}
|
||||
<a href="mailto:privacy@roocode.com" className="text-primary hover:underline">
|
||||
privacy@roocode.com
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import type { MetadataRoute } from "next"
|
||||
import { SEO } from "@/lib/seo"
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: {
|
||||
userAgent: "*",
|
||||
allow: "/",
|
||||
},
|
||||
sitemap: `${SEO.url}/sitemap.xml`,
|
||||
host: SEO.url,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { getGitHubStars, getVSCodeDownloads } from "@/lib/stats"
|
||||
|
||||
import { NavBar, Footer } from "@/components/chromes"
|
||||
|
||||
// Invalidate cache when a request comes in, at most once every hour.
|
||||
export const revalidate = 3600
|
||||
|
||||
export default async function Shell({ children }: { children: React.ReactNode }) {
|
||||
const [stars, downloads] = await Promise.all([getGitHubStars(), getVSCodeDownloads()])
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col bg-background text-foreground">
|
||||
<NavBar stars={stars} downloads={downloads} />
|
||||
<main className="flex-1">{children}</main>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
import type { Metadata } from "next"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
import ReactMarkdown from "react-markdown"
|
||||
import remarkGfm from "remark-gfm"
|
||||
import rehypeRaw from "rehype-raw"
|
||||
|
||||
const TITLE = "Our Terms of Service"
|
||||
const DESCRIPTION =
|
||||
"Terms of Service for Roo Code Cloud. Learn about our service terms, commercial conditions, and legal framework."
|
||||
const OG_DESCRIPTION = ""
|
||||
const PATH = "/terms"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${PATH}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${PATH}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(TITLE, OG_DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: TITLE,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "article",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
|
||||
},
|
||||
keywords: [...SEO.keywords, "terms of service", "legal", "agreement", "subscription"],
|
||||
}
|
||||
|
||||
function getTermsContent() {
|
||||
const filePath = path.join(process.cwd(), "src/app/terms/terms.md")
|
||||
return fs.readFileSync(filePath, "utf8")
|
||||
}
|
||||
|
||||
export default function Terms() {
|
||||
const content = getTermsContent()
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-12 sm:px-6 lg:px-8">
|
||||
<div className="prose prose-lg mx-auto max-w-4xl dark:prose-invert">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
rehypePlugins={[rehypeRaw]}
|
||||
components={{
|
||||
h1: ({ ...props }) => (
|
||||
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl" {...props} />
|
||||
),
|
||||
h2: ({ ...props }) => <h2 className="mt-12 text-2xl font-bold" {...props} />,
|
||||
a: ({ ...props }) => (
|
||||
<a
|
||||
className="text-primary hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
table: ({ ...props }) => (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full border-collapse border border-border" {...props} />
|
||||
</div>
|
||||
),
|
||||
th: ({ ...props }) => (
|
||||
<th
|
||||
className="border border-border px-4 py-2 text-left font-bold bg-muted-foreground/5"
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
td: ({ node: _node, ...props }) => {
|
||||
// Check if this is the first column (Term column)
|
||||
const isTermColumn = _node?.position?.start.column === 1
|
||||
if (isTermColumn) {
|
||||
return <td className="border border-border px-4 py-2 font-medium" {...props} />
|
||||
}
|
||||
return <td className="border border-border px-4 py-2" {...props} />
|
||||
},
|
||||
}}>
|
||||
{content}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,306 +0,0 @@
|
|||
# Roo Code Cloud Terms of Service
|
||||
|
||||
_Last updated: January 9, 2026_
|
||||
|
||||
## 1. Agreement
|
||||
|
||||
These Roo Code Cloud Terms of Service (collectively, including Schedule 1 (Data Processing Addendum), any documents, schedules, annexes, or terms attached hereto or incorporated herein, this "**Agreement**"), dated as of the date you click "Sign Up" or "I agree" or otherwise indicate your assent (the "**Effective Date**"), is entered into by and between Roo Code, Inc. ("**Roo Code**") and you ("**User**" or "**you**"). If you are also entering into this Agreement for or on behalf of the entity that employs or engages you, and/or that you represent or purport to represent ("**Entity**"), you hereby represent that you have the authority to bind and you hereby bind Entity to this Agreement. This is a legally binding contract. Roo Code and User are each referred to in this Agreement as a "**party**" and collectively as the "**parties**". By clicking "Sign Up" or "I agree" or otherwise indicating your assent or by accessing or using any Software (as defined in Section 2), you agree to be bound by this Agreement. In addition, if you are resident in (i) any jurisdiction outside of Europe (as defined below) (including in the U.S.), "Agreement" includes Roo Code's Data Protection Notice (available at [https://roocode.com/privacy](/privacy), the "**Privacy Policy**"); or (ii) European Economic Area, UK, and Switzerland (collectively, "**Europe**"), you hereby acknowledge that you have received a copy of the Privacy Policy. If you are accessing or using any Software for or on behalf of Entity pursuant to or in connection with any other effective agreement between Roo Code and Entity (any such agreement(s), collectively (as applicable), the "**Entity Agreement**"), your access to and use of the Software is also subject to the terms of the Entity Agreement. In the event of any conflict between the terms of the Entity Agreement and the other terms of this Agreement, the terms of the Entity Agreement shall prevail to the extent necessary to resolve such conflict with respect to the subject matter thereof.
|
||||
|
||||
## 2. Limited License
|
||||
|
||||
Subject to the terms of this Agreement, the Privacy Policy, and Roo Code's other applicable user terms, guidelines, and policies (as made available and updated by Roo Code from time to time) and the Entity Agreement (as applicable), Roo Code hereby grants to User a limited, revocable, non-exclusive, non-sublicensable, non-transferable license to use the then-current version of the Roo Code software tool listed in the applicable Order Form (as defined below) ("**Software**"), as made available by Roo Code to User, solely for the purposes described in the applicable Order Form and solely for the duration (during the term of this Agreement) expressly authorized in writing by Roo Code.
|
||||
|
||||
## 3. No Reliance
|
||||
|
||||
User agrees that User is not relying on the delivery of any future functionality or features (or on any oral or written public comments made by or on behalf of Roo Code regarding any future functionality or features) of the Software or any related services.
|
||||
|
||||
## 4. Restrictions
|
||||
|
||||
User shall not (directly or indirectly), and shall not permit any third party to, do or attempt to do any of the following (except as otherwise expressly authorized by Roo Code in writing):
|
||||
|
||||
1. reverse engineer, decompile, disassemble, or otherwise attempt to discover or access the source code or underlying ideas or algorithms of any Software or any other content, code, documentation, or other materials provided or made available through or in connection with, or contained in or embodied by, the Software (collectively, including any portions, copies, modifications, enhancements, derivatives, versions, or embodiments of the Software or any such other materials (in any form or media), "**Software Materials**") unless expressly permitted by law (in which case User shall notify Roo Code of its intention to exercise such rights and provide Roo Code the opportunity to remedy the issue giving rise to such rights so that User does not need to exercise such rights);
|
||||
2. copy, download, export, modify, or translate, or create derivative (or substantially similar) works based on, any Software Materials;
|
||||
3. rent, lease, distribute (or otherwise make available), sell, resell, assign, or otherwise transfer any Software Materials (or any rights related thereto);
|
||||
4. use any Software Materials for timesharing or service bureau purposes or otherwise for the benefit of a third party, or in or for any competitive, discriminatory, abusive, fraudulent, harmful, high-risk, infringing, inappropriate, unlawful, or other unauthorized manner or purpose;
|
||||
5. use any Software Materials to encourage, facilitate, or participate in the circumvention of the intended functionality or use of any Software Materials, or bypass or breach any security device or protection;
|
||||
6. remove any disclaimers, or copyright or other proprietary notices from any Software Materials;
|
||||
7. provide or make available, including via User-submitted prompts, any personal data (or other sensitive information) to Roo Code without Roo Code's express prior written consent in each instance;
|
||||
8. publish or disclose to third parties any evaluation of any Software Materials;
|
||||
9. make any Software Materials available to anyone other than authorized users;
|
||||
10. interfere with or disrupt the integrity or performance of any Software Materials, any Roo Code systems, or any contents thereof; or
|
||||
11. convey, disseminate, or imply any false or misleading information or identity.
|
||||
|
||||
## 5. Use; Fees
|
||||
|
||||
### 5.1 User's and Entity's Responsibilities
|
||||
|
||||
User and the Entity shall:
|
||||
|
||||
1. be solely responsible for the accuracy, truth, completeness, and legality of User Data (as defined in Section 6) and of the means by which User Data was acquired and made available;
|
||||
2. prevent any unauthorized access to or use of any Software Materials, and promptly notify Roo Code of any such unauthorized access or use;
|
||||
3. provide any required or reasonably requested cooperation in connection with the provision or use of the Software; and
|
||||
4. use the Software in accordance with all applicable laws and regulations.
|
||||
|
||||
### 5.2 Third Party Materials
|
||||
|
||||
From time to time, Roo Code may make available (through the Software or otherwise) certain third-party services, data, content, code, products, applications, tools, or other materials (collectively, "**Third Party Materials**"). Any access or use by User of any Third Party Materials, and any exchange of data between User and any third party or Third Party Materials, is solely between User and the applicable non-Roo Code provider.
|
||||
|
||||
### 5.3 Fees
|
||||
|
||||
As applicable, User (or, as applicable, Entity) shall pay Roo Code (or Roo Code's designated payment vendor) any amounts listed or described in any Roo Code-provided or Roo Code-approved purchasing or ordering document or procedure (each, an "**Order Form**") in accordance with the terms of this Agreement (including such Order Form, which is incorporated herein by reference). Unless otherwise stated in such Order Form, all fees, as applicable:
|
||||
|
||||
1. are non-refundable,
|
||||
2. are due in advance, and
|
||||
3. exclude any applicable taxes.
|
||||
|
||||
At Roo Code's option, in its sole discretion, the outstanding balance of any payment not received by the due date shall accrue interest (except with respect to charges then under reasonable and good faith dispute) at one and a half percent (1.5%) per month (or, if lower, the maximum rate permitted by applicable law) from the date such payment is due until the date paid. User (or, as applicable, Entity) shall also pay all costs incurred (including reasonable legal fees) in collecting overdue payments. With respect to any User payment obligation, User hereby authorizes Roo Code to, without prior notice and without any further approval, deduct such amounts from any prepaid or outstanding balance or to charge, debit, or otherwise obtain such amounts from any designated payment method, as applicable.
|
||||
|
||||
### 5.4 Credits
|
||||
|
||||
If you purchase, earn, or receive, or you are eligible for, any credits, tokens, rewards, points, or other similar items related to use of the Software or any related services (e.g., compute credits), all of the foregoing shall be subject to the terms of Roo Code's applicable policies (e.g., Roo Code's Compute Credit Policy). Unless otherwise stated in the applicable Roo Code policy or required by applicable law, any such credits or other items will automatically expire (without any refund) upon termination of this Agreement (or the applicable Order Form).
|
||||
|
||||
## 6. Ownership; Data
|
||||
|
||||
### 6.1 Software Materials
|
||||
|
||||
User acknowledges that, as between Roo Code, on the one hand, and User and Entity, on the other hand, all rights, title, and interests in and to the Software Materials, including all related intellectual property rights, belong to and are retained solely by Roo Code (or Roo Code's third-party licensors and suppliers, as applicable). Roo Code reserves all rights not expressly granted under this Agreement. If, for any reason, User or Entity acquires any rights, title, or interest in or to any of the Software Materials by virtue of this Agreement or otherwise (other than the limited license rights expressly granted in Section 2), User (on behalf of itself and Entity) agrees to assign, and does hereby irrevocably assign, any and all such rights, title, and interest to Roo Code.
|
||||
|
||||
### 6.2 Derived Data
|
||||
|
||||
User acknowledges and agrees that Roo Code shall have the right to generate any non-personally and non-User identifiable data, insights, or other information resulting from or related to User's use of the Software to the extent such information does not constitute User Data ("**Derived Data**"). Subject to the Privacy Policy and applicable law, Derived Data may be collected and used by Roo Code for any business purpose (including to improve and train the Software), provided that Derived Data is disclosed to third parties only in aggregated or anonymized form.
|
||||
|
||||
### 6.3 User Data
|
||||
|
||||
"**User Data**" means data that is provided by User, and is processed, via the Software. "**GDPR**" means, collectively, the EU General Data Protection Regulation, UK General Data Protection Regulation, UK Data Protection Act 2018, and other data protection and e-privacy laws in Europe (including laws of the member states of the European Economic Area).
|
||||
|
||||
To the extent that the processing of User Data is not subject to the GDPR, User (on behalf of itself and Entity) hereby grants to Roo Code the non-exclusive right to use (and for Roo Code's subcontractors to use on its behalf) User Data, in accordance with the Privacy Policy and this Agreement, to offer, provide, maintain, support, train, monitor, or improve the Software (or Roo Code's related technology) or to provide User or Entity with information that might be relevant in connection with this Agreement.
|
||||
|
||||
To the extent that the processing of User Data is subject to the GDPR, User hereby acknowledges that Roo Code (and Roo Code's subcontractors on Roo Code's behalf) may use and otherwise process User Data, in accordance with the Privacy Policy, including to offer, provide, maintain, support, train, monitor, or improve the Software (or Roo Code's related technology) or to provide User with information that might be relevant in connection with this Agreement.
|
||||
|
||||
### 6.4 Feedback
|
||||
|
||||
User (on behalf of itself and Entity) hereby grants Roo Code a royalty-free, worldwide, transferable, sublicenseable, irrevocable, perpetual license to use or incorporate into the Software (or any other Roo Code products, applications, or services) any suggestions, enhancement requests, recommendations or other feedback provided by User. Notwithstanding anything to the contrary in this Agreement, Roo Code (and its affiliates) may use, for any lawful purpose, any information (of a general nature or that has general potential applications) that is retained in the unaided memories of Roo Code's (or any of its affiliates') employees or contractors.
|
||||
|
||||
## 7. Warranties
|
||||
|
||||
### 7.1 Warranties by Roo Code
|
||||
|
||||
Subject to the terms of this Agreement, Roo Code represents and warrants to User that it:
|
||||
|
||||
1. has the full corporate rights, power and authority to enter into this Agreement and to perform the acts required of it hereunder; and
|
||||
2. will not violate any applicable law or regulation in the performance of its obligations under this Agreement.
|
||||
|
||||
### 7.2 Warranties by User
|
||||
|
||||
User represents and warrants to Roo Code that:
|
||||
|
||||
1. User has the full corporate rights, power and authority to enter into this Agreement and to perform the acts required of it hereunder;
|
||||
2. User will not violate any applicable law, regulation, or privacy policy in connection with its use of the Software (or any other Software Materials) or its performance under this Agreement; and
|
||||
3. User has all rights, consents and approvals necessary to provide the User Data to Roo Code (and for Roo Code to use the User Data as permitted or contemplated under this Agreement), and the User Data is accurate, true, not misleading, lawfully obtained, complete, and does not and will not violate any law, regulation, or third-party rights.
|
||||
|
||||
### 7.3 Beta Services
|
||||
|
||||
If User obtains free, alpha, beta, or trial access to any Services or features (collectively, "**Beta Services**"), the applicable provisions of this Agreement will also govern such Beta Services. Any Beta Services are provided on an "AS IS" AND WITH ALL FAULTS basis; User assumes all risks associated with, and Roo Code shall not have any liability arising from or related to, any Beta Services. Additional terms and conditions for Beta Services may appear on Roo Code's website or the Software, and any such additional terms and conditions are incorporated into this Agreement by reference.
|
||||
|
||||
## 8. Term
|
||||
|
||||
This Agreement begins on the Effective Date and shall continue until terminated in accordance with this Agreement. Subject to earlier termination in accordance with this Agreement, the term of each Order Form is as set forth therein.
|
||||
|
||||
## 9. Termination
|
||||
|
||||
### 9.1 Termination
|
||||
|
||||
Either party may terminate this Agreement (or any Order Form) upon written notice.
|
||||
|
||||
### 9.2 Suspension
|
||||
|
||||
Without limiting Roo Code's termination rights under this Agreement, Roo Code may suspend or terminate access to any Software (or block, delete, or remove any User Data), at its sole option, with or without notice to User if Roo Code reasonably determines or suspects that:
|
||||
|
||||
1. User has breached this Agreement or the Entity Agreement, or
|
||||
2. continued access would, or is reasonably likely to, result in a violation of Section 4, security, applicable law, or any intellectual property, privacy, property or other rights.
|
||||
|
||||
### 9.3 Effect of Termination
|
||||
|
||||
Roo Code shall not be liable to User or any third party for any suspension or termination of User's access to, or right to use, the Software or any related services. Upon termination of this Agreement, User's access to and use of the Software (and any related services) shall automatically and immediately terminate. Sections 4, 5, 6, 7, 9.3 and 10-14 of this Agreement shall survive the termination of this Agreement. For clarity, if User is subject to any minimum subscription period under an Order Form, User shall pay (or, if prepaid, Roo Code may retain) all fees corresponding to such committed period, notwithstanding any termination of this Agreement or such Order Form.
|
||||
|
||||
## 10. Confidentiality
|
||||
|
||||
### 10.1 Obligations
|
||||
|
||||
Each party (on behalf of itself and Entity) agrees to maintain in confidence any proprietary or non-public information disclosed or made available by the other party in connection with this Agreement, whether written or otherwise, that a party knows or reasonably should know is considered confidential by the disclosing party ("**Confidential Information**"). Roo Code's Confidential Information includes any non-public information constituting, associated with, embedded in, or copied, derived, received, downloaded, or otherwise obtained from any Software Materials (and any portions, copies, modifications, enhancements, versions, summaries, embodiments, or derivatives of any of the foregoing, in any form or media). Confidential Information shall also include any output (including questions and responses, whether voice, text or otherwise) provided by the Software to User. Each party shall not disclose to any third party or use any Confidential Information of the other party, except to perform its obligations or exercise its express rights under this Agreement and shall take appropriate measures to preserve and protect such Confidential Information and the disclosing party's rights therein, at all times exercising at least a reasonable, diligent level of care. Upon termination of this Agreement, and as otherwise requested by the disclosing party, the receiving party shall promptly return or destroy (at the disclosing party's option), all copies of Confidential Information except to the extent that the receiving party is permitted under applicable laws to retain personal data relating to it.
|
||||
|
||||
### 10.2 Required Disclosures
|
||||
|
||||
A disclosure of Confidential Information that is legally compelled to be disclosed pursuant to a subpoena, summons, order or other judicial or governmental process shall not be considered a breach of this Agreement; provided the receiving party:
|
||||
|
||||
1. except to the extent expressly prohibited under applicable law, provides prompt notice of and reasonable cooperation in connection with any such subpoena, order, or the like to the disclosing party so that the disclosing party will have the opportunity to obtain a protective order or otherwise oppose or limit the disclosure; and
|
||||
2. to the maximum extent permitted by applicable law, minimizes and obtains confidential treatment of such disclosure.
|
||||
|
||||
## 11. Warranty Disclaimer
|
||||
|
||||
EXCEPT AS EXPRESSLY PROVIDED IN THIS AGREEMENT AND TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, ALL SOFTWARE MATERIALS AND RELATED SERVICES ARE PROVIDED "AS IS AND AS AVAILABLE," AND, TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, ROO CODE AND ITS THIRD-PARTY LICENSORS MAKE NO (AND HEREBY DISCLAIM ALL) OTHER WARRANTIES OF ANY KIND, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE, WITH RESPECT TO ANY ACCESS, USE, AVAILABILITY, QUALITY, INTEGRITY, FAIRNESS, ACCURACY, OR RESULTS OF THE SOFTWARE (IN WHOLE OR IN PART), ANY THIRD PARTY MATERIALS, OR ANY OTHER PRODUCTS, CONTENT, OR SERVICES PROVIDED TO USER BY ROO CODE, OR OTHERWISE UNDER THIS AGREEMENT. WITHOUT LIMITING THE FOREGOING, ROO CODE DOES NOT WARRANT THAT ALL ERRORS CAN OR WILL BE CORRECTED, OR THAT USE OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR FREE. ROO CODE DOES NOT PROVIDE ANY LEGAL (OR OTHER PROFESSIONAL) ADVICE, AND USER SHOULD NOT RELY ON ANY SOFTWARE MATERIALS WHEN MAKING (OR ADVISING WITH RESPECT TO) ANY PERSONAL OR PROFESSIONAL DECISIONS. ROO CODE IS NOT RESPONSIBLE FOR, AND DOES NOT ENDORSE, ANY COMMUNICATIONS OR CONTENT SUBMITTED BY, OR SHARED AMONG, ANY USERS OF THE SOFTWARE. USER UNDERSTANDS AND AGREES THAT OUTPUTS MAY BE GENERATED THROUGH ARTIFICIAL INTELLIGENCE AND RELATED TECHNOLOGIES AND MAY BE SYNTHETIC IN NATURE. OUTPUTS MAY CONTAIN INACCURACIES AND SHOULD NOT BE RELIED UPON AS FACTUAL OR AUTHENTIC STATEMENTS OF ANY PERSON.
|
||||
|
||||
## 12. Indemnification
|
||||
|
||||
### 12.1 By User
|
||||
|
||||
User and/or Entity, as applicable, shall defend, indemnify and hold harmless Roo Code, its affiliates, and its and their respective directors, officers, successors, assigns, employees, third-party licensors, representatives, and agents from and against any third party claim, suit or action and all resulting losses, damages, expenses, fines, penalties or costs (including reasonable attorneys' fees) arising from or relating to:
|
||||
|
||||
1. any User Data;
|
||||
2. any breach by User of this Agreement; or
|
||||
3. any gross negligence, willful misconduct, or violation of law by User or Entity.
|
||||
|
||||
User and/or Entity, as applicable, shall pay any liability or settlement arising from any such claim or suit. User and/or Entity shall not, however, be responsible for claims to the extent arising solely from the unauthorized access, alteration, or misuse of User Data or outputs by a third party without User's knowledge or reasonable control. User and/or Entity shall be fully responsible and liable for all acts and omissions through User's account as if User directly engaged in such conduct.
|
||||
|
||||
### 12.2 By Roo Code
|
||||
|
||||
Roo Code shall indemnify, defend, and hold harmless User against any third-party claim or suit to the extent based on a claim that the Software (excluding any Third Party Materials), as provided by Roo Code to User, violates, infringes, or misappropriates any United States patent, copyright, or trade secret, and Roo Code shall pay any liability or settlement arising from such proceeding, provided that:
|
||||
|
||||
1. Roo Code is promptly notified in writing of such claim or suit;
|
||||
2. Roo Code or its designee has sole control of such defense or settlement;
|
||||
3. User gives all information and assistance requested by Roo Code or such designee; and
|
||||
4. such claim does not result from any unauthorized access, use, modification, or combination of any Software Materials or from any User Data.
|
||||
|
||||
To the extent that use of the Software is enjoined, Roo Code may at its option: (a) procure for User the right to use the Software; (b) replace the Software with a similar service; or (c) terminate this Agreement. Roo Code shall have no liability under this Section 12.2 or otherwise to the extent a claim or suit results from any negligence, willful misconduct, or breach of this Agreement by or on behalf of User or Entity or is covered by User's and Entity's indemnification obligations under Section 12.1. THIS SECTION 12.2 STATES ROO CODE'S ENTIRE LIABILITY AND USER'S AND ENTITY'S SOLE AND EXCLUSIVE REMEDY FOR ANY INFRINGEMENT CLAIMS RELATED TO ANY SOFTWARE MATERIALS OR RELATED SERVICES.
|
||||
|
||||
### 12.3 Indemnification Procedure
|
||||
|
||||
The indemnifying party will give prompt written notice of any indemnifiable claim hereunder. The indemnifying party may control the defense and settlement thereof, provided that it does so diligently and it does not enter into any settlement that imposes material non-monetary obligations on the indemnified party without the indemnified party's prior written consent, which consent shall not unreasonably be withheld. The indemnified party will reasonably cooperate in such defense and settlement at the indemnifying party's request and expense, and the indemnified party may participate at its own expense using its own counsel.
|
||||
|
||||
## 13. Limitations of Liability
|
||||
|
||||
### 13.1 Limitation on Direct Damages
|
||||
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL ROO CODE'S, ITS AFFILIATES' AND ITS THIRD-PARTY LICENSORS' TOTAL AGGREGATE LIABILITY, IF ANY, ARISING OUT OF OR IN ANY WAY RELATED TO THIS AGREEMENT EXCEED THE GREATER OF $100 USD OR THE FEES PAID BY YOU TO ROO CODE UNDER THIS AGREEMENT DURING THE TWELVE MONTH PERIOD PRECEDING THE EVENT GIVING RISE TO THE LIABILITY, REGARDLESS OF THE NATURE OF THE CLAIM OR WHETHER SUCH DAMAGES WERE FORESEEABLE.
|
||||
|
||||
### 13.2 Waiver of Consequential Damages
|
||||
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL ROO CODE OR ANY OF ITS AFFILIATES OR THIRD-PARTY LICENSORS BE LIABLE UNDER OR IN CONNECTION WITH THIS AGREEMENT FOR ANY INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR FOR ANY LOSS OR COMPROMISE OF DATA, LOSS OF AVAILABILITY OF DATA, GOODWILL, OPPORTUNITY, REVENUE OR PROFITS, REGARDLESS OF THE NATURE OF THE CLAIM OR WHETHER SUCH DAMAGES WERE FORESEEABLE.
|
||||
|
||||
## 14. General
|
||||
|
||||
### 14.1 Relationship
|
||||
|
||||
The parties to this Agreement are independent, and no agency, partnership franchise, joint venture or employee-employer relationship is intended or created by this Agreement. Roo Code may identify User (e.g., name and logo) in marketing materials unless User provides Roo Code with written notice that User is opting out of such permission.
|
||||
|
||||
### 14.2 Notices
|
||||
|
||||
Except as otherwise set forth in this Agreement, all notices to a party shall be in writing and sent to, for Roo Code: [support@roocode.com](mailto:support@roocode.com), and for User the applicable address or email address associated with User's account (which addresses may be updated by such party from time to time by written notice). Notice shall be deemed to have been duly given when received, if personally delivered; when receipt is electronically confirmed, if transmitted by email; the day after it is sent, if sent for next day delivery by recognized overnight delivery service; and upon receipt, if sent by certified or registered mail, return receipt requested. Any notices to User may be sent by email to the email address associated with User's account or may be posted in the Software, and any such notices shall be effective when delivered in accordance with the foregoing. User hereby consents to receiving notices and communications from Roo Code electronically.
|
||||
|
||||
### 14.3 Assignment
|
||||
|
||||
This Agreement may not be assigned or transferred by User without Roo Code's prior written consent. Any assignment in derogation of the foregoing is null and void. Roo Code may (i) subcontract any of its obligations or responsibilities under this Agreement, or (ii) assign or transfer this Agreement to an affiliate or in connection with a merger, acquisition, reorganization, sale of all or substantially all of its equity or assets to which this Agreement relates, or other similar corporate transaction. This Agreement shall inure to the benefit of each party's successors and permitted assigns.
|
||||
|
||||
### 14.4 Entire Agreement; Amendment
|
||||
|
||||
This Agreement, including any other documents attached hereto or otherwise incorporated herein, constitutes the entire agreement between the parties and supersedes all prior or contemporaneous agreements and understandings regarding the subject matter hereof and Roo Code, User and Entity have not relied on any representation or statement not set out in this Agreement. To the maximum extent permitted under applicable law, from time to time, in Roo Code's sole discretion, Roo Code may amend the terms of this Agreement. Such changes will become effective upon the date specified by Roo Code. By continuing to receive, use or access any Software, User agrees to be bound by the amended terms of this Agreement. No other change of any of the provisions hereof shall be effective unless and until set forth in writing and duly signed by an officer of Roo Code and by User.
|
||||
|
||||
### 14.5 No Third-Party Benefits
|
||||
|
||||
A person who is not a party to this Agreement shall have no rights under the UK Contracts (Rights of Third Parties) Act 1999 or otherwise to enforce any term of this Agreement.
|
||||
|
||||
### 14.6 Age Restrictions
|
||||
|
||||
The Software is not intended for use by individuals under the age of thirteen (13). By accessing or using the Software, User represents that User is at least thirteen (13) years of age, and if under eighteen (18), that User has the consent of a parent or legal guardian.
|
||||
|
||||
### 14.7 Governing Law; Venue
|
||||
|
||||
This Agreement (including this provision) shall be governed by and construed in accordance with the laws of Delaware, without reference to conflict of law principles. Except as otherwise expressly set forth in this Agreement, with respect to any dispute or claim (including non-contractual disputes or claims) arising out of or in connection with this Agreement or its subject matter or formation, each party hereby irrevocably submits to the exclusive jurisdiction of the courts located in Delaware. Notwithstanding anything to the contrary in this Agreement, Roo Code may seek preliminary equitable relief in any court of competent jurisdiction in connection with any actual or threatened breach of Sections 4 or 10.
|
||||
|
||||
### 14.8 No Waiver
|
||||
|
||||
The failure to insist upon strict compliance with any of the provisions of this Agreement shall not be deemed a waiver of any such provision, nor shall any waiver or relinquishment of any right or power hereunder, at any one or more times, be deemed a waiver or relinquishment of such right or power at any other time or times.
|
||||
|
||||
### 14.9 Severability; Interpretation
|
||||
|
||||
Any provision of this Agreement held to be unenforceable shall be enforced to the maximum extent permitted by applicable law and shall not affect the enforceability of any other provisions of this Agreement. Any rule of construction or interpretation otherwise requiring this Agreement to be construed or interpreted against any party by virtue of the authorship of this Agreement shall not apply to the construction and interpretation of this Agreement. The word "including" shall not be limiting in this Agreement. The parties acknowledge that this Agreement and Roo Code's provision of its services are not subject to the EU Data Act.
|
||||
|
||||
### 14.10 Force Majeure
|
||||
|
||||
Roo Code shall not be in breach or liable for its delay or failure in performing any obligation under this Agreement to the extent resulting from any events or circumstances beyond Roo Code's reasonable control, including acts of God, delay or failure in performance by User, civil commotion, war, strikes, epidemics, Internet service interruptions or slowdowns, vandalism or "hacker" attacks, acts of terrorism, or governmental actions.
|
||||
|
||||
---
|
||||
|
||||
## Schedule 1 - Data Processing Addendum
|
||||
|
||||
This Data Processing Addendum ("**Addendum**") is supplemental to, and forms part of, the Agreement between Roo Code and the Entity. To the extent that there is any inconsistency between the Agreement and this Addendum, the latter shall prevail. This Addendum is only applicable to the extent that Roo Code's processing of the Data (as defined below) is subject to the GDPR.
|
||||
|
||||
### 1. Definitions
|
||||
|
||||
In this Addendum, the following terms shall have the following meanings:
|
||||
|
||||
The words "**controller**", "**criminal convictions and offences data**", "**processor**", "**data subject**", "**personal data**", "**personal data breach**", "**processing**" (and "**process**"), and "**special category personal data**" shall have the meanings given to each in the GDPR.
|
||||
|
||||
"**Security Incident**" means a confirmed personal data breach occurring with respect to the Data processed by Roo Code.
|
||||
|
||||
### 2. Relationship of the Parties
|
||||
|
||||
1. Entity is the controller of, and Roo Code is the processor of, the personal data to be processed for the purposes of the Agreement relating to any person resident in Europe (such data, the "**Data**").
|
||||
2. Each party shall comply with its obligations under the GDPR.
|
||||
3. Entity shall be liable for Roo Code's fees and costs arising from clauses 9-12 below except to the extent these were incurred as a result of Roo Code's breach of this Addendum.
|
||||
|
||||
### 3. Personal Data Types
|
||||
|
||||
Entity:
|
||||
|
||||
1. shall undertake reasonable efforts to ensure that Roo Code is not provided with, and does not otherwise process, any Data considered to be special category personal data, or criminal convictions and offences data under or in connection with this Agreement; and
|
||||
2. acknowledges that Roo Code will perform its obligations assuming that such personal data does not form part of the Data.
|
||||
|
||||
The following describes the subject matter, duration, nature and purpose of Roo Code's Data processing on behalf of Entity:
|
||||
|
||||
- **Subject matter of processing:** For the purposes of the Agreement.
|
||||
- **Duration of processing:** For the duration of the Agreement.
|
||||
- **Nature of processing:** The personal data will be subject to basic processing activities of registration, storage and use for the purposes of the Agreement.
|
||||
- **Personal data categories:** The personal data to be processed concerns the following categories of data: name and other contact and credential information (e.g. email address, work address, phone numbers, external access credentials, and social media handles).
|
||||
- **Data subject types:** Personnel at the Entity
|
||||
|
||||
### 4. Purpose Limitation
|
||||
|
||||
Roo Code shall process the Data as a processor:
|
||||
|
||||
1. to the extent necessary to perform its obligations under the Agreement; and
|
||||
2. in accordance with the documented instructions of Entity, as set out in the Agreement, except where otherwise required by any European law (including any EEA member state law) applicable to Roo Code.
|
||||
|
||||
### 5. International Data Transfers
|
||||
|
||||
Entity acknowledges and agrees that Roo Code may in accordance with the GDPR transfer, and/or allow the transfer of, the Data outside of Europe to other jurisdictions (including to the United States) including jurisdictions which may be regarded by the European Commission and/or the UK as providing an inadequate level of data protection.
|
||||
|
||||
### 6. Confidentiality of Processing
|
||||
|
||||
Roo Code shall ensure that any person that it authorises to process the Data (including Roo Code's staff, agents and subcontractors) shall be subject to a requisite duty of confidentiality (whether a contractual, statutory, or otherwise).
|
||||
|
||||
### 7. Security
|
||||
|
||||
Roo Code shall implement and maintain appropriate technical and organisational measures to protect the Data in accordance with the GDPR. Such measures shall have regard to the state of the art, the costs of implementation and the nature, scope, context and purposes of processing as well as the risk of varying likelihood and severity for the rights and freedoms of natural persons.
|
||||
|
||||
### 8. Subprocessing
|
||||
|
||||
1. Entity hereby grants Roo Code general written authorisation to engage sub-processors to process the Data, including (a) Roo Code's affiliates; and (b) any other subprocessors engaged as of the date of this Addendum.
|
||||
2. To the extent that Roo Code is required to do so under the GDPR, Roo Code shall notify Entity of any proposed engagement or replacement of sub-processors at least 10 days prior to its effective date (which notice may, at Roo Code's option, be provided on Roo Code's website or through any other effective mechanism). Entity may object in writing to such proposed appointment or replacement on demonstrated and valid data protection grounds no later than 7 days of Roo Code's notice; provided that if Roo Code does not agree with Entity's objections, Entity may upon prior written notice to Roo Code terminate the relevant part of the services in accordance with the Agreement.
|
||||
3. To the extent that Roo Code is required to do so under the GDPR, Roo Code shall undertake reasonable efforts to agree data protection terms with any such subprocessor engaged following the date of this Agreement such that the Data is protected materially to the same extent as the protections afforded to the Data under this Addendum.
|
||||
|
||||
### 9. Cooperation and Data Subjects' Rights
|
||||
|
||||
To the extent required under the GDPR, Roo Code shall reasonably assist Entity:
|
||||
|
||||
1. in responding to request from data subjects in Europe to exercise her/his rights under the GDPR (including rights of access, correction, objection, erasure and data portability, as applicable); and
|
||||
2. Entity to comply with Entity's obligations under the GDPR relating to (a) personal data breach notifications, and (b) impact assessments and related prior consultations with supervisory authorities, in each case, to the extent relating to Roo Code's processing of the Data.
|
||||
|
||||
If any such data subject request relating to the Data is submitted directly to Roo Code, Roo Code shall without undue delay inform Entity of the same.
|
||||
|
||||
### 10. Security Incidents
|
||||
|
||||
Upon becoming aware of a Security Incident, Roo Code shall inform Entity without undue delay.
|
||||
|
||||
### 11. Deletion or Return of Data
|
||||
|
||||
To the extent required under the GDPR, upon termination or expiry of the Agreement, Roo Code shall at Entity's request (which request must be exercised promptly) either:
|
||||
|
||||
1. return to Entity, and/or
|
||||
2. destroy or permanently erase,
|
||||
|
||||
in each case, all Data in its possession or control; provided that Roo Code shall be excused from its obligations under (ii) above to the extent required or allowed by applicable law.
|
||||
|
||||
### 12. Audit
|
||||
|
||||
To the extent required under the GDPR, Roo Code shall permit Entity (or a third party auditor engaged by the Entity and which is subject to an appropriate confidentiality agreement with Roo Code) to audit Roo Code's compliance with this Addendum by making available to Entity reasonable information relating to Roo Code's processing of the Data, in each case, to the extent reasonably necessary for Entity to assess such compliance. Entity may not exercise such audit rights more than once in any twelve (12) calendar month period.
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import React, { useState, useEffect } from "react"
|
||||
import ReactCookieConsent from "react-cookie-consent"
|
||||
import { Cookie } from "lucide-react"
|
||||
import { getDomain } from "tldts"
|
||||
import { CONSENT_COOKIE_NAME } from "@roo-code/types"
|
||||
import { handleConsentAccept, handleConsentReject } from "@/lib/analytics/consent-manager"
|
||||
|
||||
/**
|
||||
* GDPR-compliant cookie consent banner component
|
||||
* Handles both the UI and consent event dispatching
|
||||
*/
|
||||
export function CookieConsentWrapper() {
|
||||
const [cookieDomain, setCookieDomain] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// Get the appropriate domain using tldts
|
||||
if (typeof window !== "undefined") {
|
||||
const domain = getDomain(window.location.hostname)
|
||||
setCookieDomain(domain)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleAccept = () => {
|
||||
handleConsentAccept()
|
||||
}
|
||||
|
||||
const handleDecline = () => {
|
||||
handleConsentReject()
|
||||
}
|
||||
|
||||
const extraCookieOptions = cookieDomain
|
||||
? {
|
||||
domain: cookieDomain,
|
||||
}
|
||||
: {}
|
||||
|
||||
const containerClasses = `
|
||||
fixed bottom-2 left-2 right-2 z-[999]
|
||||
bg-black/95 dark:bg-white/95
|
||||
text-white dark:text-black
|
||||
border-t-neutral-800 dark:border-t-gray-200
|
||||
backdrop-blur-xl
|
||||
border-t
|
||||
font-semibold
|
||||
rounded-t-lg
|
||||
px-4 py-4 md:px-8 md:py-4
|
||||
flex flex-wrap items-center justify-between gap-4
|
||||
text-sm font-sans
|
||||
`.trim()
|
||||
|
||||
const buttonWrapperClasses = `
|
||||
flex
|
||||
flex-row-reverse
|
||||
items-center
|
||||
gap-2
|
||||
`.trim()
|
||||
|
||||
const acceptButtonClasses = `
|
||||
bg-white text-black border-neutral-800
|
||||
dark:bg-black dark:text-white dark:border-gray-200
|
||||
hover:opacity-50
|
||||
transition-opacity
|
||||
rounded-md
|
||||
px-4 py-2 mr-2
|
||||
text-sm font-bold
|
||||
cursor-pointer
|
||||
focus:outline-none focus:ring-2 focus:ring-offset-2
|
||||
`.trim()
|
||||
|
||||
const declineButtonClasses = `
|
||||
dark:bg-white dark:text-black dark:border-gray-200
|
||||
bg-black text-white border-neutral-800
|
||||
hover:opacity-50
|
||||
border border-border
|
||||
transition-opacity
|
||||
rounded-md
|
||||
px-4 py-2
|
||||
text-sm font-bold
|
||||
cursor-pointer
|
||||
focus:outline-none focus:ring-2 focus:ring-offset-2
|
||||
`.trim()
|
||||
|
||||
return (
|
||||
<div role="banner" aria-label="Cookie consent banner" aria-live="polite">
|
||||
<ReactCookieConsent
|
||||
location="bottom"
|
||||
buttonText="Accept"
|
||||
declineButtonText="Decline"
|
||||
cookieName={CONSENT_COOKIE_NAME}
|
||||
expires={365}
|
||||
enableDeclineButton={true}
|
||||
onAccept={handleAccept}
|
||||
onDecline={handleDecline}
|
||||
containerClasses={containerClasses}
|
||||
buttonClasses={acceptButtonClasses}
|
||||
buttonWrapperClasses={buttonWrapperClasses}
|
||||
declineButtonClasses={declineButtonClasses}
|
||||
extraCookieOptions={extraCookieOptions}
|
||||
disableStyles={true}
|
||||
ariaAcceptLabel={`Accept`}
|
||||
ariaDeclineLabel={`Decline`}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Cookie className="size-5 hidden md:block" />
|
||||
<span>Like most of the internet, we use cookies. Are you OK with that?</span>
|
||||
</div>
|
||||
</ReactCookieConsent>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import Image from "next/image"
|
||||
import { DM_Sans } from "next/font/google"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
|
||||
const dmSans = DM_Sans({
|
||||
subsets: ["latin"],
|
||||
weight: ["500", "700", "800"],
|
||||
})
|
||||
|
||||
export function RoomoteAnnouncementBanner() {
|
||||
return (
|
||||
<div className={`relative overflow-hidden bg-[#d8f14b] text-black ${dmSans.className}`}>
|
||||
<div className="relative flex flex-col md:flex-row items-center justify-center gap-3 px-6 py-8 md:py-10 border-b-2 border-black">
|
||||
<p className="text-base sm:text-lg md:text-xl font-extrabold tracking-tight">
|
||||
The Roo Code team has something new.
|
||||
</p>
|
||||
<a
|
||||
href="https://roomote.dev"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="group inline-flex shrink-0 items-center gap-2 rounded-full bg-black text-white px-6 py-2.5 text-sm sm:text-base font-bold hover:bg-gray-900 transition-colors duration-200">
|
||||
Check out
|
||||
<Image
|
||||
src="/logos/roomote-logo.png"
|
||||
alt="Roomote"
|
||||
width={100}
|
||||
height={37}
|
||||
className="h-5 sm:h-6 w-auto invert"
|
||||
/>
|
||||
<ArrowRight className="size-4 sm:size-5 transition-transform duration-200 group-hover:translate-x-0.5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import ReactMarkdown from "react-markdown"
|
||||
import remarkGfm from "remark-gfm"
|
||||
|
||||
interface BlogContentProps {
|
||||
/** The markdown content to render */
|
||||
content: string
|
||||
}
|
||||
|
||||
/**
|
||||
* BlogContent component
|
||||
*
|
||||
* Renders markdown content with site-specific typography and link behavior.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <BlogContent content={markdownString} />
|
||||
* ```
|
||||
*/
|
||||
export function BlogContent({ content }: BlogContentProps) {
|
||||
return (
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
// Custom heading styles - note: h1 in content becomes h2 to preserve single H1
|
||||
h1: ({ node: _node, ...props }) => <h2 className="mt-12 text-2xl font-bold" {...props} />,
|
||||
h2: ({ node: _node, ...props }) => <h2 className="mt-12 text-2xl font-bold" {...props} />,
|
||||
h3: ({ node: _node, ...props }) => <h3 className="mt-8 text-xl font-semibold" {...props} />,
|
||||
// Regular external links open in a new tab.
|
||||
a: ({ href, children }) => {
|
||||
return (
|
||||
<a className="text-primary hover:underline" target="_blank" rel="noopener noreferrer" href={href}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
},
|
||||
// Styled blockquotes
|
||||
blockquote: ({ ...props }) => {
|
||||
return (
|
||||
<blockquote
|
||||
className={[
|
||||
// Opt out of Tailwind Typography's automatic quote marks for blockquotes.
|
||||
"not-prose my-6 border-l-4 border-primary pl-4 text-muted-foreground",
|
||||
// Normalize paragraph spacing inside blockquotes regardless of our global <p> renderer.
|
||||
"[&>p]:m-0 [&>p+ p]:mt-4",
|
||||
"italic",
|
||||
].join(" ")}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
},
|
||||
// Code blocks
|
||||
code: ({ className, children, node: _node, ...props }) => {
|
||||
const isInline = !className
|
||||
if (isInline) {
|
||||
return (
|
||||
<code className="rounded bg-muted px-1.5 py-0.5 text-sm" {...props}>
|
||||
{children}
|
||||
</code>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<code className={className} {...props}>
|
||||
{children}
|
||||
</code>
|
||||
)
|
||||
},
|
||||
// Strong text
|
||||
strong: ({ node: _node, ...props }) => <strong className="font-semibold" {...props} />,
|
||||
// Paragraphs
|
||||
p: ({ node: _node, ...props }) => <p className="leading-7 [&:not(:first-child)]:mt-6" {...props} />,
|
||||
// Lists
|
||||
ul: ({ node: _node, ...props }) => <ul className="my-6 ml-6 list-disc [&>li]:mt-2" {...props} />,
|
||||
ol: ({ node: _node, ...props }) => <ol className="my-6 ml-6 list-decimal [&>li]:mt-2" {...props} />,
|
||||
// Tables with zebra striping (visible in both light and dark mode)
|
||||
table: ({ node: _node, ...props }) => (
|
||||
<div className="not-prose my-6 w-full overflow-x-auto rounded-lg border border-border">
|
||||
<table className="w-full border-collapse text-sm" {...props} />
|
||||
</div>
|
||||
),
|
||||
thead: ({ node: _node, ...props }) => <thead className="bg-muted" {...props} />,
|
||||
tbody: ({ node: _node, ...props }) => <tbody {...props} />,
|
||||
tr: ({ node: _node, ...props }) => (
|
||||
<tr
|
||||
className="border-b border-border last:border-b-0 transition-colors even:bg-muted/70 hover:bg-muted"
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
th: ({ node: _node, ...props }) => (
|
||||
<th className="px-4 py-3 text-left font-semibold text-foreground" {...props} />
|
||||
),
|
||||
td: ({ node: _node, ...props }) => <td className="px-4 py-3" {...props} />,
|
||||
}}>
|
||||
{content}
|
||||
</ReactMarkdown>
|
||||
)
|
||||
}
|
||||
|
||||
export default BlogContent
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { ChevronDown } from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface FAQItem {
|
||||
question: string
|
||||
answer: string
|
||||
}
|
||||
|
||||
interface BlogFAQProps {
|
||||
items: FAQItem[]
|
||||
}
|
||||
|
||||
/**
|
||||
* BlogFAQ - Accordion-style FAQ section for blog posts
|
||||
*
|
||||
* Renders FAQ items in a collapsible accordion format to reduce page length
|
||||
* while maintaining full content visibility for AI crawlers (server-rendered).
|
||||
*/
|
||||
export function BlogFAQ({ items }: BlogFAQProps) {
|
||||
const [openIndex, setOpenIndex] = useState<number | null>(null)
|
||||
|
||||
const toggleFAQ = (index: number) => {
|
||||
setOpenIndex(openIndex === index ? null : index)
|
||||
}
|
||||
|
||||
if (items.length === 0) return null
|
||||
|
||||
return (
|
||||
<section className="mt-12 not-prose">
|
||||
<h2 className="text-2xl font-bold mb-6">Frequently asked questions</h2>
|
||||
<div className="space-y-3">
|
||||
{items.map((item, index) => (
|
||||
<div key={index} className="rounded-lg border border-border bg-card/50 overflow-hidden">
|
||||
<button
|
||||
onClick={() => toggleFAQ(index)}
|
||||
className="flex w-full items-center justify-between p-4 text-left hover:bg-muted/50 transition-colors"
|
||||
aria-expanded={openIndex === index}>
|
||||
<h3 className="text-base font-medium text-foreground pr-4">{item.question}</h3>
|
||||
<ChevronDown
|
||||
className={cn(
|
||||
"h-5 w-5 flex-shrink-0 text-muted-foreground transition-transform duration-200",
|
||||
openIndex === index ? "rotate-180" : "",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
className={cn(
|
||||
"overflow-hidden transition-all duration-300 ease-in-out",
|
||||
openIndex === index ? "max-h-[500px]" : "max-h-0",
|
||||
)}>
|
||||
<div className="px-4 pb-4 text-muted-foreground leading-relaxed">{item.answer}</div>
|
||||
</div>
|
||||
{/* Hidden content for crawlers - ensures FAQ content is always in the DOM */}
|
||||
<div className="sr-only" aria-hidden="true">
|
||||
<p>{item.question}</p>
|
||||
<p>{item.answer}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
/**
|
||||
* Blog Pagination Component
|
||||
* Provides navigation between paginated blog listing pages
|
||||
*/
|
||||
|
||||
import Link from "next/link"
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
interface BlogPaginationProps {
|
||||
currentPage: number
|
||||
totalPages: number
|
||||
basePath?: string
|
||||
/** If true, use query params (?view=all&page=N) instead of path-based pagination */
|
||||
useQueryParams?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the URL for a given page number
|
||||
* Default: Page 1 goes to /blog, pages 2+ go to /blog/page/N
|
||||
* With useQueryParams: Uses /blog?view=all or /blog?view=all&page=N
|
||||
*/
|
||||
function getPageUrl(page: number, basePath: string, useQueryParams?: boolean): string {
|
||||
if (useQueryParams) {
|
||||
if (page === 1) {
|
||||
return "/blog?view=all"
|
||||
}
|
||||
return `/blog?view=all&page=${page}`
|
||||
}
|
||||
|
||||
if (page === 1) {
|
||||
return basePath
|
||||
}
|
||||
return `${basePath}/page/${page}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates page numbers to display
|
||||
* Shows: first, last, current, and neighbors with ellipsis for gaps
|
||||
*/
|
||||
function getPageNumbers(currentPage: number, totalPages: number): (number | "ellipsis")[] {
|
||||
const pages: (number | "ellipsis")[] = []
|
||||
|
||||
if (totalPages <= 7) {
|
||||
// Show all pages if 7 or fewer
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pages.push(i)
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
// Always show first page
|
||||
pages.push(1)
|
||||
|
||||
// Calculate range around current page
|
||||
const leftBound = Math.max(2, currentPage - 1)
|
||||
const rightBound = Math.min(totalPages - 1, currentPage + 1)
|
||||
|
||||
// Add ellipsis before range if needed
|
||||
if (leftBound > 2) {
|
||||
pages.push("ellipsis")
|
||||
}
|
||||
|
||||
// Add pages in range
|
||||
for (let i = leftBound; i <= rightBound; i++) {
|
||||
pages.push(i)
|
||||
}
|
||||
|
||||
// Add ellipsis after range if needed
|
||||
if (rightBound < totalPages - 1) {
|
||||
pages.push("ellipsis")
|
||||
}
|
||||
|
||||
// Always show last page
|
||||
pages.push(totalPages)
|
||||
|
||||
return pages
|
||||
}
|
||||
|
||||
export function BlogPagination({ currentPage, totalPages, basePath = "/blog", useQueryParams }: BlogPaginationProps) {
|
||||
if (totalPages <= 1) {
|
||||
return null
|
||||
}
|
||||
|
||||
const pageNumbers = getPageNumbers(currentPage, totalPages)
|
||||
const hasPreviousPage = currentPage > 1
|
||||
const hasNextPage = currentPage < totalPages
|
||||
|
||||
return (
|
||||
<nav aria-label="Blog pagination" className="mt-12 flex items-center justify-center gap-1 sm:gap-2">
|
||||
{/* Previous button */}
|
||||
{hasPreviousPage ? (
|
||||
<Link
|
||||
href={getPageUrl(currentPage - 1, basePath, useQueryParams)}
|
||||
className={cn(
|
||||
"flex items-center gap-1 rounded-md px-3 py-2 text-sm font-medium",
|
||||
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||
"transition-colors",
|
||||
)}
|
||||
aria-label="Go to previous page">
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
<span className="hidden sm:inline">Previous</span>
|
||||
</Link>
|
||||
) : (
|
||||
<span
|
||||
className={cn(
|
||||
"flex items-center gap-1 rounded-md px-3 py-2 text-sm font-medium",
|
||||
"cursor-not-allowed text-muted-foreground/50",
|
||||
)}
|
||||
aria-disabled="true">
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
<span className="hidden sm:inline">Previous</span>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Page numbers */}
|
||||
<div className="flex items-center gap-1">
|
||||
{pageNumbers.map((page, index) => {
|
||||
if (page === "ellipsis") {
|
||||
return (
|
||||
<span key={`ellipsis-${index}`} className="px-2 py-2 text-sm text-muted-foreground">
|
||||
...
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const isCurrentPage = page === currentPage
|
||||
|
||||
if (isCurrentPage) {
|
||||
return (
|
||||
<span
|
||||
key={page}
|
||||
className={cn(
|
||||
"flex h-9 w-9 items-center justify-center rounded-md text-sm font-medium",
|
||||
"bg-primary text-primary-foreground",
|
||||
)}
|
||||
aria-current="page">
|
||||
{page}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={page}
|
||||
href={getPageUrl(page, basePath, useQueryParams)}
|
||||
className={cn(
|
||||
"flex h-9 w-9 items-center justify-center rounded-md text-sm font-medium",
|
||||
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||
"transition-colors",
|
||||
)}
|
||||
aria-label={`Go to page ${page}`}>
|
||||
{page}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Next button */}
|
||||
{hasNextPage ? (
|
||||
<Link
|
||||
href={getPageUrl(currentPage + 1, basePath, useQueryParams)}
|
||||
className={cn(
|
||||
"flex items-center gap-1 rounded-md px-3 py-2 text-sm font-medium",
|
||||
"text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||
"transition-colors",
|
||||
)}
|
||||
aria-label="Go to next page">
|
||||
<span className="hidden sm:inline">Next</span>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</Link>
|
||||
) : (
|
||||
<span
|
||||
className={cn(
|
||||
"flex items-center gap-1 rounded-md px-3 py-2 text-sm font-medium",
|
||||
"cursor-not-allowed text-muted-foreground/50",
|
||||
)}
|
||||
aria-disabled="true">
|
||||
<span className="hidden sm:inline">Next</span>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</span>
|
||||
)}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/**
|
||||
* Blog Post List Component
|
||||
* Renders a list of blog post previews
|
||||
*/
|
||||
|
||||
import Link from "next/link"
|
||||
import type { BlogPost, BlogSource } from "@/lib/blog"
|
||||
import { formatPostDatePt } from "@/lib/blog"
|
||||
|
||||
interface BlogPostListProps {
|
||||
posts: BlogPost[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Source badge component
|
||||
* Styling matches the tag badges (rounded, same padding)
|
||||
*/
|
||||
function SourceBadge({ source }: { source: BlogSource }) {
|
||||
return <span className="rounded bg-muted px-2 py-1 text-xs text-muted-foreground">{source}</span>
|
||||
}
|
||||
|
||||
export function BlogPostList({ posts }: BlogPostListProps) {
|
||||
if (posts.length === 0) {
|
||||
return (
|
||||
<div className="mt-12 text-center">
|
||||
<p className="text-muted-foreground">No posts published yet. Check back soon!</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-12 space-y-12">
|
||||
{posts.map((post) => (
|
||||
<article key={post.slug} className="border-b border-border pb-12 last:border-b-0">
|
||||
<Link href={`/blog/${post.slug}`} className="group">
|
||||
<h2 className="text-xl font-semibold tracking-tight transition-colors group-hover:text-primary sm:text-2xl">
|
||||
{post.title}
|
||||
</h2>
|
||||
</Link>
|
||||
<div className="mt-2 flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
|
||||
{post.source && <SourceBadge source={post.source} />}
|
||||
<span>{formatPostDatePt(post.publish_date)}</span>
|
||||
</div>
|
||||
<p className="mt-3 text-muted-foreground">{post.description}</p>
|
||||
{post.tags.length > 0 && (
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
{post.tags.map((tag) => (
|
||||
<span key={tag} className="rounded bg-muted px-2 py-1 text-xs text-muted-foreground">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<Link
|
||||
href={`/blog/${post.slug}`}
|
||||
className="mt-4 inline-block text-sm font-medium text-primary hover:underline">
|
||||
Read more →
|
||||
</Link>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* Blog View Toggle Component
|
||||
*
|
||||
* Toggles between curated (featured) posts and all posts view.
|
||||
* Uses URL search params for state to support SSR and sharing.
|
||||
*/
|
||||
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import { useSearchParams } from "next/navigation"
|
||||
|
||||
export type BlogView = "featured" | "all"
|
||||
|
||||
interface BlogViewToggleProps {
|
||||
curatedCount: number
|
||||
totalCount: number
|
||||
}
|
||||
|
||||
export function BlogViewToggle({ curatedCount, totalCount }: BlogViewToggleProps) {
|
||||
const searchParams = useSearchParams()
|
||||
const currentView = (searchParams.get("view") as BlogView) || "featured"
|
||||
|
||||
return (
|
||||
<div className="mt-6 flex items-center gap-4">
|
||||
<div className="flex rounded-lg border border-border bg-muted/50 p-1">
|
||||
<Link
|
||||
href="/blog"
|
||||
className={`rounded-md px-4 py-2 text-sm font-medium transition-colors ${
|
||||
currentView === "featured"
|
||||
? "bg-background text-foreground shadow-sm"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}>
|
||||
Featured
|
||||
<span className="ml-1.5 text-xs text-muted-foreground">({curatedCount})</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/blog?view=all"
|
||||
className={`rounded-md px-4 py-2 text-sm font-medium transition-colors ${
|
||||
currentView === "all"
|
||||
? "bg-background text-foreground shadow-sm"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}>
|
||||
All Posts
|
||||
<span className="ml-1.5 text-xs text-muted-foreground">({totalCount})</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current blog view from search params
|
||||
*/
|
||||
export function getBlogView(searchParams: URLSearchParams): BlogView {
|
||||
const view = searchParams.get("view")
|
||||
return view === "all" ? "all" : "featured"
|
||||
}
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import { useState, useRef, useEffect } from "react"
|
||||
import Link from "next/link"
|
||||
import Image from "next/image"
|
||||
import { ChevronDown } from "lucide-react"
|
||||
|
||||
import { EXTERNAL_LINKS, INTERNAL_LINKS } from "@/lib/constants"
|
||||
import { useLogoSrc } from "@/lib/hooks/use-logo-src"
|
||||
import { ScrollButton } from "@/components/ui"
|
||||
|
||||
export function Footer() {
|
||||
const [privacyDropdownOpen, setPrivacyDropdownOpen] = useState(false)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
const logoSrc = useLogoSrc()
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
useEffect(() => {
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
const target = event.target as Node
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(target)) {
|
||||
setPrivacyDropdownOpen(false)
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside)
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside)
|
||||
}
|
||||
}, [])
|
||||
return (
|
||||
<footer className="border-t border-border bg-background">
|
||||
<div className="mx-auto max-w-7xl px-6 pb-6 pt-12 md:pb-8 md:pt-16 lg:px-8">
|
||||
<div className="xl:grid xl:grid-cols-3 xl:gap-8">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-center">
|
||||
<Image src={logoSrc} alt="Roo Code Logo" width={120} height={40} className="h-6 w-auto" />
|
||||
</div>
|
||||
<p className="max-w-md text-sm leading-6 text-muted-foreground md:pr-16 lg:pr-32">
|
||||
Empowering developers to build better software faster with AI-powered tools and insights.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-16 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0">
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold uppercase leading-6 text-foreground">Product</h3>
|
||||
<ul className="mt-6 space-y-4">
|
||||
<li>
|
||||
<ScrollButton
|
||||
targetId="product"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Features
|
||||
</ScrollButton>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.DOCUMENTATION}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Docs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.CHANGELOG}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Changelog
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="mt-10 md:mt-0">
|
||||
<h3 className="text-sm font-semibold uppercase leading-6 text-foreground">Resources</h3>
|
||||
<ul className="mt-6 space-y-4">
|
||||
<li>
|
||||
<Link
|
||||
href="/blog"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Blog
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.TUTORIALS}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Tutorials
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.ISSUES}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Issues
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8">
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold uppercase leading-6 text-foreground">Company</h3>
|
||||
<ul className="mt-6 space-y-4">
|
||||
<li>
|
||||
<a
|
||||
href="mailto:support@roocode.com"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Contact
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href="/terms"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Terms of Service
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<div className="relative z-10" ref={dropdownRef}>
|
||||
<button
|
||||
onClick={() => setPrivacyDropdownOpen(!privacyDropdownOpen)}
|
||||
className="flex items-center text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground"
|
||||
aria-expanded={privacyDropdownOpen}
|
||||
aria-haspopup="true">
|
||||
<span>
|
||||
Privacy <span className="max-[320px]:hidden">Policy</span>
|
||||
</span>
|
||||
<ChevronDown
|
||||
className={`ml-1 h-4 w-4 transition-transform ${privacyDropdownOpen ? "rotate-180" : ""}`}
|
||||
/>
|
||||
</button>
|
||||
|
||||
{privacyDropdownOpen && (
|
||||
<div className="absolute z-50 mt-2 w-44 origin-top-left scale-95 rounded-md border border-border bg-background shadow-lg ring-1 ring-black ring-opacity-5 transition-all duration-100 ease-out data-[state=open]:scale-100 max-xs:right-0 max-xs:origin-top-right xs:left-0">
|
||||
<div className="flex flex-col gap-1 p-2 text-sm text-muted-foreground">
|
||||
<a
|
||||
href={EXTERNAL_LINKS.PRIVACY_POLICY_EXTENSION}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => setPrivacyDropdownOpen(false)}
|
||||
className="rounded-md px-3 py-2 transition-colors hover:bg-accent/50 hover:text-foreground">
|
||||
Extension
|
||||
</a>
|
||||
<Link
|
||||
href={INTERNAL_LINKS.PRIVACY_POLICY_WEBSITE}
|
||||
onClick={() => setPrivacyDropdownOpen(false)}
|
||||
className="rounded-md px-3 py-2 transition-colors hover:bg-accent/50 hover:text-foreground">
|
||||
Roo Code Cloud
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href="/legal/cookies"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Cookie Policy
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href="/legal/subprocessors"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
Subprocessors
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="mt-10 md:mt-0">
|
||||
<h3 className="text-sm font-semibold uppercase leading-6 text-foreground">Connect</h3>
|
||||
<ul className="mt-6 space-y-4">
|
||||
<li>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.GITHUB}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
GitHub
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.X}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm leading-6 text-muted-foreground transition-colors hover:text-foreground">
|
||||
X / Twitter
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-16 flex border-t border-border pt-8 sm:mt-20 lg:mt-24">
|
||||
<p className="mx-auto text-sm leading-5 text-muted-foreground">
|
||||
© {new Date().getFullYear()} Roo Code. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
export * from "./footer"
|
||||
export * from "./nav-bar"
|
||||
export * from "./stats-display"
|
||||
export * from "./theme-toggle"
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
/* eslint-disable react/jsx-no-target-blank */
|
||||
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import Image from "next/image"
|
||||
import { useState } from "react"
|
||||
import { RxGithubLogo } from "react-icons/rx"
|
||||
import { VscVscode } from "react-icons/vsc"
|
||||
import { HiMenu } from "react-icons/hi"
|
||||
|
||||
import { EXTERNAL_LINKS } from "@/lib/constants"
|
||||
import { useLogoSrc } from "@/lib/hooks/use-logo-src"
|
||||
import { ScrollButton } from "@/components/ui"
|
||||
import ThemeToggle from "@/components/chromes/theme-toggle"
|
||||
import { X } from "lucide-react"
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuList,
|
||||
navigationMenuTriggerStyle,
|
||||
} from "@/components/ui/navigation-menu"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
interface NavBarProps {
|
||||
stars: string | null
|
||||
downloads: string | null
|
||||
}
|
||||
|
||||
export function NavBar({ stars, downloads }: NavBarProps) {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||||
const logoSrc = useLogoSrc()
|
||||
|
||||
return (
|
||||
<header className="sticky font-light top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
|
||||
<div className="container flex h-16 items-center justify-between px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center flex-shrink-0">
|
||||
<Link href="/" className="flex items-center">
|
||||
<Image src={logoSrc} alt="Roo Code Logo" width={130} height={24} className="h-[24px] w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<NavigationMenu className="grow ml-6 hidden text-sm md:flex">
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
asChild
|
||||
className={cn(navigationMenuTriggerStyle(), "bg-transparent font-light")}>
|
||||
<a href={EXTERNAL_LINKS.DOCUMENTATION} target="_blank">
|
||||
Docs
|
||||
</a>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuLink
|
||||
asChild
|
||||
className={cn(navigationMenuTriggerStyle(), "bg-transparent font-light")}>
|
||||
<Link href="/blog">Blog</Link>
|
||||
</NavigationMenuLink>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
|
||||
<div className="hidden md:flex md:items-center md:space-x-4 flex-shrink-0 font-medium">
|
||||
<div className="flex flex-row space-x-2 flex-shrink-0">
|
||||
<ThemeToggle />
|
||||
<Link
|
||||
href={EXTERNAL_LINKS.GITHUB}
|
||||
target="_blank"
|
||||
className="hidden items-center gap-1.5 text-sm hover:text-foreground md:flex whitespace-nowrap">
|
||||
<RxGithubLogo className="h-4 w-4" />
|
||||
{stars !== null && <span>{stars}</span>}
|
||||
</Link>
|
||||
</div>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.CLOUD_APP_LOGIN}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hidden items-center gap-1.5 rounded-md py-2 text-sm border border-primary-background px-4 text-primary-background transition-all duration-200 hover:shadow-lg hover:scale-105 lg:flex">
|
||||
Log in
|
||||
</a>
|
||||
<Link
|
||||
href={EXTERNAL_LINKS.MARKETPLACE}
|
||||
target="_blank"
|
||||
className="hidden items-center gap-1.5 rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground transition-all duration-200 hover:shadow-lg hover:scale-105 md:flex whitespace-nowrap">
|
||||
<VscVscode className="-mr-[2px] mt-[1px] h-4 w-4" />
|
||||
<span>
|
||||
Install <span className="font-black max-lg:text-xs">·</span>
|
||||
</span>
|
||||
{downloads !== null && <span>{downloads}</span>}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<button
|
||||
aria-expanded={isMenuOpen}
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
className="relative z-10 flex items-center justify-center rounded-full p-2 transition-colors hover:bg-accent md:hidden"
|
||||
aria-label="Toggle mobile menu">
|
||||
<HiMenu className={`h-6 w-6 ${isMenuOpen ? "hidden" : "block"}`} />
|
||||
<X className={`h-6 w-6 ${isMenuOpen ? "block" : "hidden"}`} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Panel - Full Screen */}
|
||||
<div
|
||||
className={`fixed top-16 left-0 bg-background right-0 z-[100] transition-all duration-200 pointer-events-none md:hidden ${isMenuOpen ? "block h-dvh" : "hidden"}`}>
|
||||
<nav className="flex flex-col justify-between h-full pb-16 overflow-y-auto bg-background pointer-events-auto">
|
||||
{/* Main navigation items */}
|
||||
<div className="grow-1 py-4 font-semibold text-lg">
|
||||
<a
|
||||
href={EXTERNAL_LINKS.DOCUMENTATION}
|
||||
target="_blank"
|
||||
className="block w-full p-5 py-4 text-left text-foreground active:opacity-50"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
Docs
|
||||
</a>
|
||||
|
||||
<Link
|
||||
href="/blog"
|
||||
className="block w-full p-5 py-3 text-left text-foreground active:opacity-50"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
Blog
|
||||
</Link>
|
||||
<ScrollButton
|
||||
targetId="faq"
|
||||
className="block w-full p-5 py-3 text-left text-foreground active:opacity-50"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
FAQ
|
||||
</ScrollButton>
|
||||
</div>
|
||||
|
||||
{/* Bottom section with Cloud Login and stats */}
|
||||
<div className="border-t border-border">
|
||||
<div className="flex items-center justify-around px-6 pt-2">
|
||||
<Link
|
||||
href={EXTERNAL_LINKS.GITHUB}
|
||||
target="_blank"
|
||||
className="inline-flex items-center gap-2 rounded-md p-3 text-sm transition-colors hover:bg-accent hover:text-foreground"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
<RxGithubLogo className="h-6 w-6" />
|
||||
{stars !== null && <span>{stars}</span>}
|
||||
</Link>
|
||||
<div className="flex items-center rounded-md p-3 transition-colors hover:bg-accent">
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
<Link
|
||||
href={EXTERNAL_LINKS.MARKETPLACE}
|
||||
target="_blank"
|
||||
className="inline-flex items-center gap-2 rounded-md p-3 text-sm transition-colors hover:bg-accent hover:text-foreground"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
<VscVscode className="h-6 w-6" />
|
||||
{downloads !== null && <span>{downloads}</span>}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex gap-2 px-4 pb-4">
|
||||
<a
|
||||
href={EXTERNAL_LINKS.CLOUD_APP_LOGIN}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-center gap-2 rounded-full border border-primary bg-background p-4 w-full text-base font-semibold text-primary"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
Log in
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||