@promptbook/cli 0.104.0-1 → 0.104.0-11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/agents-server/config.ts +1 -3
- package/apps/agents-server/next.config.ts +2 -2
- package/apps/agents-server/package.json +7 -3
- package/apps/agents-server/public/fonts/OpenMoji-color-cbdt.woff2 +0 -0
- package/apps/agents-server/public/swagger.json +115 -0
- package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +54 -0
- package/apps/agents-server/scripts/generate-reserved-paths/tsconfig.json +19 -0
- package/apps/agents-server/src/app/AddAgentButton.tsx +47 -21
- package/apps/agents-server/src/app/actions.ts +22 -5
- package/apps/agents-server/src/app/admin/browser-test/BrowserTestClient.tsx +211 -0
- package/apps/agents-server/src/app/admin/browser-test/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +221 -274
- package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +94 -137
- package/apps/agents-server/src/app/admin/files/FilesGalleryClient.tsx +263 -0
- package/apps/agents-server/src/app/admin/files/actions.ts +61 -0
- package/apps/agents-server/src/app/admin/files/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/image-generator-test/ImageGeneratorTestClient.tsx +169 -0
- package/apps/agents-server/src/app/admin/image-generator-test/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/images/ImagesGalleryClient.tsx +256 -0
- package/apps/agents-server/src/app/admin/images/actions.ts +60 -0
- package/apps/agents-server/src/app/admin/images/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +294 -0
- package/apps/agents-server/src/app/admin/messages/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +104 -0
- package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +35 -0
- package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +13 -0
- package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +23 -19
- package/apps/agents-server/src/app/admin/search-engine-test/SearchEngineTestClient.tsx +109 -0
- package/apps/agents-server/src/app/admin/search-engine-test/actions.ts +17 -0
- package/apps/agents-server/src/app/admin/search-engine-test/page.tsx +13 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +15 -1
- package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +51 -9
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +47 -4
- package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +53 -11
- package/apps/agents-server/src/app/agents/[agentName]/_utils.ts +23 -3
- package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +8 -8
- package/apps/agents-server/src/app/agents/[agentName]/api/agents/route.ts +17 -26
- package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +4 -2
- package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +20 -0
- package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +6 -11
- package/apps/agents-server/src/app/agents/[agentName]/api/profile/route.ts +5 -1
- package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +5 -2
- package/apps/agents-server/src/app/agents/[agentName]/book/BookEditorWrapper.tsx +20 -16
- package/apps/agents-server/src/app/agents/[agentName]/book/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/book+chat/page.tsx +15 -2
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +12 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/api/route.ts +68 -0
- package/apps/agents-server/src/app/agents/[agentName]/code/page.tsx +223 -0
- package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +5 -0
- package/apps/agents-server/src/app/agents/[agentName]/history/actions.ts +2 -2
- package/apps/agents-server/src/app/agents/[agentName]/history/page.tsx +10 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/getAgentDefaultAvatarPrompt.ts +31 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/default-avatar.png/route.ts +194 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/icon-256.png/route.tsx +14 -2
- package/apps/agents-server/src/app/agents/[agentName]/images/page.tsx +200 -0
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-fullhd.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/images/screenshot-phone.png/route.tsx +4 -3
- package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +10 -3
- package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +11 -4
- package/apps/agents-server/src/app/agents/[agentName]/opengraph-image.tsx +11 -2
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +18 -10
- package/apps/agents-server/src/app/agents/[agentName]/system-message/page.tsx +100 -0
- package/apps/agents-server/src/app/api/admin-email/route.ts +12 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/clone/route.ts +13 -14
- package/apps/agents-server/src/app/api/agents/[agentName]/restore/route.ts +20 -0
- package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +43 -1
- package/apps/agents-server/src/app/api/agents/route.ts +28 -3
- package/apps/agents-server/src/app/api/api-tokens/route.ts +6 -7
- package/apps/agents-server/src/app/api/browser-test/act/route.ts +141 -0
- package/apps/agents-server/src/app/api/browser-test/screenshot/route.ts +30 -0
- package/apps/agents-server/src/app/api/browser-test/scroll-facebook/route.ts +62 -0
- package/apps/agents-server/src/app/api/docs/book.md/route.ts +61 -0
- package/apps/agents-server/src/app/api/emails/incoming/sendgrid/route.ts +48 -0
- package/apps/agents-server/src/app/api/federated-agents/route.ts +12 -0
- package/apps/agents-server/src/app/api/images/[filename]/route.ts +128 -0
- package/apps/agents-server/src/app/api/messages/route.ts +102 -0
- package/apps/agents-server/src/app/api/metadata/route.ts +5 -6
- package/apps/agents-server/src/app/api/upload/route.ts +128 -45
- package/apps/agents-server/src/app/docs/[docId]/page.tsx +2 -3
- package/apps/agents-server/src/app/docs/page.tsx +12 -12
- package/apps/agents-server/src/app/globals.css +140 -33
- package/apps/agents-server/src/app/humans.txt/route.ts +1 -1
- package/apps/agents-server/src/app/layout.tsx +27 -22
- package/apps/agents-server/src/app/page.tsx +54 -6
- package/apps/agents-server/src/app/recycle-bin/actions.ts +20 -14
- package/apps/agents-server/src/app/recycle-bin/page.tsx +27 -41
- package/apps/agents-server/src/app/robots.txt/route.ts +1 -1
- package/apps/agents-server/src/app/security.txt/route.ts +1 -1
- package/apps/agents-server/src/app/sitemap.xml/route.ts +9 -7
- package/apps/agents-server/src/app/swagger/page.tsx +14 -0
- package/apps/agents-server/src/components/AgentProfile/AgentCapabilityChips.tsx +38 -0
- package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +44 -116
- package/apps/agents-server/src/components/AgentProfile/AgentProfileImage.tsx +92 -0
- package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +0 -1
- package/apps/agents-server/src/components/AgentProfile/useAgentBackground.ts +97 -0
- package/apps/agents-server/src/components/Auth/AuthControls.tsx +5 -4
- package/apps/agents-server/src/components/DeletedAgentBanner.tsx +26 -0
- package/apps/agents-server/src/components/DocsToolbar/DocsToolbar.tsx +38 -0
- package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +11 -9
- package/apps/agents-server/src/components/Footer/Footer.tsx +5 -5
- package/apps/agents-server/src/components/ForgottenPasswordDialog/ForgottenPasswordDialog.tsx +61 -0
- package/apps/agents-server/src/components/Header/Header.tsx +130 -40
- package/apps/agents-server/src/components/Homepage/AgentCard.tsx +150 -23
- package/apps/agents-server/src/components/Homepage/AgentsList.tsx +93 -15
- package/apps/agents-server/src/components/Homepage/DeletedAgentsList.tsx +66 -0
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSection.tsx +12 -3
- package/apps/agents-server/src/components/Homepage/ExternalAgentsSectionClient.tsx +19 -10
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +3 -2
- package/apps/agents-server/src/components/LoginForm/LoginForm.tsx +50 -1
- package/apps/agents-server/src/components/NewAgentDialog/NewAgentDialog.tsx +88 -0
- package/apps/agents-server/src/components/NotFoundPage/NotFoundPage.tsx +7 -2
- package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +16 -7
- package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +4 -4
- package/apps/agents-server/src/components/RegisterUserDialog/RegisterUserDialog.tsx +61 -0
- package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +2 -0
- package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +12 -10
- package/apps/agents-server/src/components/_utils/headlessParam.tsx +7 -3
- package/apps/agents-server/src/database/$getTableName.ts +1 -0
- package/apps/agents-server/src/database/$provideSupabaseForBrowser.ts +3 -3
- package/apps/agents-server/src/database/$provideSupabaseForServer.ts +1 -1
- package/apps/agents-server/src/database/$provideSupabaseForWorker.ts +3 -3
- package/apps/agents-server/src/database/metadataDefaults.ts +19 -1
- package/apps/agents-server/src/database/migrate.ts +34 -1
- package/apps/agents-server/src/database/migrations/2025-11-0001-initial-schema.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +1 -3
- package/apps/agents-server/src/database/migrations/2025-12-0240-agent-public-id.sql +3 -0
- package/apps/agents-server/src/database/migrations/2025-12-0360-agent-deleted-at.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0370-image-table.sql +19 -0
- package/apps/agents-server/src/database/migrations/2025-12-0380-agent-visibility.sql +1 -0
- package/apps/agents-server/src/database/migrations/2025-12-0390-upload-tracking.sql +20 -0
- package/apps/agents-server/src/database/migrations/2025-12-0401-file-upload-status.sql +13 -0
- package/apps/agents-server/src/database/migrations/2025-12-0402-message-table.sql +42 -0
- package/apps/agents-server/src/database/migrations/2025-12-0403-generation-lock-table.sql +15 -0
- package/apps/agents-server/src/database/migrations/2025-12-0640-openai-assistant-cache.sql +12 -0
- package/apps/agents-server/src/database/migrations/2025-12-0820-agent-history-permanent-id.sql +29 -0
- package/apps/agents-server/src/database/migrations/2025-12-0830-image-purpose.sql +5 -0
- package/apps/agents-server/src/database/migrations/2025-12-0890-file-agent-id.sql +5 -0
- package/apps/agents-server/src/database/schema.ts +244 -4
- package/apps/agents-server/src/generated/reservedPaths.ts +32 -0
- package/apps/agents-server/src/message-providers/email/_common/Email.ts +73 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/TODO.txt +1 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +108 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.ts +62 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +117 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +119 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +74 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts +14 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/SendgridMessageProvider.ts +44 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/parseInboundSendgridEmail.ts +49 -0
- package/apps/agents-server/src/message-providers/email/zeptomail/ZeptomailMessageProvider.ts +51 -0
- package/apps/agents-server/src/message-providers/index.ts +13 -0
- package/apps/agents-server/src/message-providers/interfaces/MessageProvider.ts +11 -0
- package/apps/agents-server/src/middleware.ts +19 -23
- package/apps/agents-server/src/tools/$provideBrowserForServer.ts +32 -0
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +7 -2
- package/apps/agents-server/src/utils/auth.ts +117 -17
- package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +57 -0
- package/apps/agents-server/src/utils/cdn/classes/VercelBlobStorage.ts +4 -0
- package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +18 -0
- package/apps/agents-server/src/utils/content/extractBodyContentFromHtml.ts +19 -0
- package/apps/agents-server/src/utils/getUserIdFromRequest.ts +35 -0
- package/apps/agents-server/src/utils/handleChatCompletion.ts +65 -5
- package/apps/agents-server/src/utils/messages/sendMessage.ts +91 -0
- package/apps/agents-server/src/utils/messagesAdmin.ts +72 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.test.ts +36 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +25 -0
- package/apps/agents-server/src/utils/validateApiKey.ts +7 -11
- package/esm/index.es.js +1534 -1330
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +8 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +16 -2
- package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +29 -1
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +6 -6
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.closed.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -3
- package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +5 -1
- package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/esm/typings/src/book-components/Chat/CodeBlock/CodeBlock.d.ts +13 -0
- package/esm/typings/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +9 -13
- package/esm/typings/src/book-components/_common/Dropdown/Dropdown.d.ts +3 -3
- package/esm/typings/src/book-components/_common/HamburgerMenu/HamburgerMenu.d.ts +1 -1
- package/esm/typings/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +56 -0
- package/esm/typings/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/AttachmentIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/CameraIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/MenuIcon.d.ts +1 -1
- package/esm/typings/src/book-components/icons/SaveIcon.d.ts +1 -1
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +22 -12
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +27 -15
- package/esm/typings/src/commitments/DICTIONARY/DICTIONARY.d.ts +46 -0
- package/esm/typings/src/commitments/index.d.ts +2 -1
- package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +1 -1
- package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +6 -1
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/ollama/OllamaExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
- package/esm/typings/src/remote-server/ui/ServerApp.d.ts +1 -1
- package/esm/typings/src/search-engines/SearchEngine.d.ts +9 -0
- package/esm/typings/src/search-engines/SearchResult.d.ts +18 -0
- package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +15 -0
- package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +15 -0
- package/esm/typings/src/types/Message.d.ts +49 -0
- package/esm/typings/src/types/ModelRequirements.d.ts +38 -14
- package/esm/typings/src/types/typeAliases.d.ts +23 -1
- package/esm/typings/src/utils/color/utils/colorToDataUrl.d.ts +2 -1
- package/esm/typings/src/utils/environment/$detectRuntimeEnvironment.d.ts +4 -4
- package/esm/typings/src/utils/environment/$isRunningInBrowser.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInJest.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInNode.d.ts +1 -1
- package/esm/typings/src/utils/environment/$isRunningInWebWorker.d.ts +1 -1
- package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
- package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +3 -2
- package/esm/typings/src/utils/random/$randomBase58.d.ts +12 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +1542 -1338
- package/umd/index.umd.js.map +1 -1
- package/apps/agents-server/package-lock.json +0 -27
- package/apps/agents-server/public/fonts/download-font.js +0 -22
- package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +0 -18
- package/esm/typings/src/book-2.0/utils/generateGravatarUrl.d.ts +0 -10
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
// Dynamic sitemap.xml for Agents Server
|
|
2
2
|
|
|
3
|
-
import { NEXT_PUBLIC_SITE_URL } from '@/config';
|
|
4
3
|
import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
|
|
4
|
+
import { $provideServer } from '@/src/tools/$provideServer';
|
|
5
5
|
import { spaceTrim } from '@promptbook-local/utils';
|
|
6
6
|
import { NextResponse } from 'next/server';
|
|
7
7
|
|
|
8
8
|
export const dynamic = 'force-dynamic';
|
|
9
9
|
|
|
10
10
|
export async function GET() {
|
|
11
|
+
const { publicUrl } = await $provideServer();
|
|
12
|
+
|
|
11
13
|
const collection = await $provideAgentCollectionForServer();
|
|
12
14
|
|
|
13
15
|
// Assume collection.listAgents() returns an array of agent names
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
// Get base URL from environment or config
|
|
17
|
-
const baseUrl = NEXT_PUBLIC_SITE_URL?.href || process.env.PUBLIC_URL || 'https://ptbk.io';
|
|
16
|
+
const agents = await collection.listAgents();
|
|
18
17
|
|
|
19
|
-
const urls =
|
|
20
|
-
.map(
|
|
18
|
+
const urls = agents
|
|
19
|
+
.map(
|
|
20
|
+
({ permanentId, agentName }) =>
|
|
21
|
+
`<url><loc>${publicUrl.href}agents/${encodeURIComponent(permanentId || agentName)}</loc></url>`,
|
|
22
|
+
)
|
|
21
23
|
.join('\n');
|
|
22
24
|
|
|
23
25
|
const xml = spaceTrim(
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import dynamic from 'next/dynamic';
|
|
4
|
+
import 'swagger-ui-react/swagger-ui.css';
|
|
5
|
+
|
|
6
|
+
const SwaggerUI = dynamic(() => import('swagger-ui-react'), { ssr: false });
|
|
7
|
+
|
|
8
|
+
export default function SwaggerPage() {
|
|
9
|
+
return (
|
|
10
|
+
<div className="swagger-container bg-white min-h-screen">
|
|
11
|
+
<SwaggerUI url="/swagger.json" />
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AgentBasicInformation } from '@promptbook-local/types';
|
|
2
|
+
import { Book, FileText, Globe, Search } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
type AgentCapabilityChipsProps = {
|
|
5
|
+
readonly agent: AgentBasicInformation;
|
|
6
|
+
readonly className?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function AgentCapabilityChips({ agent, className }: AgentCapabilityChipsProps) {
|
|
10
|
+
if (!agent.capabilities || agent.capabilities.length === 0) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className={`flex flex-wrap gap-2 ${className || ''}`}>
|
|
16
|
+
{agent.capabilities.map((capability, i) => {
|
|
17
|
+
const Icon =
|
|
18
|
+
{
|
|
19
|
+
Globe,
|
|
20
|
+
Search,
|
|
21
|
+
Book,
|
|
22
|
+
FileText,
|
|
23
|
+
}[capability.iconName] || Book;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div
|
|
27
|
+
key={i}
|
|
28
|
+
className="flex items-center gap-1.5 bg-white/50 backdrop-blur-sm px-2.5 py-1 rounded-full text-xs font-semibold text-gray-800 border border-white/20 shadow-sm"
|
|
29
|
+
title={capability.label}
|
|
30
|
+
>
|
|
31
|
+
<Icon className="w-3.5 h-3.5 opacity-70" />
|
|
32
|
+
<span className="truncate max-w-[150px]">{capability.label}</span>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
})}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { colorToDataUrl } from '@promptbook-local/color';
|
|
4
|
+
import { generatePlaceholderAgentProfileImageUrl } from '@promptbook-local/core';
|
|
5
|
+
import { AgentBasicInformation, string_agent_permanent_id } from '@promptbook-local/types';
|
|
4
6
|
import { RepeatIcon } from 'lucide-react';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import { darken } from '../../../../../src/utils/color/operators/darken';
|
|
9
|
-
import { lighten } from '../../../../../src/utils/color/operators/lighten';
|
|
7
|
+
import { useState } from 'react';
|
|
8
|
+
import { AgentCapabilityChips } from './AgentCapabilityChips';
|
|
9
|
+
import { AgentProfileImage } from './AgentProfileImage';
|
|
10
10
|
import { AgentQrCode } from './AgentQrCode';
|
|
11
11
|
import { QrCodeModal } from './QrCodeModal';
|
|
12
|
+
import { useAgentBackground } from './useAgentBackground';
|
|
12
13
|
|
|
13
14
|
type AgentProfileProps = {
|
|
14
15
|
/**
|
|
@@ -16,6 +17,11 @@ type AgentProfileProps = {
|
|
|
16
17
|
*/
|
|
17
18
|
readonly agent: AgentBasicInformation;
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* The permanent ID of the agent
|
|
22
|
+
*/
|
|
23
|
+
readonly permanentId: string_agent_permanent_id;
|
|
24
|
+
|
|
19
25
|
/**
|
|
20
26
|
* URL of the agent page
|
|
21
27
|
*
|
|
@@ -23,6 +29,11 @@ type AgentProfileProps = {
|
|
|
23
29
|
*/
|
|
24
30
|
readonly agentUrl?: string;
|
|
25
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Base URL of the agents server
|
|
34
|
+
*/
|
|
35
|
+
readonly publicUrl: URL;
|
|
36
|
+
|
|
26
37
|
/**
|
|
27
38
|
* Email of the agent
|
|
28
39
|
*/
|
|
@@ -61,16 +72,19 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
61
72
|
agent,
|
|
62
73
|
agentUrl = '',
|
|
63
74
|
agentEmail = '',
|
|
75
|
+
publicUrl,
|
|
76
|
+
permanentId,
|
|
64
77
|
renderMenu,
|
|
65
78
|
children,
|
|
66
79
|
actions,
|
|
67
80
|
isHeadless = false,
|
|
68
81
|
className,
|
|
69
82
|
} = props;
|
|
83
|
+
|
|
70
84
|
const { meta, agentName } = agent;
|
|
71
85
|
const fullname = (meta.fullname as string) || agentName || 'Agent';
|
|
72
86
|
const personaDescription = agent.personaDescription || '';
|
|
73
|
-
const imageUrl =
|
|
87
|
+
const imageUrl = meta.image || generatePlaceholderAgentProfileImageUrl(permanentId, publicUrl);
|
|
74
88
|
|
|
75
89
|
const [isQrModalOpen, setIsQrModalOpen] = useState(false);
|
|
76
90
|
const [isFlipped, setIsFlipped] = useState(false);
|
|
@@ -81,102 +95,14 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
81
95
|
|
|
82
96
|
if (fontString) {
|
|
83
97
|
// [🧠] TODO: Properly parse font string to get family name
|
|
84
|
-
const primaryFont = fontString.split(',')[0].trim().replace(/['"]/g, '');
|
|
98
|
+
// const primaryFont = fontString.split(',')[0].trim().replace(/['"]/g, '');
|
|
85
99
|
fontStyle = {
|
|
86
100
|
fontFamily: fontString,
|
|
87
101
|
};
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
// Compute Colors and Background
|
|
91
|
-
const { brandColorHex, brandColorLightHex, brandColorDarkHex, backgroundImage } =
|
|
92
|
-
// [🧠] Default color should be imported constant, but for now hardcoded fallback
|
|
93
|
-
const PROMPTBOOK_COLOR_HEX = '#f15b24'; // TODO: Import PROMPTBOOK_COLOR
|
|
94
|
-
const brandColorString = meta.color || PROMPTBOOK_COLOR_HEX;
|
|
95
|
-
|
|
96
|
-
let brandColor;
|
|
97
|
-
try {
|
|
98
|
-
brandColor = Color.fromSafe(brandColorString.split(',')[0].trim());
|
|
99
|
-
} catch {
|
|
100
|
-
brandColor = Color.fromHex(PROMPTBOOK_COLOR_HEX);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const brandColorHex = brandColor.toHex();
|
|
104
|
-
const brandColorLightHex = brandColor.then(lighten(0.2)).toHex();
|
|
105
|
-
const brandColorDarkHex = brandColor.then(darken(0.15)).toHex();
|
|
106
|
-
|
|
107
|
-
// Generate Noisy SVG Background
|
|
108
|
-
const color1 = brandColor;
|
|
109
|
-
// const color2 = brandColors[1] || brandColors[0]!; // Use secondary color if available?
|
|
110
|
-
// For simplicity using primary color for now or derive second one
|
|
111
|
-
const color2 = brandColor;
|
|
112
|
-
|
|
113
|
-
// [🧠] Make colors much lighter for the background
|
|
114
|
-
const color1Light = color1.then(lighten(0.3)).toHex();
|
|
115
|
-
const color1Main = color1.toHex();
|
|
116
|
-
const color1Dark = color1.then(darken(0.3)).toHex();
|
|
117
|
-
|
|
118
|
-
const color2Light = color2.then(lighten(0.3)).toHex();
|
|
119
|
-
const color2Main = color2.toHex();
|
|
120
|
-
const color2Dark = color2.then(darken(0.3)).toHex();
|
|
121
|
-
|
|
122
|
-
const svgContent = spaceTrim(`
|
|
123
|
-
<svg xmlns="http://www.w3.org/2000/svg"
|
|
124
|
-
viewBox="0 0 1920 1080"
|
|
125
|
-
width="1920" height="1080"
|
|
126
|
-
preserveAspectRatio="xMidYMid slice">
|
|
127
|
-
<defs>
|
|
128
|
-
<!-- Bottom-left -->
|
|
129
|
-
<radialGradient id="grad1" cx="0%" cy="100%" r="90%">
|
|
130
|
-
<stop offset="0%" stop-color="${color1Light}" />
|
|
131
|
-
<stop offset="50%" stop-color="${color1Main}" />
|
|
132
|
-
<stop offset="100%" stop-color="${color1Dark}" />
|
|
133
|
-
</radialGradient>
|
|
134
|
-
|
|
135
|
-
<!-- Bottom-right -->
|
|
136
|
-
<radialGradient id="grad2" cx="100%" cy="100%" r="90%">
|
|
137
|
-
<stop offset="0%" stop-color="${color2Light}" />
|
|
138
|
-
<stop offset="50%" stop-color="${color2Main}" />
|
|
139
|
-
<stop offset="100%" stop-color="${color2Dark}" />
|
|
140
|
-
</radialGradient>
|
|
141
|
-
|
|
142
|
-
<!-- White top fade -->
|
|
143
|
-
<linearGradient id="whiteTopGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
144
|
-
<stop offset="0%" stop-color="#ffffff" stop-opacity="1" />
|
|
145
|
-
<stop offset="100%" stop-color="#ffffff" stop-opacity="0.3" />
|
|
146
|
-
</linearGradient>
|
|
147
|
-
|
|
148
|
-
<!-- Strong grain -->
|
|
149
|
-
<filter id="grain" x="-10%" y="-10%" width="120%" height="120%">
|
|
150
|
-
<feTurbulence type="fractalNoise" baseFrequency="3.5" numOctaves="3" seed="8" result="noise" />
|
|
151
|
-
<feComponentTransfer>
|
|
152
|
-
<feFuncR type="linear" slope="3.5" intercept="-1.2" />
|
|
153
|
-
<feFuncG type="linear" slope="3.5" intercept="-1.2" />
|
|
154
|
-
<feFuncB type="linear" slope="3.5" intercept="-1.2" />
|
|
155
|
-
<feFuncA type="table" tableValues="0 0.8" />
|
|
156
|
-
</feComponentTransfer>
|
|
157
|
-
</filter>
|
|
158
|
-
</defs>
|
|
159
|
-
|
|
160
|
-
<!-- White base -->
|
|
161
|
-
<rect width="100%" height="100%" fill="#ffffff" />
|
|
162
|
-
|
|
163
|
-
<!-- Gradients -->
|
|
164
|
-
<rect width="100%" height="100%" fill="url(#grad1)" />
|
|
165
|
-
<rect width="100%" height="100%" fill="url(#grad2)" style="mix-blend-mode:screen; opacity:0.85" />
|
|
166
|
-
|
|
167
|
-
<!-- White fade on top -->
|
|
168
|
-
<rect width="100%" height="100%" fill="url(#whiteTopGrad)" />
|
|
169
|
-
|
|
170
|
-
<!-- Strong visible noise -->
|
|
171
|
-
<rect width="100%" height="100%" filter="url(#grain)"
|
|
172
|
-
style="mix-blend-mode:soft-light; opacity:1.2" />
|
|
173
|
-
</svg>
|
|
174
|
-
`);
|
|
175
|
-
|
|
176
|
-
const backgroundImage = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`;
|
|
177
|
-
|
|
178
|
-
return { brandColorHex, brandColorLightHex, brandColorDarkHex, backgroundImage };
|
|
179
|
-
}, [meta.color]);
|
|
105
|
+
const { brandColorHex, brandColorLightHex, brandColorDarkHex, backgroundImage } = useAgentBackground(meta.color);
|
|
180
106
|
|
|
181
107
|
return (
|
|
182
108
|
<>
|
|
@@ -208,14 +134,14 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
208
134
|
)}
|
|
209
135
|
|
|
210
136
|
{/* Main profile content */}
|
|
211
|
-
<div className="relative z-10 grid grid-cols-[auto_1fr] gap-
|
|
137
|
+
<div className="relative z-10 flex flex-col md:grid md:grid-cols-[auto_1fr] gap-y-6 md:gap-y-4 md:gap-x-12 max-w-5xl w-full items-center md:items-start">
|
|
212
138
|
{/* Agent image card (Flippable) */}
|
|
213
139
|
<div
|
|
214
|
-
className="flex-shrink-0 perspective-1000 group row-start-1 col-start-1 md:row-span-3"
|
|
140
|
+
className="flex-shrink-0 perspective-1000 group w-full md:w-auto md:row-start-1 md:col-start-1 md:row-span-3"
|
|
215
141
|
style={{ perspective: '1000px' }}
|
|
216
142
|
>
|
|
217
143
|
<div
|
|
218
|
-
className="relative w-
|
|
144
|
+
className="relative w-full md:w-80 transition-all duration-700 transform-style-3d cursor-pointer max-w-sm mx-auto md:max-w-none md:mx-0"
|
|
219
145
|
style={{
|
|
220
146
|
aspectRatio: '1 / 1.618', // Golden Ratio
|
|
221
147
|
transformStyle: 'preserve-3d',
|
|
@@ -230,19 +156,21 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
230
156
|
backfaceVisibility: 'hidden',
|
|
231
157
|
backgroundColor: brandColorDarkHex,
|
|
232
158
|
boxShadow: `0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 0 0 1px ${brandColorLightHex}40`,
|
|
159
|
+
|
|
160
|
+
// Note: Make it squircle
|
|
161
|
+
// borderRadius: '50%',
|
|
162
|
+
// ['cornerShape' as really_any /* <- Note: `cornerShape` is non standard CSS property */]: 'squircle ',
|
|
233
163
|
}}
|
|
234
164
|
>
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
</div>
|
|
245
|
-
)}
|
|
165
|
+
<AgentProfileImage
|
|
166
|
+
src={imageUrl}
|
|
167
|
+
alt={fullname}
|
|
168
|
+
className="w-full h-full object-cover"
|
|
169
|
+
style={{
|
|
170
|
+
objectFit: 'cover',
|
|
171
|
+
backgroundImage: `url(${colorToDataUrl(brandColorLightHex)})`,
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
246
174
|
|
|
247
175
|
{/* Flip hint icon */}
|
|
248
176
|
<div className="absolute bottom-2 md:bottom-4 right-2 md:right-4 bg-black/30 p-1 md:p-2 rounded-full text-white/80 backdrop-blur-md opacity-0 group-hover:opacity-100 transition-opacity">
|
|
@@ -280,7 +208,7 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
280
208
|
</div>
|
|
281
209
|
|
|
282
210
|
{/* Agent info - Header Area */}
|
|
283
|
-
<div className="row-start-1 col-start-2 flex flex-col justify-center md:justify-start
|
|
211
|
+
<div className="w-full md:w-auto md:row-start-1 md:col-start-2 flex flex-col justify-center md:justify-start items-center md:items-start h-auto gap-4 md:gap-6 text-center md:text-left">
|
|
284
212
|
{/* Agent name with custom font */}
|
|
285
213
|
<h1
|
|
286
214
|
className="text-2xl md:text-5xl lg:text-6xl font-bold text-gray-900 tracking-tight leading-tight"
|
|
@@ -295,16 +223,16 @@ export function AgentProfile(props: AgentProfileProps) {
|
|
|
295
223
|
<p className="text-sm md:text-xl text-gray-700 max-w-lg leading-relaxed font-medium line-clamp-3 md:line-clamp-none">
|
|
296
224
|
{personaDescription}
|
|
297
225
|
</p>
|
|
226
|
+
|
|
227
|
+
<AgentCapabilityChips agent={agent} />
|
|
298
228
|
</div>
|
|
299
229
|
|
|
300
230
|
{/* Chat Area */}
|
|
301
|
-
<div className="
|
|
302
|
-
{children}
|
|
303
|
-
</div>
|
|
231
|
+
<div className="w-full md:col-span-1 md:col-start-2 mt-4 md:mt-0">{children}</div>
|
|
304
232
|
|
|
305
233
|
{/* Secondary Actions */}
|
|
306
234
|
{!isHeadless && (
|
|
307
|
-
<div className="
|
|
235
|
+
<div className="w-full md:col-span-1 md:col-start-2 flex flex-wrap justify-center md:justify-start items-center gap-4 md:gap-6 mt-4 md:mt-2">
|
|
308
236
|
{actions}
|
|
309
237
|
</div>
|
|
310
238
|
)}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Loader2 } from 'lucide-react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
type AgentProfileImageProps = {
|
|
5
|
+
readonly src: string;
|
|
6
|
+
readonly alt: string;
|
|
7
|
+
readonly className?: string;
|
|
8
|
+
readonly style?: React.CSSProperties;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function AgentProfileImage({ src, alt, className, style }: AgentProfileImageProps) {
|
|
12
|
+
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
|
13
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
let isMounted = true;
|
|
17
|
+
let timeoutId: NodeJS.Timeout;
|
|
18
|
+
let objectUrl: string | null = null;
|
|
19
|
+
|
|
20
|
+
const fetchImage = async () => {
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(src);
|
|
23
|
+
if (response.ok) {
|
|
24
|
+
const blob = await response.blob();
|
|
25
|
+
if (!isMounted) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
objectUrl = URL.createObjectURL(blob);
|
|
30
|
+
setImageSrc(objectUrl);
|
|
31
|
+
setIsLoading(false);
|
|
32
|
+
} else {
|
|
33
|
+
// Retry on non-200
|
|
34
|
+
if (isMounted) {
|
|
35
|
+
timeoutId = setTimeout(fetchImage, 2000);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.warn('Failed to fetch image, retrying...', error);
|
|
40
|
+
if (isMounted) {
|
|
41
|
+
timeoutId = setTimeout(fetchImage, 2000);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const isExternal = (() => {
|
|
47
|
+
try {
|
|
48
|
+
return new URL(src, window.location.href).origin !== window.location.origin;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
})();
|
|
53
|
+
|
|
54
|
+
if (isExternal) {
|
|
55
|
+
setImageSrc(src);
|
|
56
|
+
setIsLoading(false);
|
|
57
|
+
} else {
|
|
58
|
+
setIsLoading(true);
|
|
59
|
+
fetchImage();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return () => {
|
|
63
|
+
isMounted = false;
|
|
64
|
+
clearTimeout(timeoutId);
|
|
65
|
+
if (objectUrl) {
|
|
66
|
+
URL.revokeObjectURL(objectUrl);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}, [src]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className={`relative ${className}`} style={style}>
|
|
73
|
+
{/* Note: We apply style to the container, so backgroundImage works here */}
|
|
74
|
+
|
|
75
|
+
{isLoading && (
|
|
76
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
77
|
+
<Loader2 className="w-8 h-8 animate-spin text-white/50" />
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
|
|
81
|
+
{imageSrc && (
|
|
82
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
83
|
+
<img
|
|
84
|
+
src={imageSrc}
|
|
85
|
+
alt={alt}
|
|
86
|
+
className="w-full h-full object-cover"
|
|
87
|
+
// We don't pass style here because it is applied to container
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Color } from '../../../../../src/utils/color/Color';
|
|
2
|
+
import { darken } from '../../../../../src/utils/color/operators/darken';
|
|
3
|
+
import { lighten } from '../../../../../src/utils/color/operators/lighten';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import spaceTrim from 'spacetrim';
|
|
6
|
+
|
|
7
|
+
export function useAgentBackground(colorString: string | undefined) {
|
|
8
|
+
return useMemo(() => {
|
|
9
|
+
// [🧠] Default color should be imported constant, but for now hardcoded fallback
|
|
10
|
+
const PROMPTBOOK_COLOR_HEX = '#f15b24'; // TODO: Import PROMPTBOOK_COLOR
|
|
11
|
+
const brandColorString = colorString || PROMPTBOOK_COLOR_HEX;
|
|
12
|
+
|
|
13
|
+
let brandColor;
|
|
14
|
+
try {
|
|
15
|
+
brandColor = Color.fromSafe(brandColorString.split(',')[0].trim());
|
|
16
|
+
} catch {
|
|
17
|
+
brandColor = Color.fromHex(PROMPTBOOK_COLOR_HEX);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const brandColorHex = brandColor.toHex();
|
|
21
|
+
const brandColorLightHex = brandColor.then(lighten(0.2)).toHex();
|
|
22
|
+
const brandColorDarkHex = brandColor.then(darken(0.15)).toHex();
|
|
23
|
+
|
|
24
|
+
// Generate Noisy SVG Background
|
|
25
|
+
const color1 = brandColor;
|
|
26
|
+
// const color2 = brandColors[1] || brandColors[0]!; // Use secondary color if available?
|
|
27
|
+
// For simplicity using primary color for now or derive second one
|
|
28
|
+
const color2 = brandColor;
|
|
29
|
+
|
|
30
|
+
// [🧠] Make colors much lighter for the background
|
|
31
|
+
const color1Light = color1.then(lighten(0.3)).toHex();
|
|
32
|
+
const color1Main = color1.toHex();
|
|
33
|
+
const color1Dark = color1.then(darken(0.3)).toHex();
|
|
34
|
+
|
|
35
|
+
const color2Light = color2.then(lighten(0.3)).toHex();
|
|
36
|
+
const color2Main = color2.toHex();
|
|
37
|
+
const color2Dark = color2.then(darken(0.3)).toHex();
|
|
38
|
+
|
|
39
|
+
const svgContent = spaceTrim(`
|
|
40
|
+
<svg xmlns="http://www.w3.org/2000/svg"
|
|
41
|
+
viewBox="0 0 1920 1080"
|
|
42
|
+
width="1920" height="1080"
|
|
43
|
+
preserveAspectRatio="xMidYMid slice">
|
|
44
|
+
<defs>
|
|
45
|
+
<!-- Bottom-left -->
|
|
46
|
+
<radialGradient id="grad1" cx="0%" cy="100%" r="90%">
|
|
47
|
+
<stop offset="0%" stop-color="${color1Light}" />
|
|
48
|
+
<stop offset="50%" stop-color="${color1Main}" />
|
|
49
|
+
<stop offset="100%" stop-color="${color1Dark}" />
|
|
50
|
+
</radialGradient>
|
|
51
|
+
|
|
52
|
+
<!-- Bottom-right -->
|
|
53
|
+
<radialGradient id="grad2" cx="100%" cy="100%" r="90%">
|
|
54
|
+
<stop offset="0%" stop-color="${color2Light}" />
|
|
55
|
+
<stop offset="50%" stop-color="${color2Main}" />
|
|
56
|
+
<stop offset="100%" stop-color="${color2Dark}" />
|
|
57
|
+
</radialGradient>
|
|
58
|
+
|
|
59
|
+
<!-- White top fade -->
|
|
60
|
+
<linearGradient id="whiteTopGrad" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
61
|
+
<stop offset="0%" stop-color="#ffffff" stop-opacity="1" />
|
|
62
|
+
<stop offset="100%" stop-color="#ffffff" stop-opacity="0.3" />
|
|
63
|
+
</linearGradient>
|
|
64
|
+
|
|
65
|
+
<!-- Strong grain -->
|
|
66
|
+
<filter id="grain" x="-10%" y="-10%" width="120%" height="120%">
|
|
67
|
+
<feTurbulence type="fractalNoise" baseFrequency="3.5" numOctaves="3" seed="8" result="noise" />
|
|
68
|
+
<feComponentTransfer>
|
|
69
|
+
<feFuncR type="linear" slope="3.5" intercept="-1.2" />
|
|
70
|
+
<feFuncG type="linear" slope="3.5" intercept="-1.2" />
|
|
71
|
+
<feFuncB type="linear" slope="3.5" intercept="-1.2" />
|
|
72
|
+
<feFuncA type="table" tableValues="0 0.8" />
|
|
73
|
+
</feComponentTransfer>
|
|
74
|
+
</filter>
|
|
75
|
+
</defs>
|
|
76
|
+
|
|
77
|
+
<!-- White base -->
|
|
78
|
+
<rect width="100%" height="100%" fill="#ffffff" />
|
|
79
|
+
|
|
80
|
+
<!-- Gradients -->
|
|
81
|
+
<rect width="100%" height="100%" fill="url(#grad1)" />
|
|
82
|
+
<rect width="100%" height="100%" fill="url(#grad2)" style="mix-blend-mode:screen; opacity:0.85" />
|
|
83
|
+
|
|
84
|
+
<!-- White fade on top -->
|
|
85
|
+
<rect width="100%" height="100%" fill="url(#whiteTopGrad)" />
|
|
86
|
+
|
|
87
|
+
<!-- Strong visible noise -->
|
|
88
|
+
<rect width="100%" height="100%" filter="url(#grain)"
|
|
89
|
+
style="mix-blend-mode:soft-light; opacity:1.2" />
|
|
90
|
+
</svg>
|
|
91
|
+
`);
|
|
92
|
+
|
|
93
|
+
const backgroundImage = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`;
|
|
94
|
+
|
|
95
|
+
return { brandColorHex, brandColorLightHex, brandColorDarkHex, backgroundImage };
|
|
96
|
+
}, [colorString]);
|
|
97
|
+
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { useRouter } from 'next/navigation';
|
|
5
4
|
|
|
6
5
|
type AuthControlsProps = {
|
|
7
6
|
initialUser: { username: string; isAdmin: boolean } | null;
|
|
8
7
|
};
|
|
9
8
|
|
|
10
9
|
export function AuthControls({ initialUser }: AuthControlsProps) {
|
|
11
|
-
const router = useRouter();
|
|
12
|
-
const [user
|
|
10
|
+
// const router = useRouter();
|
|
11
|
+
const [user] = useState(initialUser);
|
|
13
12
|
const [isLoginOpen, setIsLoginOpen] = useState(false);
|
|
14
13
|
const [username, setUsername] = useState('');
|
|
15
14
|
const [password, setPassword] = useState('');
|
|
@@ -52,7 +51,9 @@ export function AuthControls({ initialUser }: AuthControlsProps) {
|
|
|
52
51
|
<div className="flex items-center space-x-4">
|
|
53
52
|
<span className="text-gray-600">
|
|
54
53
|
Logged in as <strong>{user.username}</strong>
|
|
55
|
-
{user.isAdmin &&
|
|
54
|
+
{user.isAdmin && (
|
|
55
|
+
<span className="ml-2 bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded">Admin</span>
|
|
56
|
+
)}
|
|
56
57
|
</span>
|
|
57
58
|
<button
|
|
58
59
|
onClick={handleLogout}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
type DeletedAgentBannerProps = {
|
|
4
|
+
message?: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function DeletedAgentBanner({
|
|
8
|
+
message = "This agent has been deleted. You can restore it from the Recycle Bin."
|
|
9
|
+
}: DeletedAgentBannerProps) {
|
|
10
|
+
return (
|
|
11
|
+
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
|
|
12
|
+
<div className="flex">
|
|
13
|
+
<div className="flex-shrink-0">
|
|
14
|
+
<svg className="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
|
15
|
+
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
|
16
|
+
</svg>
|
|
17
|
+
</div>
|
|
18
|
+
<div className="ml-3">
|
|
19
|
+
<p className="text-sm text-yellow-700">
|
|
20
|
+
{message}
|
|
21
|
+
</p>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Download, PrinterIcon } from 'lucide-react';
|
|
4
|
+
import Link from 'next/link';
|
|
5
|
+
import { OpenMojiIcon } from '../OpenMojiIcon/OpenMojiIcon';
|
|
6
|
+
|
|
7
|
+
export function DocsToolbar() {
|
|
8
|
+
return (
|
|
9
|
+
<div className="flex flex-wrap items-center justify-between gap-4 p-4 mb-8 bg-white rounded-xl shadow-sm border border-gray-100 print:hidden">
|
|
10
|
+
<div className="flex items-center gap-2">
|
|
11
|
+
<OpenMojiIcon icon="📚" className="text-2xl" />
|
|
12
|
+
<span className="font-semibold text-gray-700">Documentation</span>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div className="flex flex-wrap gap-2">
|
|
16
|
+
<button
|
|
17
|
+
onClick={() => window.print()}
|
|
18
|
+
className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
|
|
19
|
+
title="Print this page or save as PDF"
|
|
20
|
+
>
|
|
21
|
+
<PrinterIcon className="w-4 h-4" />
|
|
22
|
+
Print / Save as PDF
|
|
23
|
+
</button>
|
|
24
|
+
|
|
25
|
+
<Link
|
|
26
|
+
href="/api/docs/book.md"
|
|
27
|
+
download="book.md"
|
|
28
|
+
target="_blank"
|
|
29
|
+
className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-blue-700 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors"
|
|
30
|
+
title="Download raw Markdown documentation"
|
|
31
|
+
>
|
|
32
|
+
<Download className="w-4 h-4" />
|
|
33
|
+
Download Markdown
|
|
34
|
+
</Link>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|