From 7317b70ff00fc986845c16c73d63f6b04569beae Mon Sep 17 00:00:00 2001 From: Aryan Mehrotra Date: Wed, 8 Apr 2026 13:55:29 +0530 Subject: [PATCH 01/28] Add changelog, showcase, community, and examples pages - /changelog: Timeline of releases with markdown rendering, fetched from GitHub API during build - /showcase: Company logos, industry tags, testimonials from engineers - /community: Discord, GitHub, Reddit, Twitter, LinkedIn cards with contributing section - /examples: 17 examples with tag filtering, featured section - Header nav: Docs, Changelog, Examples, Community - Footer: Added links to all new pages - Mobile nav: Site-wide links added - Search: Improved ranking with word-boundary matching, keyboard hints - CLI page: Replaced "Coming Soon" with install instructions and links - Releases: Redirects to /changelog - Pkg pages: Show redirect to relevant docs instead of blank - SEO: robots.txt, comprehensive sitemap - New components: SectionCards, Tabs, PkgRedirect - Markdoc: Registered tabs and section-cards tags Co-Authored-By: Claude Opus 4.6 (1M context) --- public/robots.txt | 3 + src/app/changelog/page.jsx | 304 ++++++++++++++++++ src/app/changelog/releases.json | 1 + src/app/cli/gofr/page.jsx | 67 +++- src/app/community/page.jsx | 144 +++++++++ src/app/examples/examples.json | 19 ++ src/app/examples/page.jsx | 151 +++++++++ src/app/pkg/gofr/datasource/arangodb/page.jsx | 19 +- .../pkg/gofr/datasource/cassandra/page.jsx | 19 +- .../pkg/gofr/datasource/clickhouse/page.jsx | 19 +- .../pkg/gofr/datasource/couchbase/page.jsx | 19 +- .../pkg/gofr/datasource/dbresolver/page.jsx | 19 +- src/app/pkg/gofr/datasource/dgraph/page.jsx | 19 +- .../gofr/datasource/elasticsearch/page.jsx | 19 +- .../pkg/gofr/datasource/file/azure/page.jsx | 19 +- src/app/pkg/gofr/datasource/file/ftp/page.jsx | 19 +- src/app/pkg/gofr/datasource/file/gcs/page.jsx | 19 +- src/app/pkg/gofr/datasource/file/s3/page.jsx | 19 +- .../pkg/gofr/datasource/file/sftp/page.jsx | 19 +- .../gofr/datasource/kv-store/badger/page.jsx | 19 +- .../gofr/datasource/kv-store/nats/page.jsx | 19 +- src/app/pkg/gofr/datasource/mongo/page.jsx | 19 +- src/app/pkg/gofr/datasource/opentsdb/page.jsx | 19 +- src/app/pkg/gofr/datasource/oracle/page.jsx | 19 +- .../gofr/datasource/pubsub/eventhub/page.jsx | 19 +- .../pkg/gofr/datasource/pubsub/nats/page.jsx | 19 +- .../pkg/gofr/datasource/pubsub/sqs/page.jsx | 19 +- src/app/pkg/gofr/datasource/scylladb/page.jsx | 19 +- src/app/pkg/gofr/datasource/solr/page.jsx | 19 +- .../pkg/gofr/datasource/surrealdb/page.jsx | 19 +- src/app/releases/layout.jsx | 18 +- src/app/showcase/companies.json | 12 + src/app/showcase/page.jsx | 138 ++++++++ src/app/sitemap.xml | 239 ++++---------- src/components/Footer.jsx | 7 +- src/components/Layout.jsx | 44 ++- src/components/MobileNavigation.jsx | 31 ++ src/components/PkgRedirect.jsx | 50 +++ src/components/Search.jsx | 148 +++++---- src/components/SectionCards.jsx | 73 +++++ src/components/Tabs.jsx | 47 +++ src/markdoc/search.mjs | 106 +++--- src/markdoc/tags.js | 18 ++ 43 files changed, 1401 insertions(+), 656 deletions(-) create mode 100644 public/robots.txt create mode 100644 src/app/changelog/page.jsx create mode 100644 src/app/changelog/releases.json create mode 100644 src/app/community/page.jsx create mode 100644 src/app/examples/examples.json create mode 100644 src/app/examples/page.jsx create mode 100644 src/app/showcase/companies.json create mode 100644 src/app/showcase/page.jsx create mode 100644 src/components/PkgRedirect.jsx create mode 100644 src/components/SectionCards.jsx create mode 100644 src/components/Tabs.jsx diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..40f4b21 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Sitemap: https://gofr.dev/sitemap.xml diff --git a/src/app/changelog/page.jsx b/src/app/changelog/page.jsx new file mode 100644 index 0000000..8e9f320 --- /dev/null +++ b/src/app/changelog/page.jsx @@ -0,0 +1,304 @@ +'use client' + +import { useState } from 'react' +import Link from 'next/link' +import releases from './releases.json' + +function formatDate(dateStr) { + if (!dateStr) return '' + return new Date(dateStr).toLocaleDateString('en-US', { + year: 'numeric', month: 'long', day: 'numeric', + }) +} + +// Simple markdown-to-JSX renderer for GitHub release notes +function RenderMarkdown({ text }) { + if (!text) return null + + // Split into lines and process + let lines = text.split('\n') + let elements = [] + let inCodeBlock = false + let codeLines = [] + let codeLang = '' + + for (let i = 0; i < lines.length; i++) { + let line = lines[i] + + // Code block toggle + if (line.trim().startsWith('```')) { + if (inCodeBlock) { + elements.push( +
+            {codeLines.join('\n')}
+          
+ ) + codeLines = [] + inCodeBlock = false + } else { + inCodeBlock = true + codeLang = line.trim().replace('```', '') + } + continue + } + + if (inCodeBlock) { + codeLines.push(line) + continue + } + + // Skip top-level release title (# Release v1.x.x) + if (/^#\s+Release\s+v/i.test(line.trim())) continue + if (/^#\s+\*\*v/i.test(line.trim())) continue + + // Skip section headers like ## Features, ## Fixes (we handle these separately) + if (/^##\s+/.test(line.trim())) continue + + // Sub-headers (### Something) + if (/^###\s+/.test(line.trim())) { + let text = line.replace(/^###\s+/, '').replace(/[🔹🚀🔧🛠️]/g, '').trim() + text = renderInline(text) + elements.push( +

+ {text} +

+ ) + continue + } + + // Empty lines + if (line.trim() === '') continue + + // Bullet points + if (/^\s*[-*]\s+/.test(line)) { + let text = line.replace(/^\s*[-*]\s+/, '') + elements.push( +
  • + {renderInline(text)} +
  • + ) + continue + } + + // Regular paragraph + if (line.trim()) { + elements.push( +

    + {renderInline(line.trim())} +

    + ) + } + } + + return
    {elements}
    +} + +// Render inline markdown (bold, code, links) +function renderInline(text) { + if (!text) return text + + // Remove emoji prefixes and GitHub colon-emoji syntax + text = text.replace(/[🔹🚀🔧🛠️💎⚡]/g, '').trim() + text = text.replace(/:small_blue_diamond:/g, '') + text = text.replace(/:rocket:/g, '') + text = text.replace(/:wrench:/g, '') + text = text.replace(/:hammer_and_wrench:/g, '') + text = text.replace(/:gem:/g, '') + text = text.replace(/:zap:/g, '') + text = text.replace(/:white_check_mark:/g, '') + text = text.replace(/:warning:/g, '') + text = text.replace(/:bug:/g, '') + text = text.replace(/:sparkles:/g, '') + text = text.replace(/:[a-z_]+:/g, '').trim() + + // Split on bold markers and inline code + let parts = [] + let remaining = text + let key = 0 + + while (remaining.length > 0) { + // Bold: **text** + let boldMatch = remaining.match(/\*\*(.*?)\*\*/) + // Inline code: `text` + let codeMatch = remaining.match(/`(.*?)`/) + + // Find the earliest match + let nextBold = boldMatch ? remaining.indexOf(boldMatch[0]) : Infinity + let nextCode = codeMatch ? remaining.indexOf(codeMatch[0]) : Infinity + + if (nextBold === Infinity && nextCode === Infinity) { + parts.push(remaining) + break + } + + if (nextBold <= nextCode && boldMatch) { + if (nextBold > 0) parts.push(remaining.slice(0, nextBold)) + parts.push( + + {boldMatch[1]} + + ) + remaining = remaining.slice(nextBold + boldMatch[0].length) + } else if (codeMatch) { + if (nextCode > 0) parts.push(remaining.slice(0, nextCode)) + parts.push( + + {codeMatch[1]} + + ) + remaining = remaining.slice(nextCode + codeMatch[0].length) + } + } + + return parts.length > 0 ? parts : text +} + +function parseRelease(body) { + if (!body) return [] + + let sections = [] + let currentSection = null + let currentContent = [] + + for (let line of body.split('\n')) { + // Detect section headers: ## 🚀 Features, ## 🔧 Enhancements, ## 🛠️ Fixes + if (/^##\s+/.test(line.trim())) { + if (currentSection) { + sections.push({ type: currentSection, content: currentContent.join('\n') }) + } + let header = line.replace(/^##\s+/, '').replace(/[🚀🔧🛠️]/g, '').trim() + if (/feature/i.test(header)) currentSection = 'features' + else if (/enhancement/i.test(header)) currentSection = 'enhancements' + else if (/fix/i.test(header)) currentSection = 'fixes' + else currentSection = header.toLowerCase() + currentContent = [] + continue + } + + // Skip release title + if (/^#\s+/.test(line.trim()) && !/^##/.test(line.trim())) continue + + if (currentSection) { + currentContent.push(line) + } + } + + if (currentSection) { + sections.push({ type: currentSection, content: currentContent.join('\n') }) + } + + return sections +} + +const sectionStyles = { + features: { label: 'Features', color: 'text-violet-400', badge: 'bg-violet-500/10 text-violet-400' }, + enhancements: { label: 'Enhancements', color: 'text-sky-400', badge: 'bg-sky-500/10 text-sky-400' }, + fixes: { label: 'Fixes', color: 'text-amber-400', badge: 'bg-amber-500/10 text-amber-400' }, +} + +function ReleaseCard({ release, isLatest }) { + let [expanded, setExpanded] = useState(isLatest) + let sections = parseRelease(release.body) + let sectionTypes = sections.map(s => s.type) + + return ( +
    +
    + +
    + + {release.tag} + + {formatDate(release.date)} + {isLatest && ( + + Latest + + )} +
    + +
    + {sectionTypes.map(type => { + let style = sectionStyles[type] || { label: type, badge: 'bg-slate-800 text-slate-400' } + return ( + + {style.label} + + ) + })} +
    + + + + {expanded && ( +
    + {sections.map((section, idx) => { + let style = sectionStyles[section.type] || { label: section.type, color: 'text-slate-300' } + return ( +
    +

    + {style.label} +

    + +
    + ) + })} +
    + )} + + + View on GitHub + + + + + +
    + ) +} + +export default function ChangelogPage() { + return ( +
    +
    +

    + Changelog +

    +

    + Release notes and version history for GoFr. +

    + +
    + {releases.map((release, index) => ( + + ))} +
    + +
    + + View all releases on GitHub → + +
    +
    +
    + ) +} diff --git a/src/app/changelog/releases.json b/src/app/changelog/releases.json new file mode 100644 index 0000000..9cead84 --- /dev/null +++ b/src/app/changelog/releases.json @@ -0,0 +1 @@ +[{"body":"# Release v1.56.0\r\n\r\n## 🚀 Features\r\n\r\n🔹 **CORS Multiple Origins Support**\r\n\r\nGoFr's CORS middleware now supports **multiple allowed origins**, enabling fine-grained access control for applications serving multiple frontends or admin panels.\r\n- **Comma-Separated Origins**: Configure multiple origins via the `ACCESS_CONTROL_ALLOW_ORIGIN` environment variable\r\n- **Dynamic Origin Matching**: On each request, the `Origin` header is matched against the allowed set and only the matched origin is returned in the response (per HTTP spec)\r\n- **Correct Caching**: Adds `Vary: Origin` header when a specific origin is matched, ensuring proxies and CDNs cache responses correctly\r\n- **Fully Backward-Compatible**: Single origin and wildcard (`*`) work exactly as before\r\n\r\n**Configuration Example**\r\n```env\r\n# Single origin (existing behavior)\r\nACCESS_CONTROL_ALLOW_ORIGIN=https://app.example.com\r\n\r\n# Multiple origins (new)\r\nACCESS_CONTROL_ALLOW_ORIGIN=https://app.example.com,https://admin.example.com\r\n```\r\n\r\n## 🔧 Enhancements\r\n\r\n🔹 **Selective Migration Record Tracking**\r\n\r\nMigrations now only insert `gofr_migrations` records into databases that were **actually used** by the `UP` function, instead of all connected databases. Previously, running a migration that only touched MySQL would still insert migration records into Redis, MongoDB, Cassandra, and every other connected database — leading to phantom records, wasted I/O, and a misleading audit trail. Each datasource is now wrapped with lightweight usage-tracking before `UP()` executes, and only touched databases receive the migration record.\r\n\r\n## 🛠️ Fixes\r\n\r\n- **WebSocket Nil Pointer Panic** — Fixed a nil pointer dereference in `WriteMessageToSocket` when no WebSocket connection exists in the context. It now returns `ErrConnectionNotFound` instead of panicking.\r\n\r\n- **File Logger Descriptor Leak** — `NewFileLogger()` opens a file via `os.OpenFile` but previously had no way to close it, causing file descriptor leaks. Added a `Close()` method to the logger, which is now called during `App.Shutdown()` (HTTP/gRPC) and after `cmd.Run()` (CLI apps). `Fatal`/`Fatalf` also now call `file.Sync()` before exiting to flush buffered log data.\r\n\r\n- **Cron Job Duration Log Format** — Fixed `%!s(float64=...)` in cron job completion logs by keeping `duration` as `time.Duration` instead of converting to `float64`. Logs now show human-readable durations (e.g., `25.071286ms` instead of `%!s(float64=0.025071286)`).\r\n\r\n- **UpdateOne Breaking Change Reverted** — Reverted the `Mongo` interface's `UpdateOne` return type from `(int64, error)` back to `error`, fixing a breaking change introduced in v1.55.0. The migration lock refresh now uses `UpdateMany` (which already returns the needed `ModifiedCount`) with a filter that guarantees at most one document matches.\r\n\r\n- **Dependency Updates** — Consolidated minor dependency updates and bumped `github.com/go-jose/go-jose/v4` for security improvements.\r\n","date":"2026-04-07T11:57:02Z","tag":"v1.56.0","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.56.0"},{"body":"# Release v1.55.0\r\n\r\n## 🚀 Features\r\n\r\n### Native GraphQL Support\r\nGoFr now provides first-class **GraphQL** support using a schema-first approach. Define your API contract in `./configs/schema.graphqls`, register resolvers with `app.GraphQLQuery()` and `app.GraphQLMutation()`, and GoFr handles execution, validation, tracing, and metrics automatically.\r\n - **Single Endpoint**: All operations served at `POST /graphql`\r\n - **Interactive Playground**: Auto-hosted at `/.well-known/graphql/ui`\r\n - **Full Observability**: Per-resolver OpenTelemetry tracing, operation-level metrics (`app_graphql_operations_total`, `app_graphql_error_total`, `app_graphql_request_duration`), and structured logs aligned with GoFr's existing format\r\n - **Operation Name Extraction**: Automatically parses resolver names from the query AST for meaningful metric labels, even for anonymous operations\r\n - **Grafana Dashboard**: GraphQL panels added to the standard GoFr dashboard with Response Time SLA, Request/Error Count, and Latency breakdowns by operation and type\r\n\r\n### gRPC Rate Limiter\r\nBuilt-in rate limiter interceptors for gRPC using a token bucket algorithm, supporting both unary and streaming RPCs.\r\n - **Per-IP Rate Limiting**: Each client IP gets its own rate limit bucket\r\n - **Shared or Separate Budgets**: Use a single store for combined limits or independent configs per call type\r\n - **Prometheus Metrics**: Track violations via `app_grpc_rate_limit_exceeded_total` counter\r\n - Returns `RESOURCE_EXHAUSTED` with `retry-after` metadata on limit exceeded\r\n\r\n### GCS Metadata Upload and Signed URL Generation\r\nGoogle Cloud Storage now supports cloud-specific operations beyond the standard filesystem interface.\r\n - **`CreateWithOptions`**: Upload files with custom `Content-Type`, `Content-Disposition`, and arbitrary metadata\r\n - **`GenerateSignedURL`**: Create time-limited, pre-authenticated download URLs\r\n - **`file.AsCloud()`**: Safe type assertion helper to check cloud support\r\n\r\n## 🔧 Enhancements\r\n\r\n### NATS OpenTelemetry Span Links\r\nAdded span link support for NATS JetStream PubSub operations, providing distributed tracing visibility into publish, subscribe, and commit operations.\r\n\r\n### gRPC Observability Improvements\r\nClient-side errors (e.g., `InvalidArgument`, `NotFound`, `ResourceExhausted`) are no longer logged at ERROR level — only server-side errors are. This reduces log noise in production.\r\n\r\n## 🛠️ Fixes\r\n\r\n- **Migration Race Condition** — Fixed a race condition where multiple pods starting simultaneously could execute the same migration concurrently. The migration state is now re-verified under the distributed lock before execution, preventing duplicate runs in multi-instance deployments.\r\n\r\n- **Zipkin Deprecation Warning** — `TRACE_EXPORTER=zipkin` now logs an actionable deprecation warning with migration instructions to OTLP (Zipkin supports OTLP natively since v2.24+).\r\n\r\n- **CI Workflow Updates** — Bumped Docker GitHub Actions (`setup-buildx-action`, `login-action`) from v3 to v4 in website deployment workflows.","date":"2026-03-14T20:39:44Z","tag":"v1.55.0","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.55.0"},{"body":"# Release v1.54.6\r\n\r\n## 🛠️ Fixes\r\n\r\n- ### PubSub Migration Conflict Resolution \r\nResolved an issue where the PubSub Migrator, particularly with Redis Streams, incorrectly reported migration versions based on historical data on the message bus.\r\n - **Decoupled Versioning**: Made PubSub non-authoritative for migration state by removing it from the version chain. Migration tracking is now strictly confined to primary data stores that support atomicity and locking.\r\n - **PubSub Still Available**: The PubSub client remains fully accessible in the `migration.Datasource` object for use in migration `UP` functions (e.g., `d.PubSub.CreateTopic()`).","date":"2026-03-11T06:17:01Z","tag":"v1.54.6","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.54.6"},{"body":"# Release v1.54.5\r\n\r\n## 🚀 Enhancements\r\n\r\n### 🔹 Google Pub/Sub Span Links for Tracing\r\nGoFr now supports OpenTelemetry span links for Google Cloud Pub/Sub, extending the tracing capabilities introduced for Kafka in [v1.54.4](https://github.com/gofr-dev/gofr/releases/tag/v1.54.4).\r\n- **End-to-End Traceability**: Connects producer and consumer spans across asynchronous Google Pub/Sub messaging, enabling complete request lifecycle visualization.\r\n- **Context Propagation**: Automatically injects and extracts trace context through Pub/Sub message attributes using the standard OpenTelemetry propagator.\r\n- **Semantic Conventions**: Follows OpenTelemetry messaging semantic conventions for consistent, standards-compliant spans and links.\r\n\r\n### 🔹 SQS Span Links for Tracing\r\nAdded OpenTelemetry span links for AWS SQS, completing pub/sub tracing support across all major message brokers.\r\n- **AWS Observability**: Connects producer and consumer spans for SQS messages, providing full distributed tracing for AWS-based event-driven architectures.\r\n- **Attribute Propagation**: Leverages SQS message attributes for trace context propagation, enabling seamless correlation across services.\r\n- **Consistent Tracing**: Aligns with the same span link patterns used for Kafka and Google Pub/Sub for a unified observability experience.\r\n\r\n### 🔹 Oracle Migration Locks Management\r\nExtended migration locks support to Oracle datasources, building on the SQL \u0026 Redis locking introduced in [v1.54.3](https://github.com/gofr-dev/gofr/releases/tag/v1.54.3).\r\n- **Safe Concurrent Deployments**: In multi-instance deployments (e.g., Kubernetes), only one instance executes Oracle migrations at a time, preventing race conditions.\r\n- **Automatic Lock Lifecycle**: Manages lock acquisition, expiry-based cleanup, periodic refresh, and safe release with full PL/SQL-based error handling.\r\n- **Data Integrity**: Prevents corrupted migration states during parallel deployments against Oracle databases.\r\n\r\n## 🛠️ Fixes\r\n\r\n- ### Static File Path Traversal Prevention\r\nResolved a security issue in the static file handler where sibling directory names could bypass the restricted file check.\r\n - **Security Hardening**: Appended a path separator in [isRestrictedFile](cci:1://file:///Users/zopdev/Downloads/GolandProjects%202/gofr-repo/gofr/pkg/gofr/http/router.go:134:0-139:1) to ensure that sibling directories sharing a common prefix with the static directory (e.g., `/app/publicother` vs `/app/public`) cannot be traversed to serve unauthorized files.\r\n- **What's Restricted**: Files outside the configured static directory are blocked from being served. Additionally, direct access to `openapi.json` via static routes remains restricted — it is only accessible through the `/.well-known/swagger` or `/.well-known/openapi.json` endpoints.\r\n\r\n### 🔹 Kafka Subscribe Data Race\r\nFixed a data race condition in the Kafka `Subscribe` method that could surface under concurrent access.\r\n- **Concurrency Safety**: Ensures thread-safe subscription handling, preventing unpredictable behavior in high-concurrency environments.\r\n\r\n### 🔹 Config Parsing Silent Failures\r\nResolved an issue where invalid or missing configuration values would fail silently, making it difficult to diagnose misconfiguration issues.\r\n- **Better Error Reporting**: Added proper nil-checks and logging for configuration parsing, ensuring misconfigurations are surfaced through structured log messages instead of being swallowed silently.\r\n","date":"2026-02-27T13:32:05Z","tag":"v1.54.5","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.54.5"},{"body":"# Release v1.54.4\r\n\r\n## 🚀 Enhancements\r\n\r\n### 🔹 Kafka Span Links for Pub/Sub Tracing\r\nGoFr now supports OpenTelemetry span links for Kafka, significantly improving observability in event-driven systems.\r\n- **Improved Traceability**: Connects producer and consumer spans even in asynchronous messaging patterns, providing a complete picture of the request lifecycle.\r\n- **Enhanced Observability**: Users can now visualize the relationship between messages, making it easier to debug complex microservices interactions.\r\n- **Semantic Conventions**: Follows OpenTelemetry messaging semantic conventions for consistent spans and links.\r\n\r\n### 🔹 Metrics Export for Cron Jobs\r\nIntroduced native support for exporting metrics for background tasks managed through Cron Jobs.\r\n- **Performance Monitoring**: Automatically tracks execution duration and success/failure counts for scheduled tasks.\r\n- **Better Visibility**: Allows developers to monitor the health and performance of background workers using the same telemetry stack as their HTTP services.\r\n- **Customizable**: Leverages GoFr's internal metrics provider for seamless integration with Prometheus or other exporters.\r\n\r\n## 🛠️ Fixes\r\n\r\n### 🔹 HTTP Server Auto-detection\r\nResolved an issue where the HTTP server wouldn't start if only a static directory was auto-detected without any explicit route registration.\r\n- **Robust Static Hosting**: Ensures that applications serving only static content boot correctly and serve assets as expected.\r\n\r\n### 🔹 Reduced HTTP Shutdown Noise\r\nOptimized the server shutdown sequence to eliminate unnecessary log noise and warnings during graceful termination.\r\n- **Cleaner Logs**: Provides a more streamlined and less cluttered logging experience during application restarts and deployments.","date":"2026-02-21T12:45:31Z","tag":"v1.54.4","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.54.4"},{"body":"# Release v1.54.3\r\n\r\n## 🚀 Enhancements\r\n\r\n### 🔹 Migration Locking for SQL \u0026 Redis\r\nGoFr now implements automatic migration locking for SQL and Redis datasources.\r\n- **Automatic Coordination**: In multi-instance deployments (such as Kubernetes), instances effectively coordinate to ensure only one instance executes migrations at a time.\r\n- **Data Integrity**: This mechanism effectively prevents race conditions and corrupted migration states during parallel deployments.\r\n\r\n## 🛠️ Fixes\r\n\r\n- **Circuit Breaker Concurrency** - Resolved an issue where the Circuit Breaker was erroneously enforcing sequential execution on parallel HTTP requests. This fix restores the expected concurrent behavior, significantly improving throughput for service calls.\r\n\r\n- **Datasource Resource Management** - Fixed goroutine leaks that occurred during the shutdown process for SQL and Redis datasources. This ensures proper resource cleanup and cleaner application termination.\r\n\r\n- **Migration Version Consistency** - Fixed a bug where the last migration version was not being correctly fetched across the entire chain of datasources. This ensures accurate migration state tracking, particularly in multi-datasource configurations.","date":"2026-02-06T11:20:14Z","tag":"v1.54.3","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.54.3"},{"body":"# Release v1.54.2\r\n\r\n## 🚀 Enhancement\r\n\r\n### 🔹 Smart HTTP Server Activation\r\nGoFr now intelligently manages its internal server lifecycle, conditionally booting the HTTP stack only when relevant components are registered.\r\n- **Resource Efficiency**: Drastically reduces memory and CPU overhead for gRPC-only services or background workers by keeping dormant server components inactive.\r\n- **Automated Discovery**: Dynamically identifies the need for an HTTP server based on registered routes, static files, or custom handlers.\r\n- **Streamlined Footprint**: Prevents unnecessary port occupancy and improves application startup time for specialized services.\r\n\r\n## 🛠️ Fixes\r\n\r\n- **Panic Prevention in DB Metrics**: Added essential nil checks in the database operations logic to prevent potential panics during telemetry collection.\r\n\r\n- **Migration Version Chaining**: Fixed the chaining logic for fetching the last migration version to ensure consistency across complex deployments using multiple datasources.\r\n\r\n- **Docker Compose Port Mappings**: Resolved incorrect port assignments for Redis and MySQL in the `http-server` example, streamlining the local development environment.\r\n","date":"2026-01-31T13:45:05Z","tag":"v1.54.2","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.54.2"},{"body":"# Release v1.54.1\r\n\r\n## 🚀 Features\r\n\r\n### 🔹 gRPC Authentication Middleware\r\nIntroduced comprehensive authentication support for gRPC services, bringing it on par with HTTP services.\r\n- **Supported Methods**: Basic Authentication, API Key Authentication, and OAuth.\r\n- **Seamless Integration**: Easily enable authentication for gRPC unary and streaming handlers.\r\n- **Unified Auth Interface**: Leverages the existing authentication logic for consistency across protocols. Refer : \r\n\r\n### 🔹 Standard OTEL Tracing for gRPC\r\nEnabled standard OpenTelemetry tracing for gRPC services.\r\n- **Automatic Instrumentation**: Automatically captures spans for gRPC requests and responses.\r\n- **Better Observability**: Provides detailed insights into gRPC service performance and call chains.\r\n\r\n## 🛠️ Fixes\r\n\r\n### 🔹 EventHub Consumer Group Fix\r\n- Resolved an issue where consumer groups were not being correctly interpreted in the EventHub datasource, ensuring reliable message consumption.\r\n","date":"2026-01-27T05:43:56Z","tag":"v1.54.1","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.54.1"},{"body":"# **v1.54.0**\r\n\r\n## :rocket: Features\r\n\r\n:small_blue_diamond: **Server-Side Rate Limiter Middleware**\r\n\r\nGoFr now includes a built-in **Rate Limiter Middleware** to protect your APIs from abuse and ensure fair resource distribution.\r\n- **Token Bucket Algorithm**: Implements smooth rate limiting with configurable burst capacity.\r\n- **Per-IP Rate Limiting**: Support for independent limits per client IP with trusted proxy support (`X-Forwarded-For`, `X-Real-IP`).\r\n- **Observability**: Automatically tracks rate limit violations with the `app_http_rate_limit_exceeded_total` metric.\r\n- **Exemptions**: Built-in health check endpoints (`/.well-known/alive`, `/.well-known/health`) are automatically exempt.\r\n\r\n**Usage Example**\r\n```go\r\n app.UseMiddleware(middleware.RateLimiter(middleware.RateLimiterConfig{\r\n RequestsPerSecond: 10,\r\n Burst: 20,\r\n PerIP: true,\r\n }, app.Metrics()))\r\n```\r\n\r\n## 🛠️ Fixes\r\n\r\n:small_blue_diamond: **Circuit Breaker \u0026 Health Check Refinement**\r\n\r\nImproved the reliability of the Circuit Breaker and Health Check mechanisms:\r\n- **Custom Health Endpoints**: Fixed an issue where custom health endpoints were not consistently used by the circuit breaker for recovery checks.\r\n","date":"2026-01-18T07:02:33Z","tag":"v1.54.0","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.54.0"},{"body":"# **Release v1.53.0**\r\n\r\n## 🚀 Features\r\n\r\n🔹 **Amazon SQS PubSub Support**\r\n\r\nGoFr now supports **Amazon SQS** as a messaging backend, enabling seamless integration with AWS Simple Queue Service for building resilient, distributed microservices.\r\n\r\n- Supports both **Publishing** and **Subscribing** to SQS standard queues\r\n- **Configurable Behavior**:\r\n - Support for custom message attributes\r\n - Configurable visibility timeouts and wait times\r\n - Support for standard queues\r\n\r\n#### **Usage Example**\r\n\r\nTo use Amazon SQS, import the driver and add it to your application:\r\n\r\n```go\r\nimport (\r\n \"gofr.dev/pkg/gofr\"\r\n \"gofr.dev/pkg/gofr/datasource/pubsub/sqs\"\r\n)\r\n\r\nfunc main() {\r\n app := gofr.New()\r\n\r\n app.AddPubSub(sqs.New(\u0026sqs.Config{\r\n Region: \"us-east-1\",\r\n AccessKeyID: \"your-access-key-id\", // optional if using IAM roles\r\n SecretAccessKey: \"your-secret-access-key\", // optional if using IAM roles\r\n // Endpoint: \"http://localhost:4566\", // optional: for LocalStack\r\n }))\r\n\r\n app.Subscribe(\"my-queue\", func(ctx *gofr.Context) error {\r\n // Process message\r\n return nil\r\n })\r\n\r\n app.Run()\r\n}\r\n```\r\n\r\n## 🚀 Enhancements\r\n\r\n🔹 **Metrics for HTTP Service Resilience**\r\n\r\nEnhanced observability for inter-service communication by adding dedicated metrics for resilience patterns.\r\n- New metric `app_http_retry_count`: Tracks the total number of retries performed for each downstream service\r\n- New metric `app_http_circuit_breaker_state`: A gauge tracking the current state (0 for Closed, 1 for Open) of the circuit breaker\r\n- **Updated Grafana Dashboards**: Included new panels to visualize retry events and circuit breaker transitions, providing immediate insights into service stability and failure patterns. You can refer : https://github.com/gofr-dev/gofr/tree/main/examples/http-server/docker/provisioning/dashboards/gofr-dashboard\r\n\r\n🔹 **Configurable Metrics Server**\r\n\r\nAdded the ability to **disable the internal metrics server** by setting the `METRICS_PORT` environment variable to `0`. This provides greater flexibility for users who prefer to handle metrics collection through external agents or in environments where a separate metrics port is not required.\r\n\r\n## 🛠️ Fixes\r\n\r\n🔹 **Zip Slip Vulnerability Protection**\r\n\r\nImproved the security of the `file/zip` package by implementing protection against **Zip Slip** (path traversal) attacks.\r\n- Automatically validates file paths during extraction to ensure they remain within the target directory\r\n- Rejects zip entries containing absolute paths or parent directory traversal sequences (`..`)\r\n- Ensures safe handling of compressed files from untrusted sources\r\n","date":"2026-01-10T10:03:16Z","tag":"v1.53.0","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.53.0"},{"body":"# **Release v1.52.0**\r\n\r\n## 🚀 Features\r\n\r\n🔹 **Redis PubSub Support**\r\n\r\nGoFr now supports **Redis PubSub** as a messaging backend, providing seamless integration with Redis for publish-subscribe patterns in microservices.\r\n\r\n- Supports both **Redis Channels** (traditional PubSub) and **Redis Streams** modes\r\n- Configurable via `REDIS_PUBSUB_MODE` environment variable (defaults to `streams`)\r\n- **Redis Streams** features:\r\n - Consumer groups for load balancing and message distribution\r\n - Automatic consumer group creation with `MKSTREAM` support\r\n - Configurable PEL (Pending Entry List) ratio for balancing pending vs new messages (default: 0.7, i.e., 70% PEL, 30% new messages)\r\n - Stream length management with `MaxLen` configuration\r\n - Automatic message acknowledgment handling\r\n- **Redis Channels** features:\r\n - Traditional PubSub channel support for simple messaging patterns\r\n - Automatic channel creation on first publish/subscribe\r\n- Separate database support via `REDIS_PUBSUB_DB` to prevent keyspace collisions (defaults to database 15)\r\n- Configurable buffer size, query timeout, and query limits\r\n- Automatic connection monitoring and resubscription on reconnection\r\n- Full observability with metrics, logging, and distributed tracing\r\n- Graceful error handling with permanent failure detection\r\n\r\n---\r\n\r\n## 🚀 Enhancements\r\n\r\n🔹 **HTTP Router Path Normalization**\r\n\r\nRouter now **normalizes paths before routing** to handle edge cases with double slashes and malformed paths.\r\n\r\n- Automatically cleans and normalizes request paths using `path.Clean()`\r\n- Handles empty paths, double slashes, and trailing slashes consistently\r\n- Ensures proper routing behavior regardless of path formatting in requests\r\n- Improves compatibility with various HTTP clients and reverse proxies\r\n\r\n---\r\n\r\n## 🛠️ Fixes\r\n\r\n🔹 **JSON Encoding Error Handling for NaN Values**\r\n\r\nFixed a bug where `math.NaN()` values in responses caused incorrect error handling. The responder now properly handles JSON encoding failures by:\r\n\r\n- Detecting encoding errors before writing response headers\r\n- Returning appropriate `500 Internal Server Error` status code for encoding failures\r\n\r\n🔹 **Grafana Dashboard Configuration**\r\n\r\nFixed Grafana dashboard configuration to ensure proper metrics visualization and monitoring capabilities.","date":"2026-01-02T13:45:04Z","tag":"v1.52.0","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.52.0"},{"body":"# Release v1.51.0\r\n\r\n## 🚀 Features\r\n\r\n### 🔐 Role-Based Access Control (RBAC)\r\n\r\nGoFr introduces a **config-driven RBAC middleware** for enforcing authorization across HTTP APIs without adding role or permission logic inside handlers.\r\n\r\n---\r\n\r\n### Key Highlights\r\n\r\n* Authorization defined entirely via **JSON/YAML configuration**\r\n* **Permission-based model**\r\n\r\n * Roles define permissions\r\n * Endpoints require permissions\r\n* **Header-based and JWT-based role extraction**\r\n\r\n * JWT-based RBAC supported via GoFr OAuth\r\n * JWT takes precedence when both are configured\r\n* **Role inheritance** support\r\n* **Exact permission matching** (no wildcards)\r\n* **Gorilla/mux-compatible route matching**\r\n\r\n * Supports path variables and constraints\r\n* **Safe-by-default enforcement**\r\n\r\n * Only routes defined in RBAC config are enforced\r\n\r\n---\r\n\r\n### Usage\r\n\r\nEnable RBAC using default config paths:\r\n\r\n```go\r\napp := gofr.New()\r\napp.EnableRBAC()\r\n```\r\n\r\nOr specify a custom RBAC config file:\r\n\r\n```go\r\napp.EnableRBAC(\"configs/rbac.json\")\r\n```\r\n\r\n---\r\n\r\n### JWT Integration\r\n\r\nRBAC integrates with GoFr OAuth for JWT-based authorization:\r\n\r\n```go\r\napp.EnableOAuth(\"https://auth.example.com/.well-known/jwks.json\", 10)\r\napp.EnableRBAC(\"configs/rbac.json\")\r\n```\r\n\r\nRoles are extracted from JWT claims using configurable claim paths.\r\n\r\n---\r\n\r\n### Observability\r\n\r\n* Debug logs include route matching and authorization decision details.\r\n* **Roles are excluded** from traces to avoid PII leakage.\r\n\r\n\r\n📚 **Documentation**\r\nRefer to the RBAC documentation for configuration details and advanced usage.\r\n","date":"2025-12-27T10:02:47Z","tag":"v1.51.0","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.51.0"},{"body":"# **Release v1.50.2**\r\n\r\n## 🚀 Enhancements\r\n\r\n🔹 **HTTP Connection Pool Configuration**\r\n\r\nGoFr now supports **configurable HTTP connection pool settings** to optimize performance for high-frequency HTTP requests in microservices.\r\n\r\nNew `ConnectionPoolConfig` option for `AddHTTPService()` method\r\n\r\nConfigurable settings:\r\n\r\n- `MaxIdleConns`: Maximum idle connections across all hosts (default: 100)\r\n- `MaxIdleConnsPerHost`: Maximum idle connections per host (default: 2, recommended: 10-20)\r\n- `IdleConnTimeout`: Connection keep-alive duration (default: 90 seconds)\r\n- Addresses the limitation where Go's default `MaxIdleConnsPerHost: 2` is insufficient for microservices\r\n- **Important**: `ConnectionPoolConfig` must be applied first when using multiple options \r\n\r\n\r\n🔹 **OpenTSDB Metrics Support**\r\n\r\nAdded metrics instrumentation for OpenTSDB operations to provide better observability.\r\n\r\nNew metrics:\r\n- `app_opentsdb_operation_duration`: Duration of OpenTSDB operations in milliseconds\r\n- `app_opentsdb_operation_total`: Total OpenTSDB operations\r\n- Enables monitoring and alerting on OpenTSDB data operations\r\n\r\n---\r\n \r\n\r\n## 🛠️ Fixes\r\n\r\n🔹 **Panic Recovery for OnStart Hooks**\r\nAdded panic recovery mechanism for `OnStart` hooks to prevent entire application crash. If a hook panics, the error is logged and the application continues with other hooks, improving application stability and resilience.\r\n\r\n🔹 **GCS Provider Name for Observability**\r\nAdded provider name \"GCS\" to Google Cloud Storage file store for improved logging and metrics identification. Previously it used common logging semantics \"COMMON\" shared across file storage providers leading to improper visibilty of the underlying file storage being used,\r\n\r\n🔹 **Zipkin Trace Exporter Error Handling**\r\nFixed error logging for successful trace exports (2xx status codes). Zipkin exporter now correctly ignores `201` status codes and other `2xx` responses, reducing noise in error logs for successful operations.","date":"2025-12-21T17:05:13Z","tag":"v1.50.2","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.50.2"},{"body":"# **Release v1.50.1**\r\n\r\n## 🚀 Enhancements\r\n\r\n🔹 **TLS / SSL Support for Database Connections**\r\n\r\nGoFr now supports **secure TLS/SSL connections** for relational databases(MySQL / MariaDB/PostgreSQL), improving security and compliance for production deployments.\r\n\r\n- New configuration `DB_SSL_MODE` with supported modes:\r\n \r\n - `disable`, `preferred`, `require`, `skip-verify`, `verify-ca`, `verify-full`\r\n \r\n- New environment variables for TLS configuration:\r\n \r\n - `DB_TLS_CA_CERT`\r\n \r\n - `DB_TLS_CLIENT_CERT`\r\n \r\n - `DB_TLS_CLIENT_KEY`\r\n \r\n- `verify-ca` and `verify-full` modes enforce **CA certificate validation**\r\n \r\n- **Mutual TLS (mTLS)** supported via client certificate \u0026 key\r\n- Refer [Documentation : Tracing In GoFr](https://gofr.dev/docs/quick-start/observability#tracing) for more info.\r\n----------\r\n\r\n🔹 **Custom Authentication Headers for Tracing Exporters**\r\n\r\nGoFr now allows configuring **custom authentication headers** for OpenTelemetry exporters, enabling better compatibility with hosted observability platforms.\r\n\r\nKey Highlights:\r\n\r\n- New configuration: `TRACER_HEADERS`\r\n \r\n - Accepts **comma-separated key=value pairs**\r\n \r\n - Example: `X-Api-Key=secret,Authorization=Bearer token`\r\n \r\n- `TRACER_HEADERS` takes priority over the existing `TRACER_AUTH_KEY`\r\n- Refer [Documentation : Connecting MySQL](https://gofr.dev/docs/quick-start/connecting-mysql) for more info.\r\n\r\n## 🛠️ Fixes\r\n\r\n🔹 **Mock HTTP Services Deduplication in Tests**\r\n\r\nFixed an issue where registering multiple mock HTTP services could result in **deduplication**, causing missing mocks and lost expectations during tests.\r\n\r\nFix Details:\r\n\r\n- Each service registered via `WithMockHTTPService(...)` now receives a **distinct mock instance**\r\n \r\n- Expectations must be set per service using: `mocks.HTTPServices[\"serviceName\"]`\r\n \r\n- Refer [Documentation : Testing in GoFr](https://gofr.dev/docs/references/testing) for more info.","date":"2025-12-14T13:55:15Z","tag":"v1.50.1","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.50.1"},{"body":"# **Release v1.50.0**\r\n\r\n## 🚀Features\r\n\r\n🔹 **Azure File Storage Support — New File-Store Provider**\r\n\r\nGoFr now introduces **native Azure File Storage integration** through a new provider at \r\n`gofr.dev/pkg/gofr/datasource/file/azure`.\r\n\r\nKey Highlights:\r\n\r\n- Supports configuration via **AccountName**, **AccountKey**, and **ShareName** (optional: **Endpoint**)\r\n- Automatic **connection retry loop** with connection-status logging\r\n- **Native directory support** — `Chdir`, `ReadDir`, and `Stat` behave like a real filesystem\r\n- **Automatic parent-directory creation** for nested file paths\r\n- Built-in **content-type detection** based on extension (`json`, `txt`, `csv`, `xml`, `html`, `pdf`, etc.)\r\n- One file share **per file-store instance** (explicitly documented)\r\n- Complete documentation \u0026 examples added under [Official File Handling in GoFr Documentation](https://gofr.dev/docs/advanced-guide/handling-file/page.md)\r\n\r\n### **Example**\r\n\r\n```go\r\n// Create Azure File Storage filesystem\r\nfs, err := azure.New(\u0026azure.Config{\r\n AccountName: \"mystorageaccount\",\r\n AccountKey: \"myaccountkey\",\r\n ShareName: \"myshare\",\r\n // Endpoint is optional, defaults to https://{AccountName}.file.core.windows.net\r\n // Endpoint: \"https://custom-endpoint.file.core.windows.net\",\r\n})\r\n\r\nif err != nil {\r\n app.Logger().Fatalf(\"Failed to initialize Azure File Storage: %v\", err)\r\n}\r\n\r\napp.AddFileStore(fs)\r\n\r\napp.Run()\r\n```\r\n\r\n🔹 **CLI Improvements**\r\n\r\n- More helpful `ErrCommandNotFound` message showing the **invalid command entered**\r\n- Better help formatting with **aligned command–description columns**\r\n- Enhanced behavior for no-command scenarios: prints help + clearer messaging if added.\r\n \r\n\r\n\r\n## Bug Fixes \r\n\r\n- **Basic Auth Header Normalization**\r\nAuthorization header now correctly uses **\"Basic \"** instead of **\"basic \"** adhering to RFC standard for Basic Authorization Headers.","date":"2025-12-06T07:16:16Z","tag":"v1.50.0","url":"https://github.com/gofr-dev/gofr/releases/tag/v1.50.0"}] diff --git a/src/app/cli/gofr/page.jsx b/src/app/cli/gofr/page.jsx index 8fdde1b..5508bb2 100644 --- a/src/app/cli/gofr/page.jsx +++ b/src/app/cli/gofr/page.jsx @@ -1,17 +1,56 @@ -import React from 'react'; - +import React from 'react' +import Link from 'next/link' const Page = () => { - return ( -
    -
    - - Documentation - - Coming Soon -
    -
    - ); -}; + return ( +
    +

    + GoFr CLI +

    +

    + The command-line tool for initializing projects and performing tasks with the GoFr framework. +

    + +
    +

    Installation

    + + go install gofr.dev/cli/gofr@latest + +
    + +
    + +
    +
    +

    + CLI Documentation +

    +

    + Full reference for all CLI commands and options. +

    +
    + + +
    +
    +

    + GitHub Repository +

    +

    + Source code, issues, and contributions. +

    +
    + +
    +
    + ) +} -export default Page; \ No newline at end of file +export default Page diff --git a/src/app/community/page.jsx b/src/app/community/page.jsx new file mode 100644 index 0000000..27d1476 --- /dev/null +++ b/src/app/community/page.jsx @@ -0,0 +1,144 @@ +'use client' + +import Link from 'next/link' + +const channels = [ + { + name: 'Discord', + description: 'Real-time chat with the GoFr community and maintainers. Get help, share projects, and discuss ideas.', + href: 'https://discord.gg/5ACeSKGt37', + color: 'text-indigo-400', + bgColor: 'bg-indigo-500/10', + icon: ( + + + + ), + }, + { + name: 'GitHub', + description: 'Star the repo, report issues, submit PRs, and browse the source code.', + href: 'https://github.com/gofr-dev/gofr', + color: 'text-slate-300', + bgColor: 'bg-slate-500/10', + icon: ( + + + + ), + }, + { + name: 'Reddit', + description: 'Join r/gofr for discussions, questions, and community posts about GoFr.', + href: 'https://www.reddit.com/r/gofr/', + color: 'text-orange-400', + bgColor: 'bg-orange-500/10', + icon: ( + + + + ), + }, + { + name: 'Twitter / X', + description: 'Follow @gofr_dev for release announcements, tips, and framework updates.', + href: 'https://twitter.com/gofr_dev', + color: 'text-sky-400', + bgColor: 'bg-sky-500/10', + icon: ( + + + + ), + }, + { + name: 'LinkedIn', + description: 'Connect with GoFr professionally. Company updates and engineering posts.', + href: 'https://in.linkedin.com/company/gofr-dev', + color: 'text-blue-400', + bgColor: 'bg-blue-500/10', + icon: ( + + + + ), + }, +] + +export default function CommunityPage() { + return ( +
    +
    +
    +

    + Community +

    +

    + Join thousands of developers building with GoFr. Get help, share ideas, and contribute. +

    +
    + + {/* Channel Cards */} +
    + {channels.map((channel) => ( + +
    +
    +
    +
    {channel.icon}
    +
    +

    + {channel.name} +

    +

    + {channel.description} +

    +
    + + ))} +
    + + {/* Contributing */} +
    +

    + Contribute to GoFr +

    +

    + GoFr is open source under the Apache 2.0 license. We welcome contributions of all kinds. +

    +
    + +

    Contributing Guide

    +

    How to get started

    + + +

    Good First Issues

    +

    Pick up a starter task

    + + +

    Report an Issue

    +

    Found a bug? Let us know

    + +
    +
    +
    +
    + ) +} diff --git a/src/app/examples/examples.json b/src/app/examples/examples.json new file mode 100644 index 0000000..bdc4972 --- /dev/null +++ b/src/app/examples/examples.json @@ -0,0 +1,19 @@ +[ + { "title": "HTTP Server", "description": "Basic REST API server with CRUD endpoints, Redis caching, and structured responses.", "tags": ["REST", "Getting Started"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/http-server", "featured": true }, + { "title": "gRPC Server", "description": "Build a gRPC service with protocol buffers, streaming, and automatic observability.", "tags": ["gRPC", "Communication"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/grpc", "featured": true }, + { "title": "Publisher", "description": "Publish messages to Kafka, Google Pub/Sub, NATS, or MQTT with a unified API.", "tags": ["Pub/Sub", "Messaging"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-publisher", "featured": true }, + { "title": "Subscriber", "description": "Subscribe to message topics with automatic offset management and error handling.", "tags": ["Pub/Sub", "Messaging"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-subscriber" }, + { "title": "HTTP Server with Redis", "description": "REST API backed by Redis for caching and session management.", "tags": ["REST", "Redis", "Database"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/http-server-using-redis" }, + { "title": "REST Handlers", "description": "Auto-generate CRUD endpoints by implementing the REST interface.", "tags": ["REST", "Getting Started"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-add-rest-handlers" }, + { "title": "Data Migrations", "description": "Run versioned schema migrations across MySQL, PostgreSQL, Redis, and MongoDB.", "tags": ["Database", "Migrations"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations" }, + { "title": "GraphQL API", "description": "Schema-first GraphQL with resolvers, playground, and built-in observability.", "tags": ["GraphQL", "Communication"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-graphql" }, + { "title": "WebSocket", "description": "Real-time bidirectional communication with WebSocket support.", "tags": ["WebSocket", "Communication"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-web-socket" }, + { "title": "Cron Jobs", "description": "Schedule recurring tasks with cron expressions and automatic metrics.", "tags": ["Background", "Scheduling"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-cron-jobs" }, + { "title": "Custom Metrics", "description": "Publish application-specific Prometheus metrics alongside built-in observability.", "tags": ["Observability", "Metrics"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-custom-metrics" }, + { "title": "HTTP Service Communication", "description": "Make inter-service HTTP calls with circuit breaker and retry support.", "tags": ["Communication", "Resilience"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-http-service" }, + { "title": "Auth Middleware", "description": "Protect endpoints with Basic Auth, API Key, or OAuth middleware.", "tags": ["Security", "Middleware"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-http-auth-middleware" }, + { "title": "File Handling", "description": "Upload, download, and manage files with local, S3, GCS, or FTP backends.", "tags": ["Files", "Storage"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-add-filestore" }, + { "title": "File Binding", "description": "Bind uploaded files directly to structs for type-safe file processing.", "tags": ["Files", "Data Binding"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-file-bind" }, + { "title": "HTML Templates", "description": "Serve server-rendered HTML pages with Go template support.", "tags": ["Templates", "Frontend"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/using-html-template" }, + { "title": "CLI Application", "description": "Build command-line tools with subcommands, flags, and structured output.", "tags": ["CLI", "Tools"], "href": "https://github.com/gofr-dev/gofr/tree/main/examples/sample-cmd" } +] diff --git a/src/app/examples/page.jsx b/src/app/examples/page.jsx new file mode 100644 index 0000000..c1715cc --- /dev/null +++ b/src/app/examples/page.jsx @@ -0,0 +1,151 @@ +'use client' + +import { useState } from 'react' +import Link from 'next/link' +import examples from './examples.json' + +const tagColors = { + 'REST': 'bg-emerald-500/10 text-emerald-400', + 'gRPC': 'bg-violet-500/10 text-violet-400', + 'Pub/Sub': 'bg-sky-500/10 text-sky-400', + 'Messaging': 'bg-sky-500/10 text-sky-400', + 'Database': 'bg-amber-500/10 text-amber-400', + 'Redis': 'bg-red-500/10 text-red-400', + 'Communication': 'bg-blue-500/10 text-blue-400', + 'Migrations': 'bg-amber-500/10 text-amber-400', + 'GraphQL': 'bg-pink-500/10 text-pink-400', + 'WebSocket': 'bg-indigo-500/10 text-indigo-400', + 'Background': 'bg-slate-500/10 text-slate-400', + 'Scheduling': 'bg-slate-500/10 text-slate-400', + 'Observability': 'bg-cyan-500/10 text-cyan-400', + 'Metrics': 'bg-cyan-500/10 text-cyan-400', + 'Resilience': 'bg-orange-500/10 text-orange-400', + 'Security': 'bg-red-500/10 text-red-400', + 'Middleware': 'bg-purple-500/10 text-purple-400', + 'Files': 'bg-teal-500/10 text-teal-400', + 'Storage': 'bg-teal-500/10 text-teal-400', + 'Data Binding': 'bg-lime-500/10 text-lime-400', + 'Templates': 'bg-rose-500/10 text-rose-400', + 'Frontend': 'bg-rose-500/10 text-rose-400', + 'CLI': 'bg-slate-500/10 text-slate-300', + 'Tools': 'bg-slate-500/10 text-slate-400', + 'Getting Started': 'bg-emerald-500/10 text-emerald-400', +} + +const allTags = [...new Set(examples.flatMap((e) => e.tags))] + +export default function ExamplesPage() { + let [activeTag, setActiveTag] = useState(null) + + let filtered = activeTag + ? examples.filter((e) => e.tags.includes(activeTag)) + : examples + + let featured = examples.filter((e) => e.featured) + + return ( +
    +
    +
    +

    + Examples & Recipes +

    +

    + Learn GoFr by example. Each recipe is a working project you can clone and run. +

    +
    + + {/* Featured */} + {!activeTag && ( +
    +

    + Start here +

    +
    + {featured.map((example) => ( + +
    +
    +

    {example.title}

    +

    {example.description}

    +
    + {example.tags.map((tag) => ( + + {tag} + + ))} +
    +
    + + ))} +
    +
    + )} + + {/* Tag filter */} +
    + + {allTags.map((tag) => ( + + ))} +
    + + {/* All examples */} +
    + {filtered.map((example) => ( + +
    +
    +

    {example.title}

    +

    {example.description}

    +
    + {example.tags.map((tag) => ( + + {tag} + + ))} +
    +
    + + ))} +
    + + {/* CTA */} +
    + + Browse all examples on GitHub → + +
    +
    +
    + ) +} diff --git a/src/app/pkg/gofr/datasource/arangodb/page.jsx b/src/app/pkg/gofr/datasource/arangodb/page.jsx index f8bffb5..c9fddad 100644 --- a/src/app/pkg/gofr/datasource/arangodb/page.jsx +++ b/src/app/pkg/gofr/datasource/arangodb/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/cassandra/page.jsx b/src/app/pkg/gofr/datasource/cassandra/page.jsx index f8bffb5..426e795 100644 --- a/src/app/pkg/gofr/datasource/cassandra/page.jsx +++ b/src/app/pkg/gofr/datasource/cassandra/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/clickhouse/page.jsx b/src/app/pkg/gofr/datasource/clickhouse/page.jsx index f8bffb5..77884b5 100644 --- a/src/app/pkg/gofr/datasource/clickhouse/page.jsx +++ b/src/app/pkg/gofr/datasource/clickhouse/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/couchbase/page.jsx b/src/app/pkg/gofr/datasource/couchbase/page.jsx index f8bffb5..951205d 100644 --- a/src/app/pkg/gofr/datasource/couchbase/page.jsx +++ b/src/app/pkg/gofr/datasource/couchbase/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/dbresolver/page.jsx b/src/app/pkg/gofr/datasource/dbresolver/page.jsx index f8bffb5..afca3c7 100644 --- a/src/app/pkg/gofr/datasource/dbresolver/page.jsx +++ b/src/app/pkg/gofr/datasource/dbresolver/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/dgraph/page.jsx b/src/app/pkg/gofr/datasource/dgraph/page.jsx index f8bffb5..4f03272 100644 --- a/src/app/pkg/gofr/datasource/dgraph/page.jsx +++ b/src/app/pkg/gofr/datasource/dgraph/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/elasticsearch/page.jsx b/src/app/pkg/gofr/datasource/elasticsearch/page.jsx index f8bffb5..151bc99 100644 --- a/src/app/pkg/gofr/datasource/elasticsearch/page.jsx +++ b/src/app/pkg/gofr/datasource/elasticsearch/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/file/azure/page.jsx b/src/app/pkg/gofr/datasource/file/azure/page.jsx index f8bffb5..b2efc95 100644 --- a/src/app/pkg/gofr/datasource/file/azure/page.jsx +++ b/src/app/pkg/gofr/datasource/file/azure/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/file/ftp/page.jsx b/src/app/pkg/gofr/datasource/file/ftp/page.jsx index f8bffb5..0df0ce2 100644 --- a/src/app/pkg/gofr/datasource/file/ftp/page.jsx +++ b/src/app/pkg/gofr/datasource/file/ftp/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/file/gcs/page.jsx b/src/app/pkg/gofr/datasource/file/gcs/page.jsx index f8bffb5..a1ab84c 100644 --- a/src/app/pkg/gofr/datasource/file/gcs/page.jsx +++ b/src/app/pkg/gofr/datasource/file/gcs/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/file/s3/page.jsx b/src/app/pkg/gofr/datasource/file/s3/page.jsx index f8bffb5..b22320b 100644 --- a/src/app/pkg/gofr/datasource/file/s3/page.jsx +++ b/src/app/pkg/gofr/datasource/file/s3/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/file/sftp/page.jsx b/src/app/pkg/gofr/datasource/file/sftp/page.jsx index f8bffb5..f6adc0f 100644 --- a/src/app/pkg/gofr/datasource/file/sftp/page.jsx +++ b/src/app/pkg/gofr/datasource/file/sftp/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/kv-store/badger/page.jsx b/src/app/pkg/gofr/datasource/kv-store/badger/page.jsx index f8bffb5..9445d86 100644 --- a/src/app/pkg/gofr/datasource/kv-store/badger/page.jsx +++ b/src/app/pkg/gofr/datasource/kv-store/badger/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/kv-store/nats/page.jsx b/src/app/pkg/gofr/datasource/kv-store/nats/page.jsx index f8bffb5..6317a1a 100644 --- a/src/app/pkg/gofr/datasource/kv-store/nats/page.jsx +++ b/src/app/pkg/gofr/datasource/kv-store/nats/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/mongo/page.jsx b/src/app/pkg/gofr/datasource/mongo/page.jsx index f8bffb5..8c8aee7 100644 --- a/src/app/pkg/gofr/datasource/mongo/page.jsx +++ b/src/app/pkg/gofr/datasource/mongo/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/opentsdb/page.jsx b/src/app/pkg/gofr/datasource/opentsdb/page.jsx index f8bffb5..a90b283 100644 --- a/src/app/pkg/gofr/datasource/opentsdb/page.jsx +++ b/src/app/pkg/gofr/datasource/opentsdb/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/oracle/page.jsx b/src/app/pkg/gofr/datasource/oracle/page.jsx index f8bffb5..7066bf0 100644 --- a/src/app/pkg/gofr/datasource/oracle/page.jsx +++ b/src/app/pkg/gofr/datasource/oracle/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/pubsub/eventhub/page.jsx b/src/app/pkg/gofr/datasource/pubsub/eventhub/page.jsx index f8bffb5..ea74ae8 100644 --- a/src/app/pkg/gofr/datasource/pubsub/eventhub/page.jsx +++ b/src/app/pkg/gofr/datasource/pubsub/eventhub/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/pubsub/nats/page.jsx b/src/app/pkg/gofr/datasource/pubsub/nats/page.jsx index f8bffb5..00207f8 100644 --- a/src/app/pkg/gofr/datasource/pubsub/nats/page.jsx +++ b/src/app/pkg/gofr/datasource/pubsub/nats/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/pubsub/sqs/page.jsx b/src/app/pkg/gofr/datasource/pubsub/sqs/page.jsx index f8bffb5..8cf2d4c 100644 --- a/src/app/pkg/gofr/datasource/pubsub/sqs/page.jsx +++ b/src/app/pkg/gofr/datasource/pubsub/sqs/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/scylladb/page.jsx b/src/app/pkg/gofr/datasource/scylladb/page.jsx index f8bffb5..1c93503 100644 --- a/src/app/pkg/gofr/datasource/scylladb/page.jsx +++ b/src/app/pkg/gofr/datasource/scylladb/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/solr/page.jsx b/src/app/pkg/gofr/datasource/solr/page.jsx index f8bffb5..cad951a 100644 --- a/src/app/pkg/gofr/datasource/solr/page.jsx +++ b/src/app/pkg/gofr/datasource/solr/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/pkg/gofr/datasource/surrealdb/page.jsx b/src/app/pkg/gofr/datasource/surrealdb/page.jsx index f8bffb5..410f619 100644 --- a/src/app/pkg/gofr/datasource/surrealdb/page.jsx +++ b/src/app/pkg/gofr/datasource/surrealdb/page.jsx @@ -1,16 +1,5 @@ -import React from 'react'; +import { PkgRedirect } from '@/components/PkgRedirect' - -const Page = () => { - return ( -
    -
    - - - -
    -
    - ); -}; - -export default Page; \ No newline at end of file +export default function Page() { + return +} diff --git a/src/app/releases/layout.jsx b/src/app/releases/layout.jsx index 568878a..1d96595 100644 --- a/src/app/releases/layout.jsx +++ b/src/app/releases/layout.jsx @@ -1,8 +1,22 @@ 'use client' -import { ReleasesPage } from '@/components/ReleasesPage' + +import { useEffect } from 'react' +import { useRouter } from 'next/navigation' const Layout = ({ children }) => { - return {children} + const router = useRouter() + + useEffect(() => { + router.replace('/changelog') + }, [router]) + + return ( +
    +

    + Redirecting to changelog... +

    +
    + ) } export default Layout diff --git a/src/app/showcase/companies.json b/src/app/showcase/companies.json new file mode 100644 index 0000000..ff2bee5 --- /dev/null +++ b/src/app/showcase/companies.json @@ -0,0 +1,12 @@ +[ + { "name": "American Express", "industry": "Financial Services" }, + { "name": "IBM", "industry": "Technology" }, + { "name": "McAfee", "industry": "Cybersecurity" }, + { "name": "Blinkit", "industry": "E-commerce" }, + { "name": "Walmart", "industry": "Retail" }, + { "name": "Doceree", "industry": "AdTech" }, + { "name": "Mydbops", "industry": "Database Consulting" }, + { "name": "Guidewire", "industry": "Insurance Technology" }, + { "name": "Weave", "industry": "Technology" }, + { "name": "ZopSmart", "industry": "E-commerce Technology" } +] diff --git a/src/app/showcase/page.jsx b/src/app/showcase/page.jsx new file mode 100644 index 0000000..49a8c0c --- /dev/null +++ b/src/app/showcase/page.jsx @@ -0,0 +1,138 @@ +'use client' + +import { useEffect, useState } from 'react' +import Image from 'next/image' +import Link from 'next/link' +import { formatNumber } from '@/lib/common' +import companies from './companies.json' +import testimonials from '../../../utils/testimonials.json' + +import company1 from '@/images/doceree.svg' +import company2 from '@/images/americanExpress.svg' +import company3 from '@/images/ibm.svg' +import company4 from '@/images/mydbops.svg' +import company5 from '@/images/guidewire.svg' +import company6 from '@/images/weave.svg' +import company8 from '@/images/blinkit.svg' +import company9 from '@/images/zopsmart.svg' +import company10 from '@/images/mcafee.svg' +import company11 from '@/images/walmart.svg' + +const logoMap = { + 'American Express': company2, + 'IBM': company3, + 'McAfee': company10, + 'Blinkit': company8, + 'Walmart': company11, + 'Doceree': company1, + 'Mydbops': company4, + 'Guidewire': company5, + 'Weave': company6, + 'ZopSmart': company9, +} + +export default function ShowcasePage() { + const [githubStars, setGithubStars] = useState('3500+') + + useEffect(() => { + let cached = localStorage.getItem('githubStars') + if (cached) setGithubStars(formatNumber(Number(cached))) + }, []) + + return ( +
    +
    + {/* Hero */} +
    +

    + Trusted by Engineers Worldwide +

    +

    + GoFr powers production microservices at companies of all sizes — from startups to Fortune 500. +

    +
    + + + + {githubStars} stars on GitHub +
    +
    + + {/* Company Grid */} +
    + {companies.map((company) => ( +
    +
    +
    + {logoMap[company.name] && ( + {company.name} + )} +

    {company.industry}

    +
    +
    + ))} +
    + + {/* Testimonials */} +
    +

    + What Engineers Say +

    +
    + {testimonials.map((t, i) => ( +
    +

    + “{t.quote}” +

    +
    + {t.profile && ( + {t.author} + )} +
    +

    {t.author}

    +

    {t.role}

    +
    +
    +
    + ))} +
    +
    + + {/* CTA */} +
    +

    Using GoFr in production?

    + + Add your company to the showcase + + + + + +
    +
    +
    + ) +} diff --git a/src/app/sitemap.xml b/src/app/sitemap.xml index 9b5e3a3..d8e852f 100644 --- a/src/app/sitemap.xml +++ b/src/app/sitemap.xml @@ -2,188 +2,77 @@ https://gofr.dev/ - 2024-10-09T13:34:20+00:00 1.0 weekly https://gofr.dev/docs - 2024-10-09T13:34:20+00:00 0.9 weekly - https://gofr.dev/docs/advanced-guide/handling-file - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/injecting-databases-drivers - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/quick-start/connecting-redis - 2024-10-09T13:34:20+00:00 - 0.8 - weekly - - - https://gofr.dev/docs/advanced-guide/using-publisher-subscriber - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/dealing-with-sql - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/key-value-store - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/quick-start/introduction - 2024-10-09T13:34:20+00:00 - 0.8 - weekly - - - https://gofr.dev/docs/quick-start/configuration - 2024-10-09T13:34:20+00:00 - 0.8 - weekly - - - https://gofr.dev/docs/quick-start/connecting-mysql - 2024-10-09T13:34:20+00:00 - 0.8 - weekly - - - https://gofr.dev/docs/quick-start/observability - 2024-10-09T13:34:20+00:00 - 0.8 - weekly - - - https://gofr.dev/docs/quick-start/add-rest-handlers - 2024-10-09T13:34:20+00:00 - 0.8 - weekly - - - https://gofr.dev/docs/advanced-guide/using-cron - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/overriding-default - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/remote-log-level-change - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/publishing-custom-metrics - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/custom-spans-in-tracing - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/middlewares - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/http-communication - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/http-authentication - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/circuit-breaker - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/monitoring-service-health - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/handling-data-migrations - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/grpc - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/swagger-documentation - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/gofr-errors - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/advanced-guide/websocket - 2024-10-09T13:34:20+00:00 - 0.7 - weekly - - - https://gofr.dev/docs/references/context - 2024-10-09T13:34:20+00:00 - 0.6 - weekly - - - https://gofr.dev/docs/references/configs - 2024-10-09T13:34:20+00:00 + https://gofr.dev/events 0.6 - weekly - - - https://gofr.dev/docs/references/testing - 2024-10-09T13:34:20+00:00 - 0.6 - weekly - - \ No newline at end of file + monthly + + + + https://gofr.dev/docs/quick-start/introduction0.8weekly + https://gofr.dev/docs/quick-start/configuration0.8weekly + https://gofr.dev/docs/quick-start/connecting-redis0.8weekly + https://gofr.dev/docs/quick-start/connecting-mysql0.8weekly + https://gofr.dev/docs/quick-start/observability0.8weekly + https://gofr.dev/docs/quick-start/add-rest-handlers0.8weekly + + + https://gofr.dev/docs/advanced-guide/using-cron0.7weekly + https://gofr.dev/docs/advanced-guide/overriding-default0.7weekly + https://gofr.dev/docs/advanced-guide/remote-log-level-change0.7weekly + https://gofr.dev/docs/advanced-guide/publishing-custom-metrics0.7weekly + https://gofr.dev/docs/advanced-guide/setting-custom-response-headers0.7weekly + https://gofr.dev/docs/advanced-guide/custom-spans-in-tracing0.7weekly + https://gofr.dev/docs/advanced-guide/middlewares0.7weekly + https://gofr.dev/docs/advanced-guide/http-communication0.7weekly + https://gofr.dev/docs/advanced-guide/authentication0.7weekly + https://gofr.dev/docs/advanced-guide/rbac0.7weekly + https://gofr.dev/docs/advanced-guide/circuit-breaker0.7weekly + https://gofr.dev/docs/advanced-guide/monitoring-service-health0.7weekly + https://gofr.dev/docs/advanced-guide/handling-data-migrations0.7weekly + https://gofr.dev/docs/advanced-guide/grpc0.7weekly + https://gofr.dev/docs/advanced-guide/grpc-streaming0.7weekly + https://gofr.dev/docs/advanced-guide/using-publisher-subscriber0.7weekly + https://gofr.dev/docs/advanced-guide/key-value-store0.7weekly + https://gofr.dev/docs/advanced-guide/dealing-with-sql0.7weekly + https://gofr.dev/docs/advanced-guide/swagger-documentation0.7weekly + https://gofr.dev/docs/advanced-guide/startup-hooks0.7weekly + https://gofr.dev/docs/advanced-guide/gofr-errors0.7weekly + https://gofr.dev/docs/advanced-guide/handling-file0.7weekly + https://gofr.dev/docs/advanced-guide/websocket0.7weekly + https://gofr.dev/docs/advanced-guide/graphql0.7weekly + https://gofr.dev/docs/advanced-guide/serving-static-files0.7weekly + https://gofr.dev/docs/advanced-guide/debugging0.7weekly + https://gofr.dev/docs/advanced-guide/building-cli-applications0.7weekly + + + https://gofr.dev/docs/datasources/getting-started0.7weekly + https://gofr.dev/docs/datasources/arangodb0.6monthly + https://gofr.dev/docs/datasources/cassandra0.6monthly + https://gofr.dev/docs/datasources/clickhouse0.6monthly + https://gofr.dev/docs/datasources/cockroachdb0.6monthly + https://gofr.dev/docs/datasources/couchbase0.6monthly + https://gofr.dev/docs/datasources/dgraph0.6monthly + https://gofr.dev/docs/datasources/mongodb0.7monthly + https://gofr.dev/docs/datasources/opentsdb0.6monthly + https://gofr.dev/docs/datasources/oracle0.6monthly + https://gofr.dev/docs/datasources/scylladb0.6monthly + https://gofr.dev/docs/datasources/solr0.6monthly + https://gofr.dev/docs/datasources/surrealdb0.6monthly + https://gofr.dev/docs/datasources/elasticsearch0.6monthly + https://gofr.dev/docs/datasources/influxdb0.6monthly + + + https://gofr.dev/docs/references/context0.7weekly + https://gofr.dev/docs/references/configs0.7weekly + https://gofr.dev/docs/references/testing0.7weekly + https://gofr.dev/docs/references/gofrcli0.7weekly + diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx index e3a96ac..fe9d53e 100644 --- a/src/components/Footer.jsx +++ b/src/components/Footer.jsx @@ -39,9 +39,12 @@ const socialMediaLinks = [ ] const footerLinks = [ - // { title: 'Releases', link: '/releases' }, { title: 'Documentation', link: '/docs' }, - { title: 'Blogs', link: 'https://medium.com/gofr', target_blank: true }, + { title: 'Changelog', link: '/changelog' }, + { title: 'Examples', link: '/examples' }, + { title: 'Community', link: '/community' }, + { title: 'Showcase', link: '/showcase' }, + { title: 'Blog', link: 'https://medium.com/gofr', target_blank: true }, { title: 'Events', link: '/events' }, ] diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx index 8621a00..78b9e90 100644 --- a/src/components/Layout.jsx +++ b/src/components/Layout.jsx @@ -7,10 +7,10 @@ import clsx from 'clsx' import { MobileNavigation } from '@/components/MobileNavigation' import { Search } from '@/components/Search' + import { formatNumber } from '@/lib/common' import { ErrorBoundary } from './BugsnagWrapper' import FooterUi from '@/components/Footer' -// import { HackathonLinkButton } from './goforgofr/HackathonLinkButton' export function GitHubIcon(props) { return ( @@ -20,6 +20,13 @@ export function GitHubIcon(props) { ) } +const navLinks = [ + { title: 'Docs', href: '/docs', match: '/docs' }, + { title: 'Changelog', href: '/changelog', match: '/changelog' }, + { title: 'Examples', href: '/examples', match: '/examples' }, + { title: 'Community', href: '/community', match: '/community' }, +] + function Header() { let [isScrolled, setIsScrolled] = useState(false) let pathname = usePathname() @@ -71,7 +78,7 @@ function Header() {
    )} -
    +
    Go{' '} @@ -80,6 +87,31 @@ function Header() { + {!isCertificate && ( + + )}
    {!isCertificate && !isEvents && (
    @@ -93,7 +125,7 @@ function Header() {
    )} -
    +
    ( export function Layout({ children }) { const pathname = usePathname() - console.log(pathname) - - const isHackathon = pathname === '/hackathon' return (
    {pathname !== '/hackathon' && ( <> - {/*
    - -
    */}
    diff --git a/src/components/MobileNavigation.jsx b/src/components/MobileNavigation.jsx index c404f5c..c497135 100644 --- a/src/components/MobileNavigation.jsx +++ b/src/components/MobileNavigation.jsx @@ -49,6 +49,15 @@ function CloseOnNavigation({ close }) { return null } +const siteLinks = [ + { title: 'Docs', href: '/docs' }, + { title: 'Changelog', href: '/changelog' }, + { title: 'Examples', href: '/examples' }, + { title: 'Community', href: '/community' }, + { title: 'Showcase', href: '/showcase' }, + { title: 'Blog', href: 'https://medium.com/gofr', external: true }, +] + export function MobileNavigation() { let [isOpen, setIsOpen] = useState(false) let close = useCallback(() => setIsOpen(false), [setIsOpen]) @@ -95,6 +104,28 @@ export function MobileNavigation() {
    + diff --git a/src/components/PkgRedirect.jsx b/src/components/PkgRedirect.jsx new file mode 100644 index 0000000..b27b0e1 --- /dev/null +++ b/src/components/PkgRedirect.jsx @@ -0,0 +1,50 @@ +'use client' + +import { useEffect } from 'react' +import Link from 'next/link' + +export function PkgRedirect({ name, docsPath }) { + useEffect(() => { + if (docsPath) { + const timer = setTimeout(() => { + window.location.href = docsPath + }, 3000) + return () => clearTimeout(timer) + } + }, [docsPath]) + + return ( +
    +
    +

    Go Package

    +

    + {name} +

    +

    + This page exists for Go module import resolution. +

    + {docsPath ? ( + + View documentation + + + + + ) : ( + + View datasource documentation + + + + + )} +
    +
    + ) +} diff --git a/src/components/Search.jsx b/src/components/Search.jsx index cab6634..5a9dbc1 100644 --- a/src/components/Search.jsx +++ b/src/components/Search.jsx @@ -50,7 +50,7 @@ function useAutocomplete({ close }) { let [autocomplete] = useState(() => createAutocomplete({ id, - placeholder: 'Find something...', + placeholder: 'Search docs...', defaultActiveItemId: 0, onStateChange({ state }) { setAutocompleteState(state) @@ -67,12 +67,15 @@ function useAutocomplete({ close }) { { sourceId: 'documentation', getItems() { - return search(query, { limit: 5 }) + let result = search(query, { limit: 8 }) + // Handle both { items: [...] } and direct array formats + if (result && result.items) return result.items + if (Array.isArray(result)) return result + return [] }, getItemUrl({ item }) { return item?.url || '' }, - onSelect: navigate, }, ] @@ -116,63 +119,44 @@ function LoadingIcon(props) { function HighlightQuery({ text, query }) { return ( ) } -function SearchResult({ result, autocomplete, collection, query, index }) { +function SearchResult({ result, autocomplete, collection, query }) { let sectionTitle = navigation.find((section) => - section.links.find((link) => link.href === result?.url.split('#')[0]), + section.links.find((link) => link.href === result?.url?.split('#')[0]), )?.title let hierarchy = [sectionTitle, result.pageTitle].filter( - (x) => typeof x === 'string', + (x) => typeof x === 'string' && x.trim() !== '', ) const id = useId() return (
  • { - e.currentTarget.classList.add('bg-slate-100', 'dark:bg-slate-700/30') - const titleEl = e.currentTarget.querySelector('[data-title]') - if (titleEl) { - titleEl.classList.add('text-sky-600', 'dark:text-sky-400') - titleEl.classList.remove('text-slate-700', 'dark:text-slate-300') - } - }} - onMouseLeave={(e) => { - e.currentTarget.classList.remove('bg-slate-100', 'dark:bg-slate-700/30') - const titleEl = e.currentTarget.querySelector('[data-title]') - if (titleEl) { - titleEl.classList.remove('text-sky-600', 'dark:text-sky-400') - titleEl.classList.add('text-slate-700', 'dark:text-slate-300') - } - }} > {hierarchy.length > 0 && (