diff --git a/docs/best-practices/index.mdx b/docs/best-practices/index.mdx index 74fd6afee5..6fbf4a2112 100644 --- a/docs/best-practices/index.mdx +++ b/docs/best-practices/index.mdx @@ -3,28 +3,14 @@ id: best-practices title: Best Practices --- -import BestPractices from '@site/src/components/ServiceCallouts'; -import ApplicationServices from '@site/src/components/ServiceCallouts/ApplicationServices'; -import DataAnalysisServices from '@site/src/components/ServiceCallouts/DataAnalysisServices'; -import ComputingServices from '@site/src/components/ServiceCallouts/ComputingServices'; -import ContainerServices from '@site/src/components/ServiceCallouts/ContainerServices'; -import DatabaseServices from '@site/src/components/ServiceCallouts/DatabaseServices'; -import ManagementServices from '@site/src/components/ServiceCallouts/ManagementServices'; -import NetworkingServices from '@site/src/components/ServiceCallouts/NetworkingServices'; -import SecurityServices from '@site/src/components/ServiceCallouts/SecurityServices'; -import StorageServices from '@site/src/components/ServiceCallouts/StorageServices'; -import clsx from 'clsx'; -import Heading from '@theme/Heading'; -import styles from './styles.module.css'; -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; + # Best Practices Welcome to the Open Telekom Cloud Architecture Center Best Practices. Here we provide crucial guidelines for optimizing cloud-based solutions with emphasis to architectural principles that enhance reliability, scalability, security, high availability and fault tolerance. - +{/* ## Open Telekom Cloud Services Portfolio @@ -106,4 +92,4 @@ enhance reliability, scalability, security, high availability and fault toleranc - \ No newline at end of file + */} \ No newline at end of file diff --git a/docusaurus.config.ts b/docusaurus.config.ts index b13b284a3c..4f09153d2e 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -36,13 +36,13 @@ const config: Config = { { docs: { sidebarPath: './sidebars.ts', - editUrl:'https://github.com/opentelekomcloud/docs-next/tree/main/', + editUrl: 'https://github.com/opentelekomcloud/docs-next/tree/main/', // showLastUpdateAuthor: true, // showLastUpdateTime: true, breadcrumbs: true, exclude: ['**/by-use-case/computing/**', '**/by-use-case/hybrid/**', '**/by-use-case/migration/**'] }, - + theme: { customCss: './src/css/custom.css', }, @@ -89,12 +89,12 @@ const config: Config = { label: 'Blueprints', }, { - to: '/templates', + to: '/templates', label: 'Templates', position: 'left', }, { - to: '/webinars', + to: '/webinars', label: 'Webinars', position: 'left', }, @@ -105,14 +105,14 @@ const config: Config = { // label: 'Cloud Adoption Framework 🚧', // }, // { to: '/blog', label: 'Blog', position: 'right' }, - { - href: 'https://auth.otc.t-systems.com/', + { + href: 'https://auth.otc.t-systems.com/', position: 'right', className: 'navbar--terminal-link', "aria-label": 'Open Telekom Cloud Console', }, - { - href: 'https://github.com/opentelekomcloud/docs-next', + { + href: 'https://github.com/opentelekomcloud/docs-next', position: 'right', className: 'navbar--github-link', "aria-label": 'GitHub', @@ -148,10 +148,18 @@ const config: Config = { label: 'Help Center', to: 'https://docs.otc.t-systems.com/', }, + { + label: 'Portfolio Navigator', + to: '/portfolio', + }, { label: 'Portfolio Roadmap', to: 'https://www.open-telekom-cloud.com/en/products-services/roadmap', }, + { + label: 'Release Notes', + to: 'https://www.open-telekom-cloud.com/en/support/release-notes', + }, { label: 'Core Services Certifications', to: 'https://www.open-telekom-cloud.com/en/products-services/core-services/certifications', @@ -166,7 +174,7 @@ const config: Config = { to: 'https://marketplace.otc.t-systems.com/', }, { - label: 'Community Forums', + label: 'Community Portal', to: 'https://community.open-telekom-cloud.com/', }, { diff --git a/package-lock.json b/package-lock.json index e539f1b19e..bbe8456ae4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,11 @@ "@docusaurus/preset-classic": "^3.7.0", "@mdx-js/react": "^3.1.0", "@telekom/scale-components": "^3.0.0-beta.151", + "@telekom/scale-components-react": "^3.0.0-beta.56", "clsx": "^2.1.1", "docusaurus-plugin-zooming": "^1.0.0", "docusaurus-theme-search-typesense": "^0.23.0", + "flag-icons": "^7.5.0", "lucide-react": "^0.525.0", "prism-react-renderer": "^2.4.1", "react": "^18.3.1", @@ -4894,9 +4896,10 @@ "integrity": "sha512-57BFgDxDkvOOrQf7wmS1u5jQmPRdhh6Y/qOHwTvYlS5GwGlkr3EeGeuwePL5pJ7z0jTnxEIVhmwbZnIx9AIX8w==" }, "node_modules/@telekom/scale-components": { - "version": "3.0.0-beta.151", - "resolved": "https://registry.npmjs.org/@telekom/scale-components/-/scale-components-3.0.0-beta.151.tgz", - "integrity": "sha512-CVqCJEBUW/15wrtzFUae6kTqZz13ZCCfaCrlPPYxWG+E6aavvEzPnZVROUAbXbKFfvMSsOV+zCcVDhMER27x9A==", + "version": "3.0.0-beta.156", + "resolved": "https://registry.npmjs.org/@telekom/scale-components/-/scale-components-3.0.0-beta.156.tgz", + "integrity": "sha512-H8Dml6tKjaCYDBXr4TWaGv5u457C9dMTm6ZuTnhWMzaQBESxK0lYOuUGrQmN1IiX8mHYSzjQuIpwIRlZ1nyrkw==", + "license": "MPL-2.0", "dependencies": { "@duetds/date-picker": "1.2.0", "@floating-ui/dom": "^1.2.8", @@ -4907,6 +4910,20 @@ "stencil-inline-svg": "^1.0.1" } }, + "node_modules/@telekom/scale-components-react": { + "version": "3.0.0-beta.56", + "resolved": "https://registry.npmjs.org/@telekom/scale-components-react/-/scale-components-react-3.0.0-beta.56.tgz", + "integrity": "sha512-FtCd4gyyriSbeN7nUAjHo6jtIFW7tpFTzqDXFCjtiNaGAHVxAI5YLmhH41yPP8704FshNB5M+dBsRqNXQst2kg==", + "license": "MPL-2.0", + "dependencies": { + "@types/react-dom": "^16.9.6", + "@types/vfile-message": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.13.1", + "react-dom": ">=16.13.1" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -5155,14 +5172,25 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "node_modules/@types/react": { - "version": "18.2.79", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", - "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", + "version": "16.14.65", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.65.tgz", + "integrity": "sha512-Guc3kE+W8LrQB9I3bF3blvNH15dXFIVIHIJTqrF8cp5XI/3IJcHGo4C3sJNPb8Zx49aofXKnAGIKyonE4f7XWg==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", + "@types/scheduler": "^0.16", "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "16.9.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.25.tgz", + "integrity": "sha512-ZK//eAPhwft9Ul2/Zj+6O11YR6L4JX0J2sVeBC9Ft7x7HFN7xk7yUV/zDxqV6rjvqgl6r8Dq7oQImxtyf/Mzcw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^16.0.0" + } + }, "node_modules/@types/react-router": { "version": "5.1.20", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", @@ -5206,6 +5234,12 @@ "@types/node": "*" } }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "license": "MIT" + }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -5246,6 +5280,16 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, + "node_modules/@types/vfile-message": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-2.0.0.tgz", + "integrity": "sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw==", + "deprecated": "This is a stub types definition. vfile-message provides its own type definitions, so you do not need this installed.", + "license": "MIT", + "dependencies": { + "vfile-message": "*" + } + }, "node_modules/@types/ws": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", @@ -9743,6 +9787,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flag-icons": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-7.5.0.tgz", + "integrity": "sha512-kd+MNXviFIg5hijH766tt+3x76ele1AXlo4zDdCxIvqWZhKt4T83bOtxUOOMlTx/EcFdUMH5yvQgYlFh1EqqFg==", + "license": "MIT" + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", diff --git a/package.json b/package.json index 38f97200de..749679dd6f 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,11 @@ "@docusaurus/preset-classic": "^3.7.0", "@mdx-js/react": "^3.1.0", "@telekom/scale-components": "^3.0.0-beta.151", + "@telekom/scale-components-react": "^3.0.0-beta.56", "clsx": "^2.1.1", "docusaurus-plugin-zooming": "^1.0.0", "docusaurus-theme-search-typesense": "^0.23.0", + "flag-icons": "^7.5.0", "lucide-react": "^0.525.0", "prism-react-renderer": "^2.4.1", "react": "^18.3.1", diff --git a/src/components/HomepageFeaturedServices/index.tsx b/src/components/HomepageFeaturedServices/index.tsx index 3404ff6ec9..b003687581 100644 --- a/src/components/HomepageFeaturedServices/index.tsx +++ b/src/components/HomepageFeaturedServices/index.tsx @@ -16,8 +16,8 @@ export default function HomepageFeaturedServices(): JSX.Element {

Check out our collection of technical solutions, best practices and cool tips for the most popular services of Open Telekom Cloud.

- - Explore our Best Practices + + Open Portfolio Navigator diff --git a/src/components/PortfolioNavigator/index.tsx b/src/components/PortfolioNavigator/index.tsx new file mode 100644 index 0000000000..a9c463d5b1 --- /dev/null +++ b/src/components/PortfolioNavigator/index.tsx @@ -0,0 +1,464 @@ +import React, { useMemo, useState, useRef, useEffect, KeyboardEvent } from "react"; +import styles from "./styles.module.css"; +import 'flag-icons/css/flag-icons.min.css'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + +export type OtcCategory = + | "Application" + | "Data Analysis" + | "Computing" + | "Containers" + | "Databases" + | "Management & Deployment" + | "Network" + | "Security Services" + | "Storage" + | "Finance Services" + | "Sites"; + +export type Chip = "IaaS" | "PaaS" | "SaaS" | "Security" | "Management" | "Docs" | "Product" | "Community"; +export type Region = "eu-de" | "eu-nl" | "eu-ch" | "global"; + +export type OtcService = { + id: string; + symbol: string; + name: string; + category: OtcCategory; + description: string; + hc_url?: string; + chips: Chip[]; + regions: Region[]; +}; + +const SERVICES: OtcService[] = [ + // Application + { id: "AOM", symbol: "AOM", name: "Application Operations Management", category: "Application", description: "Application Operations Management (AOM) is a one-stop, three-dimensional O&M management platform for cloud applications. It monitors your applications and related cloud resources in real time, collects and associates the data of resource metrics, logs, and events to analyze application health statuses, and provides flexible alarms and abundant data visualization functions. This helps you detect faults timely and master the real-time running statuses of applications, resources, and services.", hc_url: "https://docs.otc.t-systems.com/application-operations-management/index.html", chips: ["Management"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "APIG", symbol: "APIG", name: "API Gateway (APIG)", category: "Application", description: "API Gateway (APIG) is a high-performance, high-availability, and high-security API hosting service that helps you build, manage, and deploy APIs at any scale. With just a few clicks, you can integrate internal systems, and selectively expose capabilities with minimal costs and risks.", hc_url: "https://docs.otc.t-systems.com/api-gateway/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "APM", symbol: "APM", name: "Application Performance Management", category: "Application", description: "The Application Performance Management (APM) monitors and manages the performance of cloud applications in real time. APM provides performance analysis of distributed applications, helping O&M personnel quickly locate and resolve faults and performance bottlenecks.", hc_url: "https://docs.otc.t-systems.com/application-performance-management/index.html", chips: ["Management"], regions: ["eu-de", "eu-nl"] }, + { id: "DMS", symbol: "DMS", name: "Distributed Message Service", category: "Application", description: "Distributed Message Service (DMS) is a message middleware service based on distributed, high-availability clustering technology. It provides reliable, scalable, and fully managed queues for storing messages.", hc_url: "https://docs.otc.t-systems.com/distributed-message-service/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl"] }, + { id: "SMN", symbol: "SMN", name: "Simple Message Notification", category: "Application", description: "Simple Message Notification (SMN) is a hosted simple message notification service that is flexible and large-scale. SMN allows you to send messages to email addresses, and HTTP/HTTPS applications in an efficient and inexpensive way.", hc_url: "https://docs.otc.t-systems.com/simple-message-notification/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + + // "Data Analysis" + { id: "CSS", symbol: "CSS", name: "Cloud Search Service", category: "Data Analysis", description: "Cloud Search Service is a fully hosted distributed search service powered on Elasticsearch. It is fully compatible with Elasticsearch APIs and provides users with structured and unstructured data search, statistics, and report capabilities.", hc_url: "https://docs.otc.t-systems.com/cloud-search-service/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl"] }, + { id: "data-arts", symbol: "DataArts Studio", name: "DataArts Studio", category: "Data Analysis", description: "DataArts Studio is a one-stop data operations platform that drives digital transformation. It allows you to perform many operations, such as integrating and developing data, designing data architecture, controlling data quality, managing data assets, creating data services, and ensuring data security. Incorporating big data storage, computing and analytical engines, it can also construct industry knowledge bases and help your enterprise build an intelligent end-to-end data system. This system can eliminate data silos, unify data standards, accelerate data monetization, and accelerate your enterprise's digital transformation.", hc_url: "https://docs.otc.t-systems.com/data-arts-studio/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "DLI", symbol: "DLI", name: "Data Lake Insight", category: "Data Analysis", description: "Data Lake Insight (DLI) is a serverless data processing and analysis service fully compatible with Apache Spark and Apache Flink ecosystems. It frees you from managing any servers.", hc_url: "https://docs.otc.t-systems.com/data-lake-insight/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "DWS", symbol: "DWS", name: "Data Warehouse Service", category: "Data Analysis", description: "Data Warehouse Service (DWS) provides a scalable, fully hosted, and out-of-the-box data warehouse. It is compatible with the PostgreSQL ecosystem and supports standard SQL statements and BI tools to help you economically and efficiently mine and analyze massive volumes of data, greatly reducing your cost.", hc_url: "https://docs.otc.t-systems.com/data-warehouse-service/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "ModelArts", symbol: "ModelArts", name: "ModelArts", category: "Data Analysis", description: "ModelArts is a one-stop development platform for AI developers. With distributed training, automated model building, and model deployment, ModelArts helps AI developers build models quickly and manage the AI development lifecycle.", hc_url: "https://docs.otc.t-systems.com/modelarts/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "MRS", symbol: "MRS", name: "MapReduce Service", category: "Data Analysis", description: "MapReduce Service (MRS) provides enterprise-level big data clusters on the cloud, which are fully controlled by tenants and support the Hadoop, Spark, HBase, Kafka, and Storm components.", hc_url: "https://docs.otc.t-systems.com/mapreduce-service/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl"] }, + { id: "OCR", symbol: "OCR", name: "Optical Character Recognition", category: "Data Analysis", description: "Optical Character Recognition (OCR) detects and extracts text from images and converts the recognition results into an editable JSON format.", hc_url: "https://docs.otc.t-systems.com/optical-character-recognition/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + + // Computing + { id: "AS", symbol: "AS", name: "Auto Scaling", category: "Computing", description: "Auto Scaling (AS) is a service that automatically adjusts service resources based on your service requirements and configured AS policies. You can specify scaling configurations and policies based on service requirements. These configurations and policies free you from having to repeatedly adjust resources to keep up with service changes and demand spikes, helping you reduce resources required and manpower costs.", hc_url: "https://docs.otc.t-systems.com/auto-scaling/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "BMS", symbol: "BMS", name: "Bare Metal Services", category: "Computing", description: "A Bare Metal Server (BMS) is a physical server dedicated to individual tenants. It provides remarkable computing performance and stability for running key applications. The BMS service can be used in conjunction with other cloud services so that you can enjoy a consistent and stable performance of server hosting and the high scalability of cloud resources together that offer the computing performance and data security required by core databases, key application systems, high-performance computing (HPC), and Big Data.", hc_url: "https://docs.otc.t-systems.com/bare-metal-server/index.html", chips: ["IaaS"], regions: ["eu-de"] }, + { id: "DeH", symbol: "DeH", name: "Dedicated Host", category: "Computing", description: "Dedicated Host (DeH) is a service that provides dedicated physical hosts. You can create Elastic Cloud Servers (ECSs) on a DeH to enhance the isolation, security, and performance of your ECSs. When you migrate services to a DeH, you can continue to use your server software licenses used before the migration. That is, you can use the Bring Your License (BYOL) feature on the DeH to reduce costs and independently manage your ECSs.", hc_url: "https://docs.otc.t-systems.com/dedicated-host/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "ECS", symbol: "ECS", name: "Elastic Cloud Server", category: "Computing", description: "An ECS is a computing server consisting of CPUs, memory, images, and Elastic Volume Service (EVS) disks that allow on-demand allocation and elastic scaling. ECSs integrate virtual private cloud (VPC), virtual firewalls, and multi-data-copy capabilities to create an efficient, reliable, and secure computing environment. This ensures stable and uninterrupted operation of services.", hc_url: "https://docs.otc.t-systems.com/elastic-cloud-server/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "FGS", symbol: "FGS", name: "FunctionGraph", category: "Computing", description: "FunctionGraph allows to run a code without provisioning or managing servers, while ensuring high availability and scalability. All you need to do is to upload your code and set execution conditions. FunctionGraph will take care of the rest. In addition, you pay only for what you use and you are not charged when your code is not running.", hc_url: "https://docs.otc.t-systems.com/function-graph/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "IMS", symbol: "IMS", name: "Image Management Service", category: "Computing", description: "Image Management Service (IMS) provides flexible self-service and comprehensive image management capabilities. You can use a public image or create a private image to apply for an Elastic Cloud Server (ECS) or multiple ECSs in batches.", hc_url: "https://docs.otc.t-systems.com/image-management-service/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + + // Containers + { id: "ASM", symbol: "ASM", name: "Application Service Mesh", category: "Containers", description: "Application Service Mesh (ASM) is a service mesh platform based on Istio. It seamlessly interconnects with Cloud Container Engine (CCE), an enterprise-grade Kubernetes cluster service. With better usability, reliability, and visualization, ASM provides you with out-of-the-box features and enhanced user experience.", hc_url: "https://docs.otc.t-systems.com/application-service-mesh/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "CCE", symbol: "CCE", name: "Cloud Container Engine", category: "Containers", description: "CCE provides highly scalable, high-performance, enterprise-class Kubernetes clusters. It supports native Kubernetes applications, tools and easy setup of container runtime environment.", hc_url: "https://docs.otc.t-systems.com/cloud-container-engine/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "CCI", symbol: "CCI", name: "Cloud Container Instance", category: "Containers", description: "Cloud Container Instance (CCI) is a serverless container engine that allows you to run containers without creating or managing server clusters.", hc_url: "https://docs.otc.t-systems.com/cloud-container-instance/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "SWR", symbol: "SWR", name: "Software Repository for Containers", category: "Containers", description: "Software Repository for Container (SWR) provides full lifecycle container image management, which is easy-to-use, secure, and reliable. SWR enables users to uickly deploy containerized services.", hc_url: "https://docs.otc.t-systems.com/software-repository-container/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + + // Databases + { id: "DCS", symbol: "DCS", name: "Distributed Cache Service", category: "Databases", description: "Distributed Cache Service (DCS) is an online, distributed, in-memory cache service. It is reliable, scalable, usable out of the box, and easy to manage. DCS makes it easy to deploy, operate, and scale in-memory data caches in the cloud.", hc_url: "https://docs.otc.t-systems.com/distributed-cache-service/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl"] }, + { id: "DDM", symbol: "DDM", name: "Distributed Database Middleware", category: "Databases", description: "Distributed Database Middleware (DDM) removes database capacity and performance bottlenecks and resolves distributed expansion issues. It provides database and table sharding, read/write splitting, and elastic scaling, helping you handle highly concurrent access to massive volumes of data and improving database read/write performance.", hc_url: "https://docs.otc.t-systems.com/distributed-database-middleware/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "DDS", symbol: "DDS", name: "Document Database Service", category: "Databases", description: "Document Database Service (DDS) is a cloud computing-based NoSQL database featuring high performance storage, high availability architecture, and disaster recovery failover, along with online scaling, backup, and restoration capabilities. It has a mature performance monitoring system, a multi-level security protection mechanism, and a professional database management platform.", hc_url: "https://docs.otc.t-systems.com/document-database-service/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl"] }, + { id: "DRS", symbol: "DRS", name: "Data Replication Service", category: "Databases", description: "Data Replication Service (DRS) is a stable, efficient, and easy-to-use cloud service for database online migration and synchronization. It simplifies data migration processes and reduces migration costs. You can use DRS to quickly transmit data between databases in various scenarios.", hc_url: "https://docs.otc.t-systems.com/data-replication-service/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "GeminiDB", symbol: "GeminiDB", name: "GeminiDB", category: "Databases", description: "GeminiDB is a distributed, multi-model NoSQL database service with decoupled compute and storage architecture. This high availability database is secure and scalable, can be deployed, backed up, or restored quickly, and includes monitoring and alarm management.", hc_url: "https://docs.otc.t-systems.com/geminidb/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + { id: "RDS", symbol: "RDS", name: "Relational Database Service", category: "Databases", description: "Relational Database Service (RDS) is an online relational database service based on the cloud computing platform. The RDS is reliable, scalable, secure, and easy to manage, allowing you to deploy a database within minutes.", hc_url: "https://docs.otc.t-systems.com/relational-database-service/index.html", chips: ["PaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "TaurusDB", symbol: "TaurusDB", name: "TaurusDB", category: "Databases", description: "TaurusDB is the latest generation enterprise-class distributed database. It is fully compatible with MySQL and provides high scalability and massive storage capacity. It uses a decoupled compute and storage architecture and supports up to 128 TB of storage. With TaurusDB, there is no need to deal with sharding, and no need to worry about data loss. It combines the performance and availability of commercial databases with the cost-effectiveness of open source databases.", hc_url: "https://docs.otc.t-systems.com/taurusdb/index.html", chips: ["PaaS"], regions: ["eu-de"] }, + + // Management & Deployment + { id: "CloudCreate", symbol: "Cloud Create", name: "Cloud Create", category: "Management & Deployment", description: "Cloud Create is a free-to-use Development and Management Platform, which enables cloud developers to create applications on Open Telekom Cloud fast.", hc_url: "https://docs.otc.t-systems.com/cloud-create/index.html", chips: ["SaaS"], regions: ["eu-de", "eu-ch"] }, + { id: "CloudEye", symbol: "Cloud Eye", name: "Cloud Eye", category: "Management & Deployment", description: "Cloud Eye is a multi-dimensional monitoring platform that monitors your resources such as ECS and bandwidth. With Cloud Eye, users can fully understand the resource usage and running status of services running on the cloud platform, receive alarm notifications in a timely manner, and make response to ensure smooth running of services.", hc_url: "https://docs.otc.t-systems.com/cloud-eye/index.html", chips: ["Management"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "Config", symbol: "Config", name: "Config", category: "Management & Deployment", description: "With Config, you can search for, record, and continuously evaluate your resource configuration to make sure that your expectations are met.", hc_url: "https://docs.otc.t-systems.com/config/index.html", chips: ["Management"], regions: ["eu-de"] }, + { id: "CTS", symbol: "CTS", name: "Cloud Trace Service", category: "Management & Deployment", description: "Cloud Trace Service (CTS) provides operation records for cloud service resources. The operation records include resource operation requests initiated from the public cloud management console or open APIs and responses to the requests. You can query, audit, and backtrack the operation records. In addition, you can use the Object Storage Service (OBS) to synchronize operation records to the OBS buckets.", hc_url: "https://docs.otc.t-systems.com/cloud-trace-service/index.html", chips: ["Management"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "LTS", symbol: "LTS", name: "Log Tank Service", category: "Management & Deployment", description: "Log Tank Service (LTS) stores logs, allowing you to query and transfer them in real time. It simplifies real-time analysis for decision making and improves log processing efficiency.", hc_url: "https://docs.otc.t-systems.com/log-tank-service/index.html", chips: ["Management"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "RFS", symbol: "RFS", name: "Resource Formation Service", category: "Management & Deployment", description: "With Resource Formation Service, you can manage system and service resources (all physical or logical entities that can be located and described, such as databases, VPCs, pipelines, and IAM roles). You can automatically deploy specified cloud service resources based on the template which uses the HCL (an open ecosystem) syntax.", hc_url: "https://docs.otc.t-systems.com/resource-formation-service/index.html", chips: ["Management"], regions: ["eu-de"] }, + { id: "TMS", symbol: "TMS", name: "Tag Management Service", category: "Management & Deployment", description: "Tag Management Service (TMS) is a visualized service for fast, unified tag management that enables you to control your resource permissions and billing more efficiently. It allows you to tag and categorize cloud services across regions, and it can be accessed through the TMS console or using APIs.", hc_url: "https://docs.otc.t-systems.com/tag-management-service/index.html", chips: ["Management"], regions: ["eu-de", "eu-ch"] }, + + // Network + { id: "DirectConnect", symbol: "Direct Connect", name: "Dedicated Network Connection", category: "Network", description: "A Direct Connect is a service that allows you to establish a dedicated network connection from your data center to the public cloud platform. You can establish a private connection between the public cloud platform and your data center, office, or collocation environment, which can reduce your network latency and provide a more consistent network experience than Internet-based connections.", hc_url: "https://docs.otc.t-systems.com/direct-connect/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "DNS", symbol: "DNS", name: "Domain Name Service", category: "Network", description: "Domain Name Service (DNS) provides highly available and scalable authoritative DNS resolution services and domain name management services. It translates domain names or application resources into IP addresses required for network connection. By doing so, visitor's access requests are directed to the desired resources.", hc_url: "https://docs.otc.t-systems.com/domain-name-service/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-ch"] }, + { id: "EIP", symbol: "EIP", name: "Elastic IP", category: "Network", description: "An EIP is a static, public IP address. You can bind an EIP to an ECS in your subnet to enable the ECS in your VPC to communicate with the Internet through a fixed public IP address.", hc_url: "https://docs.otc.t-systems.com/elastic-ip/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "ELB", symbol: "ELB", name: "Elastic Load Balancing", category: "Network", description: "Elastic Load Balancing (ELB) is a service that automatically distributes access traffic to multiple Elastic Cloud Servers (ECSs) to balance their service load. ELB enables you to achieve higher levels of fault tolerance in your applications and expand application service capabilities.", hc_url: "https://docs.otc.t-systems.com/elastic-load-balancing/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "ER", symbol: "ER", name: "Enterprise Router", category: "Network", description: "An Enterprise Router is a cloud router service that connects your VPCs and on-premises networks.", hc_url: "https://docs.otc.t-systems.com/enterprise-router/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl"] }, + { id: "NATGW", symbol: "NATGW", name: "NAT Gateway", category: "Network", description: "The NAT Gateway service offers the Network Address Translation (NAT) function for computing instances, such as Elastic Cloud Servers (ECSs), in a Virtual Private Cloud (VPC), allowing these computing instances to access the Internet using elastic IP addresses (EIPs).", hc_url: "https://docs.otc.t-systems.com/nat-gateway/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "PLAS", symbol: "PLAS", name: "Private Link Access Service", category: "Network", description: "Private Link Access Service (PLAS) enables public cloud platform users to establish exclusive connections from their on-premise networks to VPCs on the public cloud platform.PLAS connections are established between carrier networks and Direct Connect gateways, reducing network latency. These connections outperform Internet connections in stability and security.", hc_url: "https://docs.otc.t-systems.com/private-link-access-service/index.html", chips: ["IaaS"], regions: ["eu-de"] }, + { id: "smg", symbol: "SMG", name: "Secure Mail Gateway", category: "Network", description: "The Secure Mail Gateway service provides anti-spam and anti-junk functions for outgoing email traffic and prevents EIPs from being blacklisted or abused.", hc_url: "https://docs.otc.t-systems.com/secure-mail-gateway/index.html", chips: ["Security"], regions: ["eu-de"] }, + { id: "VPC", symbol: "VPC", name: "Virtual Private Cloud", category: "Network", description: "The Virtual Private Cloud (VPC) service enables you to provision logically isolated, configurable, and manageable virtual networks for Elastic Cloud Servers (ECSs), improving the security of resources in the cloud system and simplifying network deployment.", hc_url: "https://docs.otc.t-systems.com/virtual-private-cloud/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "VPCEP", symbol: "VPCEP", name: "Virtual Private Cloud Endpoint", category: "Network", description: "The VPC Endpoint (VPCEP) service provides secure and private channels to connect your VPC to VPC endpoint services (cloud services on the current platform or your private services), providing flexible networking without having to use EIPs.", hc_url: "https://docs.otc.t-systems.com/vpc-endpoint/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "VPN", symbol: "VPN", name: "Virtual Private Network", category: "Network", description: "A virtual private network (VPN) establishes an encrypted communication tunnel between a remote user and a Virtual Private Cloud (VPC). With VPN, you can connect to a VPC and access service resources in it.", hc_url: "https://docs.otc.t-systems.com/virtual-private-network/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + + // Security Services + { id: "Anti-DDoS", symbol: "Anti-DDoS", name: "Anti-DDoS Service", category: "Security Services", description: "The Anti-DDoS traffic cleaning service (Anti-DDoS for short) is a network security service that defends IP addresses against distributed denial of service (DDoS) attacks.", hc_url: "https://docs.otc.t-systems.com/anti-ddos/index.html", chips: ["Security"], regions: ["eu-de", "eu-nl"] }, + { id: "CFW", symbol: "CFW", name: "Cloud Firewall", category: "Security Services", description: "Cloud Firewall (CFW) is a next-generation cloud-native firewall. It protects Internet and VPC borders on the cloud by real-time intrusion detection and prevention, global unified access control, full traffic analysis, log audit, and tracing. It employs AI for intelligent defense, and can be elastically scaled to meet changing business needs, helping you easily handle security threats. CFW is a basic service that provides network security protection for user services on the cloud.", hc_url: "https://docs.otc.t-systems.com/cloud-firewall/index.html", chips: ["Security"], regions: ["eu-de"] }, + { id: "DSS", symbol: "DSS", name: "Database Security Service", category: "Security Services", description: "Database Security Service (DBSS) uses machine learning and big data technologies to protect your databases on the cloud, intelligently auditing them and detecting risky behaviors like SQL injection.", hc_url: "https://docs.otc.t-systems.com/database-security-service/index.html", chips: ["Security"], regions: ["eu-de"] }, + { id: "HSS", symbol: "HSS", name: "Host Security Service", category: "Security Services", description: "Host Security Service (HSS) defends your Linux and Windows cloud servers from the inside out, with a suite of advanced security features including powerful brute-force protection, intrusion detection monitoring, and vulnerability fixes.", hc_url: "https://docs.otc.t-systems.com/host-security-service/index.html", chips: ["Security"], regions: ["eu-de"] }, + { id: "IAM", symbol: "IAM", name: "Identity & Access Management", category: "Security Services", description: "Identity and Access Management (IAM) provides a public cloud system (Open Telekom Cloud) with user identity management and access control.You can use IAM to manage user accounts (such as employee, system or application program accounts) and control the operation permissions of these user accounts on your resources (such as computing, storage, and network resources). In this way, IAM prevents these accounts from sharing your password or access key with other users. IAM also ensures user account security and reduces security risks for your enterprise information by allowing you to set login verification policies, password policies, and an access control list (ACL).", hc_url: "https://docs.otc.t-systems.com/identity-access-management/index.html", chips: ["Security"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "KMS", symbol: "KMS", name: "Key Management Service", category: "Security Services", description: "Key Management Service (KMS) is a secure, reliable, and easy-to-use service that helps users centrally manage and safeguard their Customer Master Keys (CMKs).", hc_url: "https://docs.otc.t-systems.com/key-management-service/index.html", chips: ["Security"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "WAF", symbol: "WAF", name: "Web Application Firewall", category: "Security Services", description: "Web Application Firewall (WAF) keeps web services stable and secure. It examines all HTTP and HTTPS requests to detect and block the following attacks: Structured Query Language (SQL) injection, cross-site scripting (XSS), webshells, command and code injections, file inclusion, sensitive file access, third-party vulnerability exploits, Challenge Collapsar (CC) attacks, malicious crawlers, and cross-site request forgery (CSRF).", hc_url: "https://docs.otc.t-systems.com/web-application-firewall/index.html", chips: ["Security"], regions: ["eu-de", "eu-nl"] }, + { id: "DWAF", symbol: "DWAF", name: "Dedicated Web Application Firewall", category: "Security Services", description: "Web Application Firewall (WAF) keeps web services stable and secure. It examines all HTTP and HTTPS requests to detect and block the following attacks: Structured Query Language (SQL) injection, cross-site scripting (XSS), webshells, command and code injections, file inclusion, sensitive file access, third-party vulnerability exploits, Challenge Collapsar (CC) attacks, malicious crawlers, and cross-site request forgery (CSRF).", hc_url: "https://docs.otc.t-systems.com/web-application-firewall-dedicated/index.html", chips: ["Security"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + + // Storage + { id: "CBR", symbol: "CBR", name: "Cloud Backup & Recovery", category: "Storage", description: "Cloud Backup and Recovery (CBR) allows you to back up cloud disks, elastic cloud servers, and bare metal servers, protecting the security and accuracy of your data to the greatest extent for service security.", hc_url: "https://docs.otc.t-systems.com/cloud-backup-recovery/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "CSBS", symbol: "CSBS", name: "Cloud Server Backup Service", category: "Storage", description: "Cloud Server Backup Service (CSBS) offers the backup protection service for Elastic Cloud Servers (ECSs). It works based on the consistent snapshot technology for Elastic Volume Service (EVS) disks. With CSBS, you can use backup data to restore ECS data.", hc_url: "https://docs.otc.t-systems.com/cloud-server-backup-service/index.html", chips: ["IaaS"], regions: ["eu-de"] }, + { id: "EVS", symbol: "EVS", name: "Elastic Volume Service", category: "Storage", description: "Elastic Volume Service (EVS) offers scalable block storage for servers. With high reliability, high performance, and rich specifications, EVS disks can be used for distributed file systems, development and testing environments, data warehouse applications, and high-performance computing (HPC) scenarios to meet diverse service requirements.", hc_url: "https://docs.otc.t-systems.com/elastic-volume-service/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "OBS", symbol: "OBS", name: "Object Storage Service", category: "Storage", description: "Object Storage Service (OBS) is an object-based storage service that provides customers with massive, secure, reliable, and cost-effective data storage capabilities, such as bucket creation, modification, and deletion, as well as object upload, download, and deletion.", hc_url: "https://docs.otc.t-systems.com/object-storage-service/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "SDRS", symbol: "SDRS", name: "Storage Disaster Recovery Service", category: "Storage", description: "Storage Disaster Recovery Service (SDRS) provides disaster recovery (DR) services for many cloud services, such as Elastic Cloud Server (ECS) and Elastic Volume Service (EVS). SDRS uses multiple technologies, such as storage replication, data redundancy, and cache acceleration, to provide high data reliability and service continuity for users.", hc_url: "https://docs.otc.t-systems.com/storage-disaster-recovery-service/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl", "eu-ch"] }, + { id: "SFS", symbol: "SFS", name: "Scalable File Service", category: "Storage", description: "Scalable File Service (SFS) provides high-performance file storage that is scalable on demand. It can be shared with multiple Elastic Cloud Servers (ECS).", hc_url: "https://docs.otc.t-systems.com/scalable-file-service/index.html", chips: ["IaaS"], regions: ["eu-de", "eu-nl"] }, + { id: "VBS", symbol: "VBS", name: "Volume Backup Service", category: "Storage", description: "Volume Backup Service (VBS) provides snapshot-based data protection service for Elastic Volume Service (EVS) disks. You can perform one-click backup and restoration for the EVS disks on Elastic Cloud Servers (ECSs) all through the online platform.", hc_url: "https://docs.otc.t-systems.com/volume-backup-service/index.html", chips: ["IaaS"], regions: ["eu-de"] }, + + // Finance Services + { id: "ED", symbol: "ED", name: "Enterprise Dashboard", category: "Finance Services", description: "The Enterprise Dashboard (ED) helps you keep track of your cloud consumption data, as well as all billing information and financial metrics.", hc_url: "https://enterprise-dashboard.otc-service.com/", chips: ["Management"], regions: ["global"] }, + // { id: "INV", symbol: "INV", name: "Invoicing", category: "Finance Services", description: "", hc_url: "", chips: ["Management"], regions: ["global"] }, + + // Sites Services + { id: "AC", symbol: "AC", name: "Architecture Center", category: "Sites", description: "The Architecture Center for Open Telekom Cloud, is a knowledge-hub designed to guide architects, developers, and IT teams in building secure, scalable, and efficient cloud solutions. It provides curated best practices, detailed reference architectures, and blueprints for common workloads and use cases. The platform offers infrastructure templates in formats like Terraform and TOSCA to accelerate deployment and ensure consistency. Users can explore architectural guidance for networking, storage, compute, and security. The site focuses on reliability, compliance, and sustainability to meet enterprise and public sector needs. It serves as a central resource for designing and operating solutions on Open Telekom Cloud effectively.", hc_url: "https://arch.otc-service.com/", chips: ["Docs"], regions: ["global"] }, + { id: "HC", symbol: "HC", name: "Help Center", category: "Sites", description: "Help Center is the official documentation hub for Open Telekom Cloud, offering comprehensive user and developer guidance. It covers a full range of cloud services—including compute, storage, networking, application, data analysis, containers, databases, management, security, and more—with detailed API references, user guides, SDKs, and infrastructure-as-code resources. The site also includes developer-focused content like REST API guidance, SDK usage, automation tools, architecture best practices, regional endpoints, a glossary, FAQs, release notes, and status dashboards.", hc_url: "https://docs.otc.t-systems.com/", chips: ["Docs"], regions: ["global"] }, + { id: "OTC", symbol: "OTC", name: "Open Telekom Cloud", category: "Sites", description: "Open Telekom Cloud, powered by Deutsche Telekom's T-Systems, is a European public cloud platform built on OpenStack. It offers secure, GDPR-compliant infrastructure services—including compute, storage, networking, and AI—from data centers in Germany, the Netherlands, and Switzerland. Designed for scalability and sovereignty, it supports enterprises and public organizations with flexible pricing, strong certifications, and 24/7 expert support.", hc_url: "https://open-telekom-cloud.com/en", chips: ["Product"], regions: ["global"] }, + { id: "CP", symbol: "CP", name: "Community Portal", category: "Sites", description: "The Open Telekom Cloud Community is a user-driven forum where developers, architects, and users can share experiences, ask questions, find help, and discover blog entries and webinars. Serving as a practical support channel, it gathers collective knowledge to help with real-world cloud challenges and foster expert-to-user interactions.", hc_url: "https://community.open-telekom-cloud.com/", chips: ["Community"], regions: ["global"] }, + { id: "Console", symbol: "Console", name: "Open Telekom Cloud Console", category: "Sites", description: "The Open Telekom Cloud Console is a web-based management interface that provides users with centralized access to all Open Telekom Cloud services and resources. It enables administrators and developers to create, configure, and monitor compute, storage, network, and security services through an intuitive dashboard. The console supports project-based organization, fine-grained identity and access management, and real-time resource monitoring. Designed for usability and transparency, the console offers a unified platform to manage infrastructure, automate workflows, and ensure compliance.", hc_url: "https://auth.otc.t-systems.com/", chips: ["Management"], regions: ["global"] }, + { id: "SD", symbol: "SD", name: "Status Dashboard", category: "Sites", description: "Status Dashboard is the official service status dashboard for Open Telekom Cloud. It provides real-time information on the availability and performance of all cloud services across regions, helping users quickly identify incidents or maintenance activities. The site offers clear service indicators, detailed incident updates, and regional views, ensuring transparency and operational awareness for customers and administrators.", hc_url: "https://status.otc-service.com/", chips: ["Product"], regions: ["global"] }, + +]; + +export default function OtcServicesColumns() { + const [query] = useState(""); + const [chips, setChips] = useState>(new Set()); // OR + const [regionsSel, setRegionsSel] = useState>(new Set()); // OR + const [open, setOpen] = useState(null); // ← sleeve + // NEW: category filter state + options + const ALL_CATS = Array.from(new Set(SERVICES.map(s => s.category))).sort(); + const [categoryFilter, setCategoryFilter] = useState("all"); + const OTC_CATEGORY_OPTIONS: string[] = ["all", ...ALL_CATS]; + const noDataImg = useBaseUrl('/img/undraw_no-data_ig65.svg'); + + const toggleChip = (c: Chip) => + setChips((prev) => { + const next = new Set(prev); + if (next.has(c)) { + next.delete(c); + } else { + next.add(c); + } + return next; + }); + + const toggleRegion = (r: Region) => + setRegionsSel((prev) => { + const next = new Set(prev); + if (next.has(r)) { + next.delete(r); + } else { + next.add(r); + } + return next; + }); + + const categorySelectRef = useRef(null); + + useEffect(() => { + const el = categorySelectRef.current; + if (!el) return; + + const onChange = (e: Event) => { + // SCALE emits CustomEvent with { detail: { value } } + const value = (e as CustomEvent).detail?.value ?? "all"; + setCategoryFilter(value); + }; + + el.addEventListener("scale-change", onChange); + // Some builds also dispatch a native 'change' — safe to listen to both: + el.addEventListener("change", onChange); + + return () => { + el.removeEventListener("scale-change", onChange); + el.removeEventListener("change", onChange); + }; + }, []); + + const resetFilters = () => { + // 1) category -> "all" + setCategoryFilter("all"); + + // 2) chips + regions -> unchecked + // Use your existing setters for those two pieces of state. + // (If your state uses arrays, set [] instead of new Set().) + setChips?.(new Set()); // existing chips state + setRegionsSel?.(new Set()); // existing regions state + }; + + const isChipActive = (c: Chip) => chips.has(c); + const isRegionActive = (r: Region) => regionsSel.has(r); + + // React ONLY to chip toggles via capture; block the component's own handler to avoid double-toggles + const onChipRowClickCapture = (e: React.MouseEvent) => { + const host = (e.target as HTMLElement)?.closest("scale-chip") as HTMLElement | null; + if (!host) return; + const id = host.getAttribute("data-chip") as Chip | null; + if (!id) return; + e.preventDefault(); + e.stopPropagation(); + toggleChip(id); + }; + + const onRegionRowClickCapture = (e: React.MouseEvent) => { + const host = (e.target as HTMLElement)?.closest("scale-chip") as HTMLElement | null; + if (!host) return; + const id = host.getAttribute("data-region") as Region | null; + if (!id) return; + e.preventDefault(); + e.stopPropagation(); + toggleRegion(id); + }; + + // text + chips(OR) + regions(OR). If none selected -> show all. + const filtered = useMemo(() => { + const q = query.trim().toLowerCase(); + return SERVICES.filter((s) => { + const mq = + !q || + s.name.toLowerCase().includes(q) || + s.symbol.toLowerCase().includes(q) || + s.category.toLowerCase().includes(q); + if (!mq) return false; + + if (chips.size > 0 && !s.chips.some((c) => chips.has(c))) return false; + if (regionsSel.size > 0 && !s.regions.some((r) => regionsSel.has(r))) return false; + + if ( + categoryFilter !== "all" && + s.category !== categoryFilter + ) { + return false; + } + + return true; + }); + }, [query, chips, regionsSel, categoryFilter]); + + // open sleeve on Enter/Space as well + function onTileKey(e: KeyboardEvent, s: OtcService) { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + setOpen(s); + } + } + + const renderRegionChip = (region: Region) => { + if (region === "global") return null; + + const cls = + region === "eu-de" ? "fi fi-de" : + region === "eu-nl" ? "fi fi-nl" : + region === "eu-ch" ? "fi fi-ch fis" : ""; + + return ( + + ); + }; + + const renderRegionFooter = (region: Region) => { + if (region === "global") { + return GLOBAL; + } + + const cls = + region === "eu-de" ? "fi fi-de" : + region === "eu-nl" ? "fi fi-nl" : + region === "eu-ch" ? "fi fi-ch fis" : ""; + + return ( + + ); + }; + + return ( +
+
+
+
{/* heading removed intentionally */}
+
+ {/* Filters: categories (single line) */} +
+
+ + {OTC_CATEGORY_OPTIONS.map((opt) => ( + + {opt === "all" ? "All Categories" : opt} + + ))} + + + Reset Filters + +
+ +
+ + {/* Filters: chips | regions (single line) */} +
+ {/* Capability chips (SCALE) */} +
+ {(["IaaS", "PaaS", "SaaS", "Security", "Management"] as Chip[]).map((c) => ( + + {c} + + ))} +
+ + + + {/* Region chips (SCALE) */} +
+ {(["eu-de", "eu-nl", "eu-ch", "global"] as Region[]).map((r) => ( + + {renderRegionChip(r)} + {` ${r.toUpperCase()}`} + + ))} +
+
+ + + {/* Grid */} +
+ {filtered.length === 0 ? ( +
+
+ +

No results match your filters.

+
+
+ + ) : ( + filtered.map((s) => ( +
setOpen(s)} + onKeyDown={(e) => onTileKey(e, s)} + role="button" + tabIndex={0} + > +
+ {s.category} + {s.chips} +
+
{s.name}
+
+
+ {s.regions.map((r) => ( + + {renderRegionFooter(r)} + + ))} +
+ {/* {s.hc_url && ( + + Docs + + )} */} +
+
+ )) + )} +
+
+ + {/* Sleeve */} + {open && ( +
setOpen(null)} role="dialog" aria-modal="true"> +
e.stopPropagation()}> + + +

+
+
{open.symbol}:
+
{open.name}
+
+ +
+ {open.description?.trim() ? open.description : "No description available."} +
+ + {open.category === "Finance Services" || open.category === "Sites" ? ( +
+ + Go to {open.name} + + +
+ ) : ( +
+ + Discover Blueprints + + + + + Go to Help Center + + +
+ )} +
+ +
+ ) + } +
+ ); +} diff --git a/src/components/PortfolioNavigator/styles.module.css b/src/components/PortfolioNavigator/styles.module.css new file mode 100644 index 0000000000..ba3aa50adb --- /dev/null +++ b/src/components/PortfolioNavigator/styles.module.css @@ -0,0 +1,573 @@ +:root{ + /* --bg: #f8fafc; */ + /* --panel: #ffffff; */ + /* --ink: #0f172a; */ + --muted: #475569; + --line: #e2e8f0; + --chip: #f1f5f9; + --chip-ink: #0f172a; + --chip-active: #111827; + --chip-active-ink: #fff; + --badge: #eef2ff; + --badge-ink: #3730a3; + --tile-radius: 4px; + --shadow: 0 1px 2px rgba(0,0,0,.06), 0 2px 4px rgba(0,0,0,.06); + --colW: 280px; /* base column width for smaller screens */ + --card-bg: #fff; + --card-border: #ddd; + --text-base: #000; + --text-muted: #444; + --text-weak: #999; + --shadow-hover: rgba(0, 0, 0, 0.1); +} + +*{box-sizing:border-box} +body{color:var(--ink)} + +.otcWrap{min-height:100vh;background:linear-gradient(#fff, var(--bg));padding:24px} +.otcMax{max-width:1280px;margin:0 auto} + +/* header */ +.header{display:flex;gap:16px;flex-wrap:wrap;align-items:flex-end;justify-content:space-between} +.titleBlock h1{margin:0;font-weight:700;font-size:clamp(24px,3vw,34px)} +.titleBlock p{margin:.25rem 0 0;color:var(--muted)} +.ctrls{display:flex;gap:12px;align-items:center} + +/* search */ +.search{position:relative} +.searchIcon{position:absolute;left:10px;top:50%;transform:translateY(-50%);opacity:.45} +.search input{ + height:36px; /* ↑ was 34 */ + width:260px;max-width:58vw;padding:8px 10px 8px 28px; + border:1px solid var(--line);border-radius:10px;outline:none;font-size:15px; /* ↑ was 14px */ +} +.search input:focus{border-color:#818cf8; box-shadow:0 0 0 3px rgba(129,140,248,.25)} + +.viewchip{display:inline-flex;align-items:center;gap:6px;background:#eef2ff;border:1px solid #e0e7ff;color:#3730a3;padding:6px 10px;border-radius:999px;font-size:13px} + +/* chips */ +.bucketsChips{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px} +.bucketsRegions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px } + +.chip{background:var(--chip);color:var(--chip-ink);border:1px solid var(--line);padding:4px 10px;border-radius:999px;font-size:13px;cursor:pointer} /* ↑ was 12px */ +.chipActive{background:var(--chip-active);color:var(--chip-active-ink);border-color:var(--chip-active)} + +.flags { + background: transparent; + border: 0; + padding: 7px 0 3px 0; + box-shadow: none; + font-size: 11px; + line-height: 1; +} + +.flags span { + padding: 0 4px 0 0; /* Changed from left padding to right padding */ +} + +/* Remove the .flag class since it's not being used */ + +/* columns (wrap on small screens; fixed 3 even columns on desktop) */ +.columns{ + display:grid; gap:10px; margin-top:10px; + grid-template-columns: repeat(auto-fit, minmax(var(--colW), 1fr)); + justify-content:stretch; +} + +/* Desktop: exactly 9 columns per row (your current setting) */ +@media (min-width: 1200px) { + .columns { + grid-template-columns: repeat(9, minmax(0, 1fr)); + gap:10px; + } +} + +/* Column container — borderless & compact */ +.col{ + position:relative; + background:transparent; /* remove panel */ + border:none; /* remove frame */ + border-radius:16px; + overflow:hidden; + box-shadow:none; +} +.col::before{content:""; position:absolute; inset:0; background:var(--stripe, transparent); opacity:0; pointer-events:none} /* hide stripe */ +.colHead{ + position:sticky; top:0; + background:transparent; /* lighter header */ + border-bottom:1px solid var(--line); + padding:6px 8px; font-weight:700; letter-spacing:.2px; color:var(--ink); z-index:1; + font-size:16px; /* ↑ was 15px */ +} +.colTitle{white-space:nowrap; overflow:hidden; text-overflow:ellipsis} +.colBody{display:flex; flex-direction:column; gap:8px; padding:8px 2px; min-height:100px} +.empty{ + border:1px dashed var(--line); border-radius:12px; padding:14px; + text-align:center; color:var(--muted); background:#fbfcfe; +} + +html[data-theme='dark'] .empty{ + border:1px dashed var(--ifm-color-emphasis-200); border-radius:12px; padding:14px; + text-align:center; color:var(--ifm-color-emphasis-400); background:var(--ifm-background-surface-color); +} + +/* tile */ +.tile{ + /* --accent: #e2e8f0; */ + background:var(--panel);border:1px solid var(--line);border-radius:10px; + border: 1px solid var(--card-border, var(--ifm-color-emphasis-200)); + padding:8px;display:flex;flex-direction:column;box-shadow:var(--shadow); + cursor:pointer;position:relative;transition:transform .15s ease, box-shadow .15s ease; + box-shadow: var(--shadow), inset 0 2px 0 var(--accent); +} + +html[data-theme='dark'] .tile{ + /* --accent: #e2e8f0; */ + background:var(--ifm-background-surface-color);border:1px solid var(--ifm-color-emphasis-200);border-radius:10px; + padding:8px;display:flex;flex-direction:column;box-shadow:var(--shadow); + cursor:pointer;position:relative;transition:transform .15s ease, box-shadow .15s ease; + box-shadow: var(--shadow), inset 0 2px 0 var(--accent); +} +.tile:hover { + text-decoration: none; + box-shadow: + 0px 16px 64px 0px var(--shadow-hover, var(--telekom-shadow-raised-hover)), + 0px 8px 16px 0px var(--shadow-hover, var(--telekom-shadow-raised-hover)) +} +/* .tile:hover{transform:translateY(-2px);box-shadow:0 4px 4px rgba(0,0,0,.10), inset 0 4px 0 var(--accent)} */ +html[data-theme='dark'] .tile:hover{ + box-shadow: + 0px 16px 64px 0px #e20074, + 0px 8px 16px 0px #e20074; +} + +.tileTop{display:flex;align-items:center;justify-content:space-between;gap:6px;padding-bottom: 6px;} +html[data-theme='dark'] .tileTop{display:flex;align-items:center;justify-content:space-between;gap:6px} + +.cat{text-transform:uppercase;font-size:11px;letter-spacing:.05em;opacity:.7} /* ↑ was 9px */ +.symbol{flex:1;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:15px;line-height:1.1} /* ↑ was 12px */ + +.tileBottom{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-top:2px} +html[data-theme='dark'] .tileBottom{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-top:2px} + + +.name{font-size:18px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align: center;} /* ↑ was 9px */ +/* .ext{opacity:.5} */ +.badge{background:var(--badge);color:var(--badge-ink);padding:1px 6px;border-radius:999px;font-size:12px;border:1px solid #e0e7ff} /* ↑ was 10px */ + + + +/* External link icon — fixed, uniform size everywhere */ +.ext { + opacity: .6; /* keep your style */ + display: inline-flex; + align-items: center; + justify-content: center; + + /* fixed box so text size/line-height can’t affect it */ + width: 12px; + height: 12px; + flex: 0 0 16px; + line-height: 0; + vertical-align: middle; +} + +.ext svg { + width: 12px !important; /* defeat global svg width/height */ + height: 12px !important; + flex: 0 0 16px; + stroke-width: 2; /* optional: consistent weight */ +} + +/* tooltip */ +.tile[data-tooltip]:hover::after{ + content:attr(data-tooltip);position:absolute;left:8px;right:8px;bottom:100%; + transform:translateY(-6px);background:#0f172a;color:#fff;padding:8px 10px; + border-radius:10px;white-space:normal;font-size:12px;box-shadow:var(--shadow); +} +.tile[data-tooltip]:hover::before{ + content:"";position:absolute;left:20px;bottom:100%;transform:translateY(2px); + border:6px solid transparent;border-top-color:#0f172a +} + +/* ===== Sleeve (drawer) ===== */ +.sleeveBackdrop{ + position: fixed; + inset: 0; + background: rgba(2,6,23,.35); + display: grid; + place-items: stretch; + z-index: 60; + /* click-through animation */ + animation: otcFadeIn .12s ease-out; +} + +@keyframes otcFadeIn { from { opacity: 0 } to { opacity: 1 } } + +.sleeve{ + margin-left: auto; /* stick to right */ + width: min(420px, 90vw); + height: 100%; + background: #fff; + border-left: 1px solid var(--line); + box-shadow: -8px 0 24px rgba(0,0,0,.15); + display: flex; flex-direction: column; + transform: translateX(8px); + animation: otcSlideIn .16s ease-out forwards; +} + +html[data-theme='dark'] .sleeve{ + margin-left: auto; /* stick to right */ + width: min(420px, 96vw); + height: 100%; + background: var(--ifm-background-surface-color); + border-left: 1px solid var(--ifm-color-emphasis-200); + box-shadow: -8px 0 24px var(--ifm-background-surface-color); + display: flex; flex-direction: column; + transform: translateX(8px); + animation: otcSlideIn .16s ease-out forwards; +} + +@keyframes otcSlideIn { from { transform: translateX(24px); opacity: .8 } to { transform: translateX(0); opacity: 1 } } + +.sleeveClose{ + position: absolute; + top: 10px; right: 10px; + width: 32px; height: 32px; + border-radius: 8px; + border: 1px solid var(--line); + background: #fff; + cursor: pointer; + font-size: 20px; + line-height: 1; +} + +.sleeveHeader{ + padding: 20px 18px 10px 18px; + border-bottom: 1px solid var(--line); + display: grid; + grid-template-columns: auto 1fr; + align-items: end; + gap: 10px; +} + +html[data-theme='dark'] .sleeveHeader{ + padding: 20px 18px 10px 18px; + border-bottom: 1px solid var(--ifm-color-emphasis-200); + display: grid; + grid-template-columns: auto 1fr; + align-items: end; + gap: 10px; +} + +.sleeveSymbol{ + font-weight: 800; + font-size: 20px; + letter-spacing: .02em; +} +.sleeveTitle{ + font-weight: 700; + font-size: 18px; + color: var(--ink); +} + +.sleeveBody{ + padding: 16px 18px; + color: var(--muted); + line-height: 1.5; + overflow: auto; + flex: 1; +} + +html[data-theme='dark'] .sleeveBody{ + padding: 16px 18px; + color: white; + line-height: 1.5; + overflow: auto; + flex: 1; +} + +/* 2 equal tracks */ +.sleeveFooter { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); /* 50/50 */ + gap: 10px; + padding: 14px 18px 18px 18px; + border-top: 1px solid var(--line); + + /* safety: if an old rule set justify-content, kill it */ + justify-content: initial; +} + +.sleeveFooterSingle { + display: grid; + grid-template-columns: 1fr; + gap: 10px; + padding: 14px 18px 18px; + border-top: 1px solid var(--line); +} + +.sleeveFooterSingle scale-button { + --width: 100%; /* <- this is the key */ + display: block; /* optional, makes the host behave like a block */ + justify-self: stretch; +} + +html[data-theme='dark'] .sleeveFooter { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); /* 50/50 */ + gap: 10px; + padding: 14px 18px 18px 18px; + border-top: 1px solid 1px solid var(--ifm-color-emphasis-200); + + /* safety: if an old rule set justify-content, kill it */ + justify-content: initial; +} + +html[data-theme='dark'] .sleeveFooterSingle { + display: grid; + grid-template-columns: 1fr; + gap: 10px; + padding: 14px 18px 18px; + border-top: 1px solid 1px solid var(--ifm-color-emphasis-200); +} + +/* make the SCALE button host fill its grid cell */ +.sleeveFooter scale-button { + display: block; /* not inline-block */ + width: 100%; +} + +.sleeveBtn{ + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 10px 12px; + border-radius: 10px; + border: 1px solid #111827; + background: #111827; + color: #fff; + text-decoration: none; + font-weight: 600; + font-size: 14px; +} +.sleeveBtn:hover{ filter: brightness(1.06); transform: translateY(-1px); } + +.sleeveBtnGhost{ + background: #fff; + color: #111827; + border-color: var(--line); +} +.sleeveBtnGhost:hover{ + background: #f8fafc; +} + +.sleeveBtn, +.sleeveBtn:hover, +.sleeveBtn:focus, +.sleeveBtn:active, +.sleeveBtn:visited, +.sleeveBtnGhost, +.sleeveBtnGhost:hover, +.sleeveBtnGhost:focus, +.sleeveBtnGhost:active, +.sleeveBtnGhost:visited{ + width: 100%; /* fill each 1fr cell */ + text-decoration: none; /* no underline on any state */ + justify-content: center; /* keep label centered */ +} + +/* … your existing styles unchanged … */ + +/* enable pointer + inline layout for SCALE chips */ +.buckets scale-chip{display:inline-flex;cursor:pointer} + +.filtersRow{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:16px 0 10px} +.filtersSep{opacity:.5;padding:0 6px;user-select:none} +/* Smaller font for filter chips only (pipe stays the same size) */ +.filtersRow .buckets { font-size: 8px; } +/* fallback */ +.buckets scale-chip { font-size: 8px; } + +/* the row you already have */ +.filtersRow{ + display:flex; + gap:10px; + align-items:center; + flex-wrap:wrap; + margin:16px 0 10px; +} + +/* keeps the text field on the right and sized neatly */ +.filtersSearchWrap{ + padding-top: 10px; + margin-left:auto; /* pushes it to the right */ + min-width: 220px; + max-width: 340px; + flex: 1 1 220px; /* lets it grow a bit when there’s room */ +} + +.filtersSearchWrap scale-text-field{ + display:block; + width:100%; + --transition: all var(--telekom-motion-duration-transition) var( + --telekom-motion-easing-standard + ); + --radius: var(--telekom-radius-standard); + --border: var(--telekom-spacing-composition-space-01) solid var( + --telekom-color-ui-border-standard + ); + --border-error: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-danger-standard + ); + --border-success: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-success-standard + ); + --border-warning: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-warning-standard + ); + --border-color-hover: var(--telekom-color-ui-border-hovered); + --border-color-focus: var(--telekom-color-ui-border-hovered); + --border-color-disabled: var(--telekom-color-ui-border-disabled); + --background-color-hover: var(--telekom-color-ui-state-fill-hovered); + --background-color-disabled: none; + --focus-outline: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-focus-standard + ); + --height: 44px; + --spacing-x: var(--telekom-spacing-composition-space-05); + --color-disabled: var(--telekom-color-text-and-icon-disabled); + --background-disabled: none; + --border-color-readonly: var(--telekom-color-ui-border-disabled); + --background-readonly: var(--telekom-color-ui-disabled); + + /* meta */ + --font-weight-meta: var(--telekom-line-weight-bold); + --font-size-meta: var(--telekom-typography-font-size-small); + --line-height-meta: var(--telekom-typography-line-spacing-standard); + --spacing-y-meta: var(--telekom-spacing-composition-space-03); + --color-meta: var(--telekom-color-text-and-icon-standard); + --color-meta-error: var(--telekom-color-text-and-icon-functional-danger); + + /* control */ + --spacing-control: 1.125rem calc( + 2rem - var(--telekom-spacing-composition-space-01) + ) 0.25rem calc(0.75rem - var(--telekom-spacing-composition-space-01)); + --transition-control: var(--transition); + --background-control: var(--telekom-color-ui-state-fill-standard); + --margin-bottom-control: var(--telekom-spacing-composition-space-03); + + /* counter */ + --transition-counter: var(--transition); + --color-counter-error: var(--color-meta-error); + + /* helper-text */ + --font-size-helper-text: var(--telekom-typography-font-size-small); + --line-height-helper-text: 0.8; + --font-weight-helper-text: var(--telekom-typography-font-weight-bold); + --color-helper-text: var( + --telekom-color-text-and-icon-functional-informational + ); + --color-helper-text-error: var(--color-meta-error); + --color-helper-text-success: var( + --telekom-color-text-and-icon-functional-success + ); + --color-helper-text-warning: var( + --telekom-color-text-and-icon-functional-warning + ); + --color-helper-text-neutral: var(--telekom-color-text-and-icon-additional); + --helper-text-icon-size: 8px; + + /* placeholder */ + --transition-placeholder: var(--transition); + --color-placeholder: var(--telekom-color-text-and-icon-additional); + + /* label */ + --color-label: var(--telekom-color-text-and-icon-additional); + --color-label-readonly: var(--telekom-color-text-and-icon-standard); + --z-index-label: var(--scl-z-index-10); + --transition-label: var(--transition); +} + +/* Single grid for tiles — 4 per row on desktop */ +.tileGrid{ + display: grid; + gap: 10px; + grid-template-columns: repeat(4, minmax(0, 1fr)); + align-items: start; +} + +/* Tweak columns responsively so it doesn’t overflow on smaller screens */ +@media (max-width: 1200px){ + .tileGrid { grid-template-columns: repeat(3, minmax(0, 1fr)); } +} +@media (max-width: 900px){ + .tileGrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } +} +@media (max-width: 540px){ + .tileGrid { grid-template-columns: 1fr; } +} + +.filterBarRight { + width: 100%; + gap:10px; + display: block; /* ensures the custom element honors width */ + min-width: 300px; +} + +/* Style container for Scale dropdown */ +.filterBarRight scale-dropdown-select { + --background-hover: var(--telekom-color-ui-state-fill-hovered); + --color-hover: var(--telekom-color-text-and-icon-standard); + --background: var(--telekom-color-ui-state-fill-standard); + --color: var(--telekom-color-text-and-icon-standard); + --radius: var(--telekom-radius-standard); + --spacing: var(--telekom-spacing-composition-space-04); + /* --min-width: 200px; */ +} + +/* one-row layout with a 90/10 split */ +.filterRow { + display: grid; + grid-template-columns: 8.5fr 1.5fr; /* 90% / 10% */ + gap: 10px; + align-items: center; + width: 100%; +} + +/* ensure the custom element stretches */ +.fullWidthDropdown { + width: 100%; + display: block; +} + +/* make the reset button fill its 10% column */ +.resetBtn { + width: 100%; + height: 44px; /* match your input height if needed */ +} + +/* Span the full results grid and center content */ +.emptyFill { + grid-column: 1 / -1; /* <-- key: occupy all grid columns */ + width: 100%; + + display: grid; /* center both axes */ + place-items: center; + min-height: 50vh; /* or 100vh if you want true viewport centering */ +} + +.emptyState { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + text-align: center; +} + +.emptyState img { + max-width: 220px; + height: auto; + margin-bottom: 10px; +} diff --git a/src/pages/portfolio.mdx b/src/pages/portfolio.mdx new file mode 100644 index 0000000000..765aa26f49 --- /dev/null +++ b/src/pages/portfolio.mdx @@ -0,0 +1,11 @@ +--- +title: Portfolio Navigator +description: periodic-table +hide_table_of_contents: true +--- + +# Portfolio Navigator + +import Navigator from "@site/src/components/PortfolioNavigator"; + + diff --git a/src/theme/DocTagDocListPage/index.tsx b/src/theme/DocTagDocListPage/index.tsx index ea5d9ac5c3..e4e65517ff 100644 --- a/src/theme/DocTagDocListPage/index.tsx +++ b/src/theme/DocTagDocListPage/index.tsx @@ -7,16 +7,16 @@ import { ThemeClassNames, usePluralForm, } from '@docusaurus/theme-common'; -import Translate, {translate} from '@docusaurus/Translate'; +import Translate, { translate } from '@docusaurus/Translate'; import SearchMetadata from '@theme/SearchMetadata'; -import type {Props} from '@theme/DocTagDocListPage'; +import type { Props } from '@theme/DocTagDocListPage'; import Heading from '@theme/Heading'; -import {File, FlaskConical, Factory, FileCheck} from 'lucide-react'; +import { File, FlaskConical, Factory, FileCheck } from 'lucide-react'; import styles from './styles.module.css'; // Custom pluralization hook function useNDocsTaggedPlural() { - const {selectMessage} = usePluralForm(); + const { selectMessage } = usePluralForm(); return (count: number) => selectMessage( count, @@ -26,7 +26,7 @@ function useNDocsTaggedPlural() { description: 'Pluralized label for "{count} docs tagged"', message: 'We found one article tagged|We found {count} articles tagged', }, - {count}, + { count }, ), ); } @@ -40,20 +40,20 @@ function usePageTitle(props: Props): string { description: 'Title of the docs tag list page', message: '{nDocsTagged} with "{tagName}"', }, - {nDocsTagged, tagName: props.tag.label}, + { nDocsTagged, tagName: props.tag.label }, ); } // Single document item -function DocItem({doc}: {doc: Props['tag']['items'][number]}): JSX.Element { +function DocItem({ doc }: { doc: Props['tag']['items'][number] }): JSX.Element { const url = doc.permalink; const IconComponent = url.includes('best-practices') ? FileCheck : url.includes('by-industry') - ? Factory - : url.includes('blueprints') - ? FlaskConical - : File; + ? Factory + : url.includes('blueprints') + ? FlaskConical + : File; return (
@@ -78,7 +78,7 @@ function DocItem({doc}: {doc: Props['tag']['items'][number]}): JSX.Element { function DocTagDocListPageMetadata({ title, tag, -}: Props & {title: string}): JSX.Element { +}: Props & { title: string }): JSX.Element { return ( <> @@ -91,7 +91,7 @@ function DocTagDocListPageMetadata({ function DocTagDocListPageContent({ tag, title, -}: Props & {title: string}): JSX.Element { +}: Props & { title: string }): JSX.Element { return ( {title} {tag.description &&

{tag.description}

} - - - - View All Tags - - - + + + + View All Tags + + + + + + + Go to Portfolio Navigator + +
{tag.items.map((doc) => ( diff --git a/src/theme/DocTagDocListPage/styles.module.css b/src/theme/DocTagDocListPage/styles.module.css index 93a9c9cd23..62fc4c5c73 100644 --- a/src/theme/DocTagDocListPage/styles.module.css +++ b/src/theme/DocTagDocListPage/styles.module.css @@ -62,3 +62,6 @@ html[data-theme='dark'] .title { .viewAll { } + +.filtersSep{opacity:.5;padding:0 6px;user-select:none} + diff --git a/src/theme/NotFound/Content/index.tsx b/src/theme/NotFound/Content/index.tsx index d925c27958..438dff73f6 100644 --- a/src/theme/NotFound/Content/index.tsx +++ b/src/theme/NotFound/Content/index.tsx @@ -1,9 +1,10 @@ import clsx from 'clsx'; import Translate from '@docusaurus/Translate'; -import type {Props} from '@theme/NotFound/Content'; +import type { Props } from '@theme/NotFound/Content'; import Heading from '@theme/Heading'; +import styles from './styles.module.css'; -export default function NotFoundContent({className}: Props): JSX.Element { +export default function NotFoundContent({ className }: Props): JSX.Element { return (
@@ -30,6 +31,33 @@ export default function NotFoundContent({className}: Props): JSX.Element { original URL and let them know their link is broken.

*/} + + + + Go to Portfolio Navigator + + + + + + + View All Tags + + + + + + + + Return Home + +
diff --git a/src/theme/NotFound/Content/styles.module.css b/src/theme/NotFound/Content/styles.module.css new file mode 100644 index 0000000000..11a4d450e2 --- /dev/null +++ b/src/theme/NotFound/Content/styles.module.css @@ -0,0 +1 @@ +.filtersSep{opacity:.5;padding:0 6px;user-select:none} diff --git a/static/img/undraw_no-data_ig65.svg b/static/img/undraw_no-data_ig65.svg new file mode 100644 index 0000000000..c61356c421 --- /dev/null +++ b/static/img/undraw_no-data_ig65.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 487d335859..e258b6bb77 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2809,10 +2809,18 @@ resolved "https://registry.npmjs.org/@telekom/design-tokens/-/design-tokens-1.0.0-beta.10.tgz" integrity sha512-57BFgDxDkvOOrQf7wmS1u5jQmPRdhh6Y/qOHwTvYlS5GwGlkr3EeGeuwePL5pJ7z0jTnxEIVhmwbZnIx9AIX8w== +"@telekom/scale-components-react@^3.0.0-beta.56": + version "3.0.0-beta.56" + resolved "https://registry.npmjs.org/@telekom/scale-components-react/-/scale-components-react-3.0.0-beta.56.tgz" + integrity sha512-FtCd4gyyriSbeN7nUAjHo6jtIFW7tpFTzqDXFCjtiNaGAHVxAI5YLmhH41yPP8704FshNB5M+dBsRqNXQst2kg== + dependencies: + "@types/react-dom" "^16.9.6" + "@types/vfile-message" "^2.0.0" + "@telekom/scale-components@^3.0.0-beta.151": - version "3.0.0-beta.151" - resolved "https://registry.npmjs.org/@telekom/scale-components/-/scale-components-3.0.0-beta.151.tgz" - integrity sha512-CVqCJEBUW/15wrtzFUae6kTqZz13ZCCfaCrlPPYxWG+E6aavvEzPnZVROUAbXbKFfvMSsOV+zCcVDhMER27x9A== + version "3.0.0-beta.156" + resolved "https://registry.npmjs.org/@telekom/scale-components/-/scale-components-3.0.0-beta.156.tgz" + integrity sha512-H8Dml6tKjaCYDBXr4TWaGv5u457C9dMTm6ZuTnhWMzaQBESxK0lYOuUGrQmN1IiX8mHYSzjQuIpwIRlZ1nyrkw== dependencies: "@duetds/date-picker" "1.2.0" "@floating-ui/dom" "^1.2.8" @@ -3048,6 +3056,11 @@ resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== +"@types/react-dom@^16.9.6": + version "16.9.25" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.25.tgz" + integrity sha512-ZK//eAPhwft9Ul2/Zj+6O11YR6L4JX0J2sVeBC9Ft7x7HFN7xk7yUV/zDxqV6rjvqgl6r8Dq7oQImxtyf/Mzcw== + "@types/react-router-config@*", "@types/react-router-config@^5.0.7": version "5.0.11" resolved "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz" @@ -3074,12 +3087,13 @@ "@types/history" "^4.7.11" "@types/react" "*" -"@types/react@*", "@types/react@>= 16.8.0 < 19.0.0", "@types/react@>=16": - version "18.2.79" - resolved "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz" - integrity sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w== +"@types/react@*", "@types/react@^16.0.0", "@types/react@>= 16.8.0 < 19.0.0", "@types/react@>=16": + version "16.14.65" + resolved "https://registry.npmjs.org/@types/react/-/react-16.14.65.tgz" + integrity sha512-Guc3kE+W8LrQB9I3bF3blvNH15dXFIVIHIJTqrF8cp5XI/3IJcHGo4C3sJNPb8Zx49aofXKnAGIKyonE4f7XWg== dependencies: "@types/prop-types" "*" + "@types/scheduler" "^0.16" csstype "^3.0.2" "@types/retry@0.12.0": @@ -3094,6 +3108,11 @@ dependencies: "@types/node" "*" +"@types/scheduler@^0.16": + version "0.16.8" + resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz" + integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== + "@types/send@*": version "0.17.4" resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" @@ -3135,6 +3154,13 @@ resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz" integrity sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA== +"@types/vfile-message@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-2.0.0.tgz" + integrity sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw== + dependencies: + vfile-message "*" + "@types/ws@^8.5.5": version "8.5.10" resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz" @@ -5470,6 +5496,11 @@ find-up@^6.3.0: locate-path "^7.1.0" path-exists "^5.0.0" +flag-icons@^7.5.0: + version "7.5.0" + resolved "https://registry.npmjs.org/flag-icons/-/flag-icons-7.5.0.tgz" + integrity sha512-kd+MNXviFIg5hijH766tt+3x76ele1AXlo4zDdCxIvqWZhKt4T83bOtxUOOMlTx/EcFdUMH5yvQgYlFh1EqqFg== + flat-cache@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz" @@ -8988,7 +9019,7 @@ react-dev-utils@^12.0.1: strip-ansi "^6.0.1" text-table "^0.2.0" -react-dom@*, "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", react-dom@^18.0.0, "react-dom@^18.0.0 || ^19.0.0", react-dom@^18.3.1, "react-dom@>= 16.8.0 < 19.0.0": +react-dom@*, "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", react-dom@^18.0.0, "react-dom@^18.0.0 || ^19.0.0", react-dom@^18.3.1, "react-dom@>= 16.8.0 < 19.0.0", react-dom@>=16.13.1: version "18.3.1" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -9076,7 +9107,7 @@ react-router@^5.3.4, react-router@>=5, react-router@5.3.4: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react@*, "react@^16.13.1 || ^17.0.0 || ^18.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.6.0 || ^17.0.0 || ^18.0.0", react@^18.0.0, "react@^18.0.0 || ^19.0.0", react@^18.3.1, "react@>= 16.8.0 < 19.0.0", react@>=15, react@>=16, react@>=16.0.0: +react@*, "react@^16.13.1 || ^17.0.0 || ^18.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.6.0 || ^17.0.0 || ^18.0.0", react@^18.0.0, "react@^18.0.0 || ^19.0.0", react@^18.3.1, "react@>= 16.8.0 < 19.0.0", react@>=15, react@>=16, react@>=16.0.0, react@>=16.13.1: version "18.3.1" resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -10568,7 +10599,7 @@ vfile-location@^5.0.0: "@types/unist" "^3.0.0" vfile "^6.0.0" -vfile-message@^4.0.0: +vfile-message@*, vfile-message@^4.0.0: version "4.0.2" resolved "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz" integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==