mirror of
https://github.com/dathere/ckanaction.git
synced 2025-12-18 16:29:25 +00:00
feat: add highlights and underlines to first doc page, fix OpenAPI CSS
This commit is contained in:
parent
1de7c29050
commit
6f8107249f
5 changed files with 136 additions and 3 deletions
|
|
@ -2,6 +2,7 @@
|
|||
@import 'fumadocs-ui/css/neutral.css';
|
||||
@import "fumadocs-ui/css/ocean.css";
|
||||
@import "fumadocs-ui/css/preset.css";
|
||||
@import 'fumadocs-openapi/css/preset.css';
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@
|
|||
"fumadocs-openapi": "^10.1.4",
|
||||
"fumadocs-ui": "16.2.5",
|
||||
"lucide-react": "^0.561.0",
|
||||
"motion": "^12.23.26",
|
||||
"next": "^16.0.10",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"rough-notation": "^0.5.1",
|
||||
"shiki": "^3.20.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
},
|
||||
|
|
@ -459,6 +461,8 @@
|
|||
|
||||
"foreach": ["foreach@2.0.6", "", {}, "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg=="],
|
||||
|
||||
"framer-motion": ["framer-motion@12.23.26", "", { "dependencies": { "motion-dom": "^12.23.23", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA=="],
|
||||
|
||||
"fumadocs-core": ["fumadocs-core@16.2.5", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.6.2", "@orama/orama": "^3.1.16", "@shikijs/rehype": "^3.20.0", "@shikijs/transformers": "^3.20.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.20.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.19.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-u07n2oQJ2XaEQpWOdCyJnICYEasQiZhTFNf40C+Q2AJ3kKFeiz42mHccea0t/sjfBbO9pEDHyvZVHhSf/Cm3AA=="],
|
||||
|
||||
"fumadocs-mdx": ["fumadocs-mdx@14.1.0", "", { "dependencies": { "@mdx-js/mdx": "^3.1.1", "@standard-schema/spec": "^1.0.0", "chokidar": "^5.0.0", "esbuild": "^0.27.1", "estree-util-value-to-estree": "^3.5.0", "js-yaml": "^4.1.1", "mdast-util-to-markdown": "^2.1.2", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "remark-mdx": "^3.1.1", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3", "zod": "^4.1.13" }, "peerDependencies": { "@fumadocs/mdx-remote": "^1.4.0", "fumadocs-core": "^15.0.0 || ^16.0.0", "next": "^15.3.0 || ^16.0.0", "react": "*", "vite": "6.x.x || 7.x.x" }, "optionalPeers": ["@fumadocs/mdx-remote", "next", "react", "vite"], "bin": { "fumadocs-mdx": "dist/bin.js" } }, "sha512-6I3nXzM3+dSap5UZvKFQvOaKNKdMfxK5/8Cyu3am6zm0d/acuUxT1r1s1GQpc8H5iB9bFMtwyoZff1WN2qWq8g=="],
|
||||
|
|
@ -649,6 +653,12 @@
|
|||
|
||||
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
|
||||
|
||||
"motion": ["motion@12.23.26", "", { "dependencies": { "framer-motion": "^12.23.26", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-Ll8XhVxY8LXMVYTCfme27WH2GjBrCIzY4+ndr5QKxsK+YwCtOi2B/oBi5jcIbik5doXuWT/4KKDOVAZJkeY5VQ=="],
|
||||
|
||||
"motion-dom": ["motion-dom@12.23.23", "", { "dependencies": { "motion-utils": "^12.23.6" } }, "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA=="],
|
||||
|
||||
"motion-utils": ["motion-utils@12.23.6", "", {}, "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
|
@ -729,6 +739,8 @@
|
|||
|
||||
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||
|
||||
"rough-notation": ["rough-notation@0.5.1", "", {}, "sha512-ITHofTzm13cWFVfoGsh/4c/k2Mg8geKgBCwex71UZLnNuw403tCRjYPQ68jSAd37DMbZIePXPjDgY0XdZi9HPw=="],
|
||||
|
||||
"sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="],
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
|
|
|||
103
docs/components/ui/highlighter.tsx
Normal file
103
docs/components/ui/highlighter.tsx
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
"use client"
|
||||
|
||||
import { useEffect, useRef } from "react"
|
||||
import type React from "react"
|
||||
import { useInView } from "motion/react"
|
||||
import { annotate } from "rough-notation"
|
||||
import { type RoughAnnotation } from "rough-notation/lib/model"
|
||||
|
||||
type AnnotationAction =
|
||||
| "highlight"
|
||||
| "underline"
|
||||
| "box"
|
||||
| "circle"
|
||||
| "strike-through"
|
||||
| "crossed-off"
|
||||
| "bracket"
|
||||
|
||||
interface HighlighterProps {
|
||||
children: React.ReactNode
|
||||
action?: AnnotationAction
|
||||
color?: string
|
||||
strokeWidth?: number
|
||||
animationDuration?: number
|
||||
iterations?: number
|
||||
padding?: number
|
||||
multiline?: boolean
|
||||
isView?: boolean
|
||||
}
|
||||
|
||||
export function Highlighter({
|
||||
children,
|
||||
action = "highlight",
|
||||
color = "#ffd1dc",
|
||||
strokeWidth = 1.5,
|
||||
animationDuration = 600,
|
||||
iterations = 2,
|
||||
padding = 2,
|
||||
multiline = true,
|
||||
isView = false,
|
||||
}: HighlighterProps) {
|
||||
const elementRef = useRef<HTMLSpanElement>(null)
|
||||
const annotationRef = useRef<RoughAnnotation | null>(null)
|
||||
|
||||
const isInView = useInView(elementRef, {
|
||||
once: true,
|
||||
margin: "-10%",
|
||||
})
|
||||
|
||||
// If isView is false, always show. If isView is true, wait for inView
|
||||
const shouldShow = !isView || isInView
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldShow) return
|
||||
|
||||
const element = elementRef.current
|
||||
if (!element) return
|
||||
|
||||
const annotationConfig = {
|
||||
type: action,
|
||||
color,
|
||||
strokeWidth,
|
||||
animationDuration,
|
||||
iterations,
|
||||
padding,
|
||||
multiline,
|
||||
}
|
||||
|
||||
const annotation = annotate(element, annotationConfig)
|
||||
|
||||
annotationRef.current = annotation
|
||||
annotationRef.current.show()
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
annotation.hide()
|
||||
annotation.show()
|
||||
})
|
||||
|
||||
resizeObserver.observe(element)
|
||||
resizeObserver.observe(document.body)
|
||||
|
||||
return () => {
|
||||
if (element) {
|
||||
annotate(element, { type: action }).remove()
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}
|
||||
}, [
|
||||
shouldShow,
|
||||
action,
|
||||
color,
|
||||
strokeWidth,
|
||||
animationDuration,
|
||||
iterations,
|
||||
padding,
|
||||
multiline,
|
||||
])
|
||||
|
||||
return (
|
||||
<span ref={elementRef} className="relative inline-block bg-transparent">
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
@ -2,7 +2,9 @@
|
|||
title: ckanaction docs
|
||||
---
|
||||
|
||||
ckanaction is a Rust library crate that acts as an API wrapper for the CKAN Actions API (v3).
|
||||
import { Highlighter } from "@/components/ui/highlighter"
|
||||
|
||||
<Highlighter animationDuration={2000} isView action="box" color="#2596be">ckanaction is a <Highlighter animationDuration={5000} isView action="highlight" color="#2596be">Rust library crate</Highlighter> that acts as an API wrapper for the CKAN Actions API (v3). There is also an <Highlighter animationDuration={5000} isView action="highlight" color="#2596be">interactive web GUI</Highlighter>.</Highlighter>
|
||||
|
||||
This means that instead of using generic request library crates such as `reqwest`, a developer can use `ckanaction` instead to make API calls to their CKAN instance.
|
||||
|
||||
|
|
@ -35,8 +37,21 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
The source code of ckanaction can be found at [github.com/dathere/ckanaction](https://github.com/ckanaction).
|
||||
|
||||
You may also explore this web app to view more code examples for each endpoint and also use an interactive GUI for sending HTTP requests to any local or remote CKAN instance.
|
||||
<Highlighter isView action="underline" color="#2596be">You may also explore this web app</Highlighter> to view more code examples for each endpoint and also <Highlighter isView action="underline" color="#2596be">use an interactive GUI</Highlighter> for sending HTTP requests to any local or remote CKAN instance.
|
||||
|
||||
View the GIF below to see how to point to a specific CKAN API endpoint using the interactive GUI, which by default points to a local CKAN instance endpoint's URL.
|
||||
<Highlighter isView action="underline" color="#2596be">View the GIF below</Highlighter> to see how to point to a specific CKAN API endpoint using the interactive GUI, which by default points to a local CKAN instance endpoint's URL.
|
||||
|
||||

|
||||
|
||||
import { GitMergeIcon, MousePointerClickIcon } from 'lucide-react';
|
||||
|
||||
<Cards>
|
||||
<Card
|
||||
icon={<MousePointerClickIcon />}
|
||||
href="/docs/status_show"
|
||||
title="Try out an endpoint!"
|
||||
>
|
||||
Explore the web GUI by using the `status_show` CKAN Actions API endpoint.
|
||||
</Card>
|
||||
<Card icon={<GitMergeIcon />} href="https://github.com/dathere/ckanaction" title="Source code">Explore the source code for the Rust library crate and web GUI.</Card>
|
||||
</Cards>
|
||||
|
|
|
|||
|
|
@ -19,9 +19,11 @@
|
|||
"fumadocs-openapi": "^10.1.4",
|
||||
"fumadocs-ui": "16.2.5",
|
||||
"lucide-react": "^0.561.0",
|
||||
"motion": "^12.23.26",
|
||||
"next": "^16.0.10",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"rough-notation": "^0.5.1",
|
||||
"shiki": "^3.20.0",
|
||||
"tailwind-merge": "^3.4.0"
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue