Compare commits
11 Commits
ebd5348bf5
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
259496bc86 | ||
|
|
217310888c | ||
|
|
039d8d5a50 | ||
|
|
6ea39676c8 | ||
|
|
4a6d0da72a | ||
|
|
5060fd2154 | ||
|
|
2bca9eb28e | ||
|
|
e192899446 | ||
|
|
9b6ef22262 | ||
|
|
fc46b72224 | ||
|
|
e13ba8c9e9 |
2
.vscode/image-link.code-snippets
vendored
2
.vscode/image-link.code-snippets
vendored
@@ -2,7 +2,7 @@
|
||||
"DocuImage": {
|
||||
"prefix": "image",
|
||||
"body": [
|
||||
""
|
||||
""
|
||||
],
|
||||
"description": "Snippet untuk menampilkan image komponen."
|
||||
},
|
||||
|
||||
@@ -12,13 +12,19 @@ import MobToc from "@/components/mob-toc";
|
||||
const { meta } = docuConfig;
|
||||
|
||||
type PageProps = {
|
||||
params: {
|
||||
params: Promise<{
|
||||
slug: string[];
|
||||
};
|
||||
}>;
|
||||
};
|
||||
|
||||
// Function to generate metadata dynamically
|
||||
export async function generateMetadata({ params: { slug = [] } }: PageProps) {
|
||||
export async function generateMetadata(props: PageProps) {
|
||||
const params = await props.params;
|
||||
|
||||
const {
|
||||
slug = []
|
||||
} = params;
|
||||
|
||||
const pathName = slug.join("/");
|
||||
const res = await getDocsForSlug(pathName);
|
||||
|
||||
@@ -62,7 +68,13 @@ export async function generateMetadata({ params: { slug = [] } }: PageProps) {
|
||||
};
|
||||
}
|
||||
|
||||
export default async function DocsPage({ params: { slug = [] } }: PageProps) {
|
||||
export default async function DocsPage(props: PageProps) {
|
||||
const params = await props.params;
|
||||
|
||||
const {
|
||||
slug = []
|
||||
} = params;
|
||||
|
||||
const pathName = slug.join("/");
|
||||
const res = await getDocsForSlug(pathName);
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ import { GeistMono } from "geist/font/mono";
|
||||
import { Footer } from "@/components/footer";
|
||||
import docuConfig from "@/docu.json";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import "@docsearch/css";
|
||||
import "@/styles/algolia.css";
|
||||
import "@/styles/syntax.css";
|
||||
import "@/styles/globals.css";
|
||||
|
||||
const { meta } = docuConfig;
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function Home() {
|
||||
)}
|
||||
>
|
||||
<AnimatedShinyText className="inline-flex items-center justify-center px-4 py-1 transition ease-out hover:text-neutral-100 hover:duration-300 hover:dark:text-neutral-200">
|
||||
<span>🚀 New Version - Release v1.15.1</span>
|
||||
<span>🚀 Release v2.0.0-beta.1</span>
|
||||
<ArrowRightIcon className="ml-1 size-3 transition-transform duration-300 ease-in-out group-hover:translate-x-0.5" />
|
||||
</AnimatedShinyText>
|
||||
</div>
|
||||
|
||||
@@ -50,6 +50,7 @@ export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setSearchedInput("");
|
||||
}
|
||||
}, [isOpen]);
|
||||
@@ -71,9 +72,9 @@ export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
||||
return advanceSearch(trimmedInput) as unknown as SearchResult[];
|
||||
}, [searchedInput]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedIndex(0);
|
||||
}, [filteredResults]);
|
||||
// useEffect(() => {
|
||||
// setSelectedIndex(0);
|
||||
// }, [filteredResults]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleNavigation = (event: KeyboardEvent) => {
|
||||
@@ -117,7 +118,10 @@ export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
||||
|
||||
<input
|
||||
value={searchedInput}
|
||||
onChange={(e) => setSearchedInput(e.target.value)}
|
||||
onChange={(e) => {
|
||||
setSearchedInput(e.target.value);
|
||||
setSelectedIndex(0);
|
||||
}}
|
||||
placeholder="Type something to search..."
|
||||
autoFocus
|
||||
className="h-14 px-6 bg-transparent border-b text-[14px] outline-none w-full"
|
||||
@@ -177,14 +181,14 @@ export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
||||
<DialogFooter className="md:flex md:justify-start hidden h-14 px-6 bg-transparent border-t text-[14px] outline-none">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="dark:bg-accent/15 bg-slate-200 border rounded p-2">
|
||||
<ArrowUpIcon className="w-3 h-3"/>
|
||||
<ArrowUpIcon className="w-3 h-3" />
|
||||
</span>
|
||||
<span className="dark:bg-accent/15 bg-slate-200 border rounded p-2">
|
||||
<ArrowDownIcon className="w-3 h-3"/>
|
||||
<ArrowDownIcon className="w-3 h-3" />
|
||||
</span>
|
||||
<p className="text-muted-foreground">to navigate</p>
|
||||
<span className="dark:bg-accent/15 bg-slate-200 border rounded p-2">
|
||||
<CornerDownLeftIcon className="w-3 h-3"/>
|
||||
<CornerDownLeftIcon className="w-3 h-3" />
|
||||
</span>
|
||||
<p className="text-muted-foreground">to select</p>
|
||||
<span className="dark:bg-accent/15 bg-slate-200 border rounded px-2 py-1">
|
||||
|
||||
@@ -45,6 +45,7 @@ export default function ContextPopover({ className }: ContextPopoverProps) {
|
||||
|
||||
useEffect(() => {
|
||||
if (pathname.startsWith("/docs")) {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setActiveRoute(getActiveContextRoute(pathname));
|
||||
} else {
|
||||
setActiveRoute(undefined);
|
||||
@@ -61,7 +62,7 @@ export default function ContextPopover({ className }: ContextPopoverProps) {
|
||||
<Button
|
||||
variant="ghost"
|
||||
className={cn(
|
||||
"w-full max-w-[240px] flex items-center justify-between font-semibold text-foreground px-0 pt-8",
|
||||
"w-full max-w-[240px] cursor-pointer flex items-center justify-between font-semibold text-foreground px-0 pt-8",
|
||||
"hover:bg-transparent hover:text-foreground",
|
||||
className
|
||||
)}
|
||||
|
||||
4
components/contexts/AccordionContext.ts
Normal file
4
components/contexts/AccordionContext.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
// Create a context to check if a component is inside an accordion group
|
||||
export const AccordionGroupContext = createContext<{ inGroup: boolean } | null>(null);
|
||||
@@ -1,8 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import { type ThemeProviderProps } from "next-themes/dist/types";
|
||||
import { type ThemeProviderProps } from "next-themes";
|
||||
|
||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||
|
||||
@@ -10,53 +10,27 @@ interface DocsMenuProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// Get the current context from the path
|
||||
function getCurrentContext(path: string): string | undefined {
|
||||
if (!path.startsWith('/docs')) return undefined;
|
||||
|
||||
// Extract the first segment after /docs/
|
||||
const match = path.match(/^\/docs\/([^\/]+)/);
|
||||
return match ? match[1] : undefined;
|
||||
}
|
||||
|
||||
// Get the route that matches the current context
|
||||
function getContextRoute(contextPath: string): EachRoute | undefined {
|
||||
return ROUTES.find(route => {
|
||||
const normalizedHref = route.href.replace(/^\/+|\/+$/g, '');
|
||||
return normalizedHref === contextPath;
|
||||
});
|
||||
}
|
||||
|
||||
export default function DocsMenu({ isSheet = false, className = "" }: DocsMenuProps) {
|
||||
const pathname = usePathname();
|
||||
|
||||
// Skip rendering if not on a docs page
|
||||
if (!pathname.startsWith("/docs")) return null;
|
||||
|
||||
// Get the current context
|
||||
const currentContext = getCurrentContext(pathname);
|
||||
|
||||
// Get the route for the current context
|
||||
const contextRoute = currentContext ? getContextRoute(currentContext) : undefined;
|
||||
|
||||
// If no context route is found, don't render anything
|
||||
if (!contextRoute) return null;
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-label="Documentation navigation"
|
||||
className={cn("transition-all duration-200", className)}
|
||||
>
|
||||
<ul className="flex flex-col gap-1.5 py-4">
|
||||
{/* Display only the items from the current context */}
|
||||
<li key={contextRoute.title}>
|
||||
{ROUTES.map((route, index) => (
|
||||
<li key={route.title + index}>
|
||||
<SubLink
|
||||
{...contextRoute}
|
||||
href={`/docs${contextRoute.href}`}
|
||||
{...route}
|
||||
href={`/docs${route.href}`}
|
||||
level={0}
|
||||
isSheet={isSheet}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ export function ToggleButton({
|
||||
<Button
|
||||
size="icon"
|
||||
variant="outline"
|
||||
className="hover:bg-transparent hover:text-inherit border-none text-muted-foreground"
|
||||
className="cursor-pointer hover:bg-transparent hover:text-inherit border-none text-muted-foreground"
|
||||
onClick={onToggle}
|
||||
>
|
||||
{collapsed ? (
|
||||
|
||||
31
components/markdown/AccordionGroupMdx.tsx
Normal file
31
components/markdown/AccordionGroupMdx.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
"use client"
|
||||
|
||||
import React, { ReactNode } from "react";
|
||||
import clsx from "clsx";
|
||||
import { AccordionGroupContext } from "@/components/contexts/AccordionContext";
|
||||
|
||||
interface AccordionGroupProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AccordionGroup: React.FC<AccordionGroupProps> = ({ children, className }) => {
|
||||
|
||||
return (
|
||||
// Wrap all children with the AccordionGroupContext.Provider
|
||||
// so that any nested accordions know they are inside a group.
|
||||
// This enables group-specific behavior in child components.
|
||||
<AccordionGroupContext.Provider value={{ inGroup: true }}>
|
||||
<div
|
||||
className={clsx(
|
||||
"border rounded-lg overflow-hidden",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</AccordionGroupContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccordionGroup;
|
||||
@@ -1,42 +1,57 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode, useState } from 'react';
|
||||
import { ReactNode, useState, useContext } from 'react';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import * as Icons from "lucide-react";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { AccordionGroupContext } from '@/components/contexts/AccordionContext';
|
||||
|
||||
type AccordionProps = {
|
||||
title: string;
|
||||
children?: ReactNode;
|
||||
defaultOpen?: boolean;
|
||||
className?: string;
|
||||
icon?: keyof typeof Icons;
|
||||
};
|
||||
|
||||
const Accordion = ({
|
||||
const Accordion: React.FC<AccordionProps> = ({
|
||||
title,
|
||||
children,
|
||||
defaultOpen = false,
|
||||
className,
|
||||
icon,
|
||||
}: AccordionProps) => {
|
||||
const groupContext = useContext(AccordionGroupContext);
|
||||
const isInGroup = groupContext?.inGroup === true;
|
||||
const [isOpen, setIsOpen] = useState(defaultOpen);
|
||||
const Icon = icon ? (Icons[icon] as React.FC<{ className?: string }>) : null;
|
||||
|
||||
// The main wrapper div for the accordion.
|
||||
// All styling logic for the accordion container is handled here.
|
||||
return (
|
||||
<div className={cn("border rounded-lg overflow-hidden", className)}>
|
||||
<div
|
||||
className={cn(
|
||||
// Style for STANDALONE: full card with border & shadow
|
||||
!isInGroup && "border rounded-lg shadow-sm",
|
||||
// Style for IN GROUP: only a bottom border separator
|
||||
isInGroup && "border-b last:border-b-0 border-border"
|
||||
)}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="flex items-center my-auto space-x-2 space-y-2 w-full px-4 h-12 transition-colors bg-background dark:hover:bg-muted/50 hover:bg-muted/15"
|
||||
className="flex items-center gap-2 w-full px-4 h-12 transition-colors bg-muted/40 dark:bg-muted/20 hover:bg-muted/70 dark:hover:bg-muted/70"
|
||||
>
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
"w-4 h-4 text-muted-foreground transition-transform duration-200",
|
||||
"w-4 h-4 text-muted-foreground transition-transform duration-200 flex-shrink-0",
|
||||
isOpen && "rotate-90"
|
||||
)}
|
||||
/>
|
||||
<h3 className="font-medium text-base text-foreground pb-2">{title}</h3>
|
||||
{Icon && <Icon className="text-foreground w-4 h-4 flex-shrink-0" />}
|
||||
<h3 className="font-medium text-base text-foreground !m-0 leading-none">{title}</h3>
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className="px-4 py-3 border-t dark:bg-muted/50 bg-muted/15">
|
||||
<div className="px-4 py-3 dark:bg-muted/10 bg-muted/15">
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -8,13 +8,21 @@ interface CardGroupProps {
|
||||
}
|
||||
|
||||
const CardGroup: React.FC<CardGroupProps> = ({ children, cols = 2, className }) => {
|
||||
const cardsArray = React.Children.toArray(children); // Pastikan children berupa array
|
||||
const cardsArray = React.Children.toArray(children);
|
||||
|
||||
// Static grid column classes for Tailwind v4 compatibility
|
||||
const gridColsClass = {
|
||||
1: "grid-cols-1",
|
||||
2: "grid-cols-1 sm:grid-cols-2",
|
||||
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
||||
4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4",
|
||||
}[cols] || "grid-cols-1 sm:grid-cols-2";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"grid gap-4 text-foreground",
|
||||
`grid-cols-1 sm:grid-cols-${cols}`,
|
||||
gridColsClass,
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -100,8 +100,8 @@ export const Files = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
rounded-xl border border-muted/50
|
||||
bg-card/50 backdrop-blur-sm
|
||||
rounded-xl border border-muted/20
|
||||
bg-card/20 backdrop-blur-sm
|
||||
shadow-sm overflow-hidden
|
||||
transition-all duration-200
|
||||
hover:shadow-md hover:border-muted/60
|
||||
|
||||
@@ -4,13 +4,17 @@ import NextImage from "next/image";
|
||||
type Height = ComponentProps<typeof NextImage>["height"];
|
||||
type Width = ComponentProps<typeof NextImage>["width"];
|
||||
|
||||
type ImageProps = Omit<ComponentProps<"img">, "src"> & {
|
||||
src?: ComponentProps<typeof NextImage>["src"];
|
||||
};
|
||||
|
||||
export default function Image({
|
||||
src,
|
||||
alt = "alt",
|
||||
width = 800,
|
||||
height = 350,
|
||||
...props
|
||||
}: ComponentProps<"img">) {
|
||||
}: ImageProps) {
|
||||
if (!src) return null;
|
||||
return (
|
||||
<NextImage
|
||||
|
||||
@@ -1,18 +1,108 @@
|
||||
import { ComponentProps } from "react";
|
||||
import { type ComponentProps, type JSX } from "react";
|
||||
import Copy from "./CopyMdx";
|
||||
import {
|
||||
SiJavascript,
|
||||
SiTypescript,
|
||||
SiReact,
|
||||
SiPython,
|
||||
SiGo,
|
||||
SiPhp,
|
||||
SiRuby,
|
||||
SiSwift,
|
||||
SiKotlin,
|
||||
SiHtml5,
|
||||
SiCss3,
|
||||
SiSass,
|
||||
SiPostgresql,
|
||||
SiGraphql,
|
||||
SiYaml,
|
||||
SiToml,
|
||||
SiDocker,
|
||||
SiNginx,
|
||||
SiGit,
|
||||
SiGnubash,
|
||||
SiMarkdown,
|
||||
} from "react-icons/si";
|
||||
import { FaJava, FaCode } from "react-icons/fa";
|
||||
import { TbJson } from "react-icons/tb";
|
||||
|
||||
type PreProps = ComponentProps<"pre"> & {
|
||||
raw?: string;
|
||||
"data-title"?: string;
|
||||
};
|
||||
|
||||
// Component to display an icon based on the programming language
|
||||
const LanguageIcon = ({ lang }: { lang: string }) => {
|
||||
const iconProps = { className: "w-4 h-4" };
|
||||
const languageToIconMap: Record<string, JSX.Element> = {
|
||||
gitignore: <SiGit {...iconProps} />,
|
||||
docker: <SiDocker {...iconProps} />,
|
||||
dockerfile: <SiDocker {...iconProps} />,
|
||||
nginx: <SiNginx {...iconProps} />,
|
||||
sql: <SiPostgresql {...iconProps} />,
|
||||
graphql: <SiGraphql {...iconProps} />,
|
||||
yaml: <SiYaml {...iconProps} />,
|
||||
yml: <SiYaml {...iconProps} />,
|
||||
toml: <SiToml {...iconProps} />,
|
||||
json: <TbJson {...iconProps} />,
|
||||
md: <SiMarkdown {...iconProps} />,
|
||||
markdown: <SiMarkdown {...iconProps} />,
|
||||
bash: <SiGnubash {...iconProps} />,
|
||||
sh: <SiGnubash {...iconProps} />,
|
||||
shell: <SiGnubash {...iconProps} />,
|
||||
swift: <SiSwift {...iconProps} />,
|
||||
kotlin: <SiKotlin {...iconProps} />,
|
||||
kt: <SiKotlin {...iconProps} />,
|
||||
kts: <SiKotlin {...iconProps} />,
|
||||
rb: <SiRuby {...iconProps} />,
|
||||
ruby: <SiRuby {...iconProps} />,
|
||||
php: <SiPhp {...iconProps} />,
|
||||
go: <SiGo {...iconProps} />,
|
||||
py: <SiPython {...iconProps} />,
|
||||
python: <SiPython {...iconProps} />,
|
||||
java: <FaJava {...iconProps} />,
|
||||
tsx: <SiReact {...iconProps} />,
|
||||
typescript: <SiTypescript {...iconProps} />,
|
||||
ts: <SiTypescript {...iconProps} />,
|
||||
jsx: <SiReact {...iconProps} />,
|
||||
js: <SiJavascript {...iconProps} />,
|
||||
javascript: <SiJavascript {...iconProps} />,
|
||||
html: <SiHtml5 {...iconProps} />,
|
||||
css: <SiCss3 {...iconProps} />,
|
||||
scss: <SiSass {...iconProps} />,
|
||||
sass: <SiSass {...iconProps} />,
|
||||
};
|
||||
return languageToIconMap[lang] || <FaCode {...iconProps} />;
|
||||
};
|
||||
|
||||
// Function to extract the language from className
|
||||
function getLanguage(className: string = ""): string {
|
||||
const match = className.match(/language-(\w+)/);
|
||||
return match ? match[1] : "default";
|
||||
}
|
||||
|
||||
export default function Pre({ children, raw, ...rest }: PreProps) {
|
||||
const { "data-title": title, className, ...restProps } = rest;
|
||||
const language = getLanguage(className);
|
||||
const hasTitle = !!title;
|
||||
|
||||
export default function Pre({
|
||||
children,
|
||||
raw,
|
||||
...rest
|
||||
}: ComponentProps<"pre"> & { raw?: string }) {
|
||||
return (
|
||||
<div className="my-5 relative">
|
||||
<div className="absolute top-3 right-2.5 z-10 sm:block hidden">
|
||||
<Copy content={raw!} />
|
||||
<div className="code-block-container">
|
||||
<div className="code-block-actions">
|
||||
{raw && <Copy content={raw} />}
|
||||
</div>
|
||||
<div className="relative">
|
||||
<pre {...rest}>{children}</pre>
|
||||
{hasTitle && (
|
||||
<div className="code-block-header">
|
||||
<div className="flex items-center gap-2">
|
||||
<LanguageIcon lang={language} />
|
||||
<span>{title}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="code-block-body">
|
||||
<pre className={className} {...restProps}>
|
||||
{children}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -14,7 +14,7 @@ interface MobTocProps {
|
||||
tocs: TocItem[];
|
||||
}
|
||||
|
||||
const useClickOutside = (ref: React.RefObject<HTMLElement>, callback: () => void) => {
|
||||
const useClickOutside = (ref: React.RefObject<HTMLElement | null>, callback: () => void) => {
|
||||
const handleClick = React.useCallback((event: MouseEvent) => {
|
||||
if (ref.current && !ref.current.contains(event.target as Node)) {
|
||||
callback();
|
||||
|
||||
@@ -32,6 +32,7 @@ export function ScrollToTop({
|
||||
|
||||
useEffect(() => {
|
||||
// Initial check
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
checkScroll();
|
||||
|
||||
// Set up scroll listener with debounce for better performance
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function SubLink({
|
||||
parentHref = "",
|
||||
}: SubLinkProps) {
|
||||
const path = usePathname();
|
||||
const [isOpen, setIsOpen] = useState(level === 0);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
// Full path including parent's href
|
||||
const fullHref = `${parentHref}${href}`;
|
||||
@@ -44,6 +44,7 @@ export default function SubLink({
|
||||
// Auto-expand if current path is a child of this item
|
||||
useEffect(() => {
|
||||
if (items && (path.startsWith(fullHref) && path !== fullHref)) {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setIsOpen(true);
|
||||
}
|
||||
}, [path, fullHref, items]);
|
||||
@@ -85,7 +86,11 @@ export default function SubLink({
|
||||
<div className={cn("flex flex-col gap-1 w-full")}>
|
||||
<Collapsible open={isOpen} onOpenChange={setIsOpen}>
|
||||
<CollapsibleTrigger
|
||||
className="w-full pr-5 text-left"
|
||||
className={cn(
|
||||
"w-full pr-5 text-left rounded-md transition-colors",
|
||||
isOpen && "bg-muted/30 pb-2 pt-2", // Background when open
|
||||
hasActiveChild && "bg-primary/5" // Accent tint when child is active
|
||||
)}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls={`collapsible-${fullHref.replace(/[^a-zA-Z0-9]/g, '-')}`}
|
||||
>
|
||||
@@ -103,13 +108,13 @@ export default function SubLink({
|
||||
<CollapsibleContent
|
||||
id={`collapsible-${fullHref.replace(/[^a-zA-Z0-9]/g, '-')}`}
|
||||
className={cn(
|
||||
"overflow-hidden transition-all duration-200 ease-in-out",
|
||||
"pl-3 overflow-hidden transition-all duration-200 ease-in-out",
|
||||
isOpen ? "animate-collapsible-down" : "animate-collapsible-up"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col items-start sm:text-sm text-foreground/80 ml-0.5 mt-2.5 gap-3 hover:[&_a]:text-foreground transition-colors",
|
||||
"flex flex-col items-start sm:text-sm text-foreground/80 ml-0.5 mt-2.5 gap-3 transition-colors",
|
||||
level > 0 && "pl-4 border-l border-border ml-1.5"
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,65 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { Moon, Sun, Monitor } from "lucide-react";
|
||||
import { Moon, Sun } from "lucide-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||
|
||||
export function ModeToggle() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
const [selectedTheme, setSelectedTheme] = React.useState<string>("system");
|
||||
const { theme, setTheme, resolvedTheme } = useTheme();
|
||||
const [mounted, setMounted] = React.useState(false);
|
||||
|
||||
// Pastikan toggle tetap di posisi yang benar setelah reload
|
||||
// Untuk menghindari hydration mismatch
|
||||
React.useEffect(() => {
|
||||
if (theme) {
|
||||
setSelectedTheme(theme);
|
||||
} else {
|
||||
setSelectedTheme("system"); // Default ke system jika undefined
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
// Jika belum mounted, jangan render apapun untuk menghindari mismatch
|
||||
if (!mounted) {
|
||||
return (
|
||||
<div className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-1">
|
||||
<div className="rounded-full p-1 w-8 h-8" />
|
||||
<div className="rounded-full p-1 w-8 h-8" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
// Tentukan theme yang aktif: gunakan resolvedTheme untuk menampilkan ikon yang sesuai
|
||||
// jika theme === "system", resolvedTheme akan menjadi "light" atau "dark" sesuai device
|
||||
const activeTheme = theme === "system" || !theme ? resolvedTheme : theme;
|
||||
|
||||
const handleToggle = () => {
|
||||
// Toggle antara light dan dark
|
||||
// Jika sekarang light, ganti ke dark, dan sebaliknya
|
||||
if (activeTheme === "light") {
|
||||
setTheme("dark");
|
||||
} else {
|
||||
setTheme("light");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
value={selectedTheme}
|
||||
onValueChange={(value) => {
|
||||
if (value) {
|
||||
setTheme(value);
|
||||
setSelectedTheme(value);
|
||||
}
|
||||
}}
|
||||
value={activeTheme}
|
||||
onValueChange={handleToggle}
|
||||
className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-1 transition-all"
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value="light"
|
||||
size="sm"
|
||||
aria-label="Light Mode"
|
||||
className={`rounded-full p-1 transition-all ${
|
||||
selectedTheme === "light"
|
||||
className={`rounded-full p-1 transition-all ${activeTheme === "light"
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-transparent hover:bg-muted/50"
|
||||
}`}
|
||||
>
|
||||
<Sun className="h-4 w-4" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="system"
|
||||
size="sm"
|
||||
aria-label="System Mode"
|
||||
className={`rounded-full p-1 transition-all ${
|
||||
selectedTheme === "system"
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-transparent hover:bg-muted/50"
|
||||
}`}
|
||||
>
|
||||
<Monitor className="h-4 w-4" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="dark"
|
||||
size="sm"
|
||||
aria-label="Dark Mode"
|
||||
className={`rounded-full p-1 transition-all ${
|
||||
selectedTheme === "dark"
|
||||
className={`rounded-full p-1 transition-all ${activeTheme === "dark"
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-transparent hover:bg-muted/50"
|
||||
}`}
|
||||
|
||||
@@ -1,324 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { renderToString } from "react-dom/server";
|
||||
|
||||
interface Icon {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
scale: number;
|
||||
opacity: number;
|
||||
id: number;
|
||||
}
|
||||
|
||||
interface IconCloudProps {
|
||||
icons?: React.ReactNode[];
|
||||
images?: string[];
|
||||
}
|
||||
|
||||
function easeOutCubic(t: number): number {
|
||||
return 1 - Math.pow(1 - t, 3);
|
||||
}
|
||||
|
||||
export function IconCloud({ icons, images }: IconCloudProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [iconPositions, setIconPositions] = useState<Icon[]>([]);
|
||||
const [rotation] = useState({ x: 0, y: 0 });
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [lastMousePos, setLastMousePos] = useState({ x: 0, y: 0 });
|
||||
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
|
||||
const [targetRotation, setTargetRotation] = useState<{
|
||||
x: number;
|
||||
y: number;
|
||||
startX: number;
|
||||
startY: number;
|
||||
distance: number;
|
||||
startTime: number;
|
||||
duration: number;
|
||||
} | null>(null);
|
||||
const animationFrameRef = useRef<number>();
|
||||
const rotationRef = useRef(rotation);
|
||||
const iconCanvasesRef = useRef<HTMLCanvasElement[]>([]);
|
||||
const imagesLoadedRef = useRef<boolean[]>([]);
|
||||
|
||||
// Create icon canvases once when icons/images change
|
||||
useEffect(() => {
|
||||
if (!icons && !images) return;
|
||||
|
||||
const items = icons || images || [];
|
||||
imagesLoadedRef.current = new Array(items.length).fill(false);
|
||||
|
||||
const newIconCanvases = items.map((item, index) => {
|
||||
const offscreen = document.createElement("canvas");
|
||||
offscreen.width = 40;
|
||||
offscreen.height = 40;
|
||||
const offCtx = offscreen.getContext("2d");
|
||||
|
||||
if (offCtx) {
|
||||
if (images) {
|
||||
// Handle image URLs directly
|
||||
const img = new Image();
|
||||
img.crossOrigin = "anonymous";
|
||||
img.src = items[index] as string;
|
||||
img.onload = () => {
|
||||
offCtx.clearRect(0, 0, offscreen.width, offscreen.height);
|
||||
|
||||
// Create circular clipping path
|
||||
offCtx.beginPath();
|
||||
offCtx.arc(20, 20, 20, 0, Math.PI * 2);
|
||||
offCtx.closePath();
|
||||
offCtx.clip();
|
||||
|
||||
// Draw the image
|
||||
offCtx.drawImage(img, 0, 0, 40, 40);
|
||||
|
||||
imagesLoadedRef.current[index] = true;
|
||||
};
|
||||
} else {
|
||||
// Handle SVG icons
|
||||
offCtx.scale(0.4, 0.4);
|
||||
const svgString = renderToString(item as React.ReactElement);
|
||||
const img = new Image();
|
||||
img.src = "data:image/svg+xml;base64," + btoa(svgString);
|
||||
img.onload = () => {
|
||||
offCtx.clearRect(0, 0, offscreen.width, offscreen.height);
|
||||
offCtx.drawImage(img, 0, 0);
|
||||
imagesLoadedRef.current[index] = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
return offscreen;
|
||||
});
|
||||
|
||||
iconCanvasesRef.current = newIconCanvases;
|
||||
}, [icons, images]);
|
||||
|
||||
// Generate initial icon positions on a sphere
|
||||
useEffect(() => {
|
||||
const items = icons || images || [];
|
||||
const newIcons: Icon[] = [];
|
||||
const numIcons = items.length || 20;
|
||||
|
||||
// Fibonacci sphere parameters
|
||||
const offset = 2 / numIcons;
|
||||
const increment = Math.PI * (3 - Math.sqrt(5));
|
||||
|
||||
for (let i = 0; i < numIcons; i++) {
|
||||
const y = i * offset - 1 + offset / 2;
|
||||
const r = Math.sqrt(1 - y * y);
|
||||
const phi = i * increment;
|
||||
|
||||
const x = Math.cos(phi) * r;
|
||||
const z = Math.sin(phi) * r;
|
||||
|
||||
newIcons.push({
|
||||
x: x * 100,
|
||||
y: y * 100,
|
||||
z: z * 100,
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
id: i,
|
||||
});
|
||||
}
|
||||
setIconPositions(newIcons);
|
||||
}, [icons, images]);
|
||||
|
||||
// Handle mouse events
|
||||
const handleMouseDown = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
||||
const rect = canvasRef.current?.getBoundingClientRect();
|
||||
if (!rect || !canvasRef.current) return;
|
||||
|
||||
const x = e.clientX - rect.left;
|
||||
const y = e.clientY - rect.top;
|
||||
|
||||
const ctx = canvasRef.current.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
iconPositions.forEach((icon) => {
|
||||
const cosX = Math.cos(rotationRef.current.x);
|
||||
const sinX = Math.sin(rotationRef.current.x);
|
||||
const cosY = Math.cos(rotationRef.current.y);
|
||||
const sinY = Math.sin(rotationRef.current.y);
|
||||
|
||||
const rotatedX = icon.x * cosY - icon.z * sinY;
|
||||
const rotatedZ = icon.x * sinY + icon.z * cosY;
|
||||
const rotatedY = icon.y * cosX + rotatedZ * sinX;
|
||||
|
||||
const screenX = canvasRef.current!.width / 2 + rotatedX;
|
||||
const screenY = canvasRef.current!.height / 2 + rotatedY;
|
||||
|
||||
const scale = (rotatedZ + 200) / 300;
|
||||
const radius = 20 * scale;
|
||||
const dx = x - screenX;
|
||||
const dy = y - screenY;
|
||||
|
||||
if (dx * dx + dy * dy < radius * radius) {
|
||||
const targetX = -Math.atan2(
|
||||
icon.y,
|
||||
Math.sqrt(icon.x * icon.x + icon.z * icon.z),
|
||||
);
|
||||
const targetY = Math.atan2(icon.x, icon.z);
|
||||
|
||||
const currentX = rotationRef.current.x;
|
||||
const currentY = rotationRef.current.y;
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(targetX - currentX, 2) + Math.pow(targetY - currentY, 2),
|
||||
);
|
||||
|
||||
const duration = Math.min(2000, Math.max(800, distance * 1000));
|
||||
|
||||
setTargetRotation({
|
||||
x: targetX,
|
||||
y: targetY,
|
||||
startX: currentX,
|
||||
startY: currentY,
|
||||
distance,
|
||||
startTime: performance.now(),
|
||||
duration,
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
setIsDragging(true);
|
||||
setLastMousePos({ x: e.clientX, y: e.clientY });
|
||||
};
|
||||
|
||||
const handleMouseMove = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
||||
const rect = canvasRef.current?.getBoundingClientRect();
|
||||
if (rect) {
|
||||
const x = e.clientX - rect.left;
|
||||
const y = e.clientY - rect.top;
|
||||
setMousePos({ x, y });
|
||||
}
|
||||
|
||||
if (isDragging) {
|
||||
const deltaX = e.clientX - lastMousePos.x;
|
||||
const deltaY = e.clientY - lastMousePos.y;
|
||||
|
||||
rotationRef.current = {
|
||||
x: rotationRef.current.x + deltaY * 0.002,
|
||||
y: rotationRef.current.y + deltaX * 0.002,
|
||||
};
|
||||
|
||||
setLastMousePos({ x: e.clientX, y: e.clientY });
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
// Animation and rendering
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
const ctx = canvas?.getContext("2d");
|
||||
if (!canvas || !ctx) return;
|
||||
|
||||
const animate = () => {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const centerX = canvas.width / 2;
|
||||
const centerY = canvas.height / 2;
|
||||
const maxDistance = Math.sqrt(centerX * centerX + centerY * centerY);
|
||||
const dx = mousePos.x - centerX;
|
||||
const dy = mousePos.y - centerY;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const speed = 0.003 + (distance / maxDistance) * 0.01;
|
||||
|
||||
if (targetRotation) {
|
||||
const elapsed = performance.now() - targetRotation.startTime;
|
||||
const progress = Math.min(1, elapsed / targetRotation.duration);
|
||||
const easedProgress = easeOutCubic(progress);
|
||||
|
||||
rotationRef.current = {
|
||||
x:
|
||||
targetRotation.startX +
|
||||
(targetRotation.x - targetRotation.startX) * easedProgress,
|
||||
y:
|
||||
targetRotation.startY +
|
||||
(targetRotation.y - targetRotation.startY) * easedProgress,
|
||||
};
|
||||
|
||||
if (progress >= 1) {
|
||||
setTargetRotation(null);
|
||||
}
|
||||
} else if (!isDragging) {
|
||||
rotationRef.current = {
|
||||
x: rotationRef.current.x + (dy / canvas.height) * speed,
|
||||
y: rotationRef.current.y + (dx / canvas.width) * speed,
|
||||
};
|
||||
}
|
||||
|
||||
iconPositions.forEach((icon, index) => {
|
||||
const cosX = Math.cos(rotationRef.current.x);
|
||||
const sinX = Math.sin(rotationRef.current.x);
|
||||
const cosY = Math.cos(rotationRef.current.y);
|
||||
const sinY = Math.sin(rotationRef.current.y);
|
||||
|
||||
const rotatedX = icon.x * cosY - icon.z * sinY;
|
||||
const rotatedZ = icon.x * sinY + icon.z * cosY;
|
||||
const rotatedY = icon.y * cosX + rotatedZ * sinX;
|
||||
|
||||
const scale = (rotatedZ + 200) / 300;
|
||||
const opacity = Math.max(0.2, Math.min(1, (rotatedZ + 150) / 200));
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(
|
||||
canvas.width / 2 + rotatedX,
|
||||
canvas.height / 2 + rotatedY,
|
||||
);
|
||||
ctx.scale(scale, scale);
|
||||
ctx.globalAlpha = opacity;
|
||||
|
||||
if (icons || images) {
|
||||
// Only try to render icons/images if they exist
|
||||
if (
|
||||
iconCanvasesRef.current[index] &&
|
||||
imagesLoadedRef.current[index]
|
||||
) {
|
||||
ctx.drawImage(iconCanvasesRef.current[index], -20, -20, 40, 40);
|
||||
}
|
||||
} else {
|
||||
// Show numbered circles if no icons/images are provided
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, 20, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "#4444ff";
|
||||
ctx.fill();
|
||||
ctx.fillStyle = "white";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.font = "16px Arial";
|
||||
ctx.fillText(`${icon.id + 1}`, 0, 0);
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
});
|
||||
animationFrameRef.current = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
return () => {
|
||||
if (animationFrameRef.current) {
|
||||
cancelAnimationFrame(animationFrameRef.current);
|
||||
}
|
||||
};
|
||||
}, [icons, images, iconPositions, isDragging, mousePos, targetRotation]);
|
||||
|
||||
return (
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={400}
|
||||
height={400}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseLeave={handleMouseUp}
|
||||
className="rounded-full"
|
||||
aria-label="Interactive 3D Icon Cloud"
|
||||
role="img"
|
||||
/>
|
||||
);
|
||||
}
|
||||
87
contents/docs/api-reference/licensing/index.mdx
Normal file
87
contents/docs/api-reference/licensing/index.mdx
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: Licensing API
|
||||
description: Endpoints for activating, validating, and managing licenses
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Licensing API allows external applications to interact with the WooNooW licensing system.
|
||||
|
||||
**Base URL**: `https://your-domain.com/wp-json/woonoow/v1`
|
||||
|
||||
---
|
||||
|
||||
## Public Endpoints
|
||||
|
||||
### Activate License
|
||||
|
||||
Activates a license key for a specific domain.
|
||||
|
||||
```http
|
||||
POST /licenses/activate
|
||||
```
|
||||
|
||||
#### Activation Parameters
|
||||
|
||||
| Body Params | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `license_key` | `string` | **Yes** | The license key to activate |
|
||||
| `domain` | `string` | **Yes** | The domain where the software is installed |
|
||||
| `activation_mode` | `string` | No | Set to `oauth` to trigger OAuth flow |
|
||||
|
||||
#### Responses
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"activation_id": 123,
|
||||
"license_key": "XXXX-YYYY-ZZZZ-WWWW",
|
||||
"status": "active"
|
||||
}
|
||||
```
|
||||
|
||||
If OAuth is required:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"oauth_required": true,
|
||||
"oauth_redirect": "https://vendor.com/my-account/license-connect/...",
|
||||
"state": "abc12345"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Validate License
|
||||
|
||||
Checks if a license key is valid and active for the current domain.
|
||||
|
||||
```http
|
||||
POST /licenses/validate
|
||||
```
|
||||
|
||||
#### Validation Parameters
|
||||
|
||||
| Body Params | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `license_key` | `string` | **Yes** | The license key to validate |
|
||||
| `domain` | `string` | **Yes** | The domain to check against |
|
||||
|
||||
---
|
||||
|
||||
### Deactivate License
|
||||
|
||||
Deactivates a license for the current domain.
|
||||
|
||||
```http
|
||||
POST /licenses/deactivate
|
||||
```
|
||||
|
||||
#### Deactivation Parameters
|
||||
|
||||
| Body Params | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `license_key` | `string` | **Yes** | The license key to deactivate |
|
||||
| `domain` | `string` | **Yes** | The domain to remove |
|
||||
5
contents/docs/api-reference/meta.json
Normal file
5
contents/docs/api-reference/meta.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"pages": [
|
||||
"licensing"
|
||||
]
|
||||
}
|
||||
16
contents/docs/changelog/index.mdx
Normal file
16
contents/docs/changelog/index.mdx
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: Changelog
|
||||
description: Latest updates and changes to WooNooW
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Initial Release
|
||||
|
||||
<Release version="1.0.0" date="2024-01-31" title="Initial Public Release">
|
||||
<Changes type="added">
|
||||
- Core plugin functionality for WooCommerce enhancement.
|
||||
- Licensing module with OAuth activation flow.
|
||||
- Subscription management and payment gateway integration.
|
||||
- Extensive hook system for developers.
|
||||
</Changes>
|
||||
</Release>
|
||||
@@ -1,687 +0,0 @@
|
||||
---
|
||||
title: Release Version 1.0+
|
||||
description: List of latest changes and updates on DocuBook
|
||||
date: 02-08-2025
|
||||
---
|
||||
|
||||
<Note type="note" title="Version History">
|
||||
This changelog contains a list of all the changes made to the DocuBook template. It will be updated with each new release and will include information about new features, bug fixes, and other improvements.
|
||||
</Note>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.15.1
|
||||
</div>
|
||||
|
||||
<Release version="1.15.1" date="2025-08-06" title="Algolia DocSearch for better search result">
|
||||
<Changes type="added">
|
||||
- new DocSearch.tsx components
|
||||
- add props type algolia
|
||||
- add searchprops
|
||||
- add algolia.css
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<Note type="warning" title="environment">
|
||||
To use Algolia DocSearch, you need to configure the following environment variables:
|
||||
|
||||
```plaintext
|
||||
NEXT_PUBLIC_ALGOLIA_DOCSEARCH_APP_ID="your_app_id"
|
||||
NEXT_PUBLIC_ALGOLIA_DOCSEARCH_API_KEY="your_api_key"
|
||||
NEXT_PUBLIC_ALGOLIA_DOCSEARCH_INDEX_NAME="your_index_name"
|
||||
```
|
||||
|
||||
in the navbar component, add a prop to the class
|
||||
|
||||
```
|
||||
Change <Search /> to <Search type="algolia" />
|
||||
```
|
||||
</Note>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.14.2
|
||||
</div>
|
||||
|
||||
<Release version="1.14.2" date="2025-08-05" title="Refactor & Fix: Decouple Search Component and Resolve Type Errors">
|
||||
<Changes type="added">
|
||||
- Refactor Search component into three distinct components: Search, SearchTrigger, and SearchModal for better maintainability and scalability.
|
||||
- New SearchTrigger components
|
||||
- New SearchModal components
|
||||
</Changes>
|
||||
<Changes type="fixed">
|
||||
- Resolve TypeScript error for missing 'noLink' property on the 'Page' type after refactoring.
|
||||
- Fix TypeScript error for missing 'context' property by providing a complete inline type annotation in the SearchModal component.
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.14.0
|
||||
</div>
|
||||
|
||||
<Release version="1.14.0" date="2025-08-02" title="Dev: Add workflow to run Sync NPM package">
|
||||
<Changes type="added">
|
||||
- Add workflows to run Sync NPM package
|
||||
- Add sync-from-npm.yml
|
||||
- Add PR to organization github.com/DocuBook/docubook
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.13.9
|
||||
</div>
|
||||
|
||||
<Release version="1.13.9" date="2025-07-27" title="Code Cleanup & Stability Improvements">
|
||||
<Changes type="added">
|
||||
- Added proper type definitions for unist-util-visit
|
||||
- Added .eslintrc.json configuration file
|
||||
- Added proper type checking for node values in markdown processing
|
||||
</Changes>
|
||||
<Changes type="improved">
|
||||
- Enhanced type safety in lib/markdown.ts with proper TypeScript interfaces
|
||||
- Converted interface extensions to type aliases in UI components for consistency
|
||||
- Improved code organization across multiple files
|
||||
</Changes>
|
||||
<Changes type="fixed">
|
||||
- Fixed potential null reference in markdown.ts when processing code blocks
|
||||
- Updated import for MDXRemote in mdx-provider.tsx
|
||||
- Optimized event listener cleanup in toc-observer.tsx
|
||||
</Changes>
|
||||
<Changes type="removed">
|
||||
- Removed unused state and variables in toc-observer.tsx
|
||||
- Removed unused imports for cleaner codebase
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.13.6
|
||||
</div>
|
||||
|
||||
<Release version="1.13.6" date="2025-06-01" title="Improve sheet leftbar and search icon">
|
||||
<Changes type="improved">
|
||||
- Improve sheet leftbar and search icon
|
||||
- color scheme for sheet leftbar
|
||||
- color scheme for search icon
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.13.5
|
||||
</div>
|
||||
|
||||
<Release version="1.13.5" date="2025-05-31" title="Add Theme schema for consistent theme">
|
||||
<Changes type="added">
|
||||
- Add Theme schema
|
||||
- Add Freshlime theme
|
||||
- Add Coffee theme
|
||||
- Add llms context for generated theme with AI
|
||||
</Changes>
|
||||
<Changes type="improved">
|
||||
- Markdown support for theme-colors
|
||||
- consistent theme-colors page
|
||||
- all components now consistent with theme-colors
|
||||
- syntax with theme-colors
|
||||
</Changes>
|
||||
<Changes type="fixed">
|
||||
- fix bug FileTree component
|
||||
- fix issue markdown with theme-colors
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.13.0
|
||||
</div>
|
||||
|
||||
<Release version="1.13.0" date="2025-05-29" title="Context Menu for organize file and folder">
|
||||
<Changes type="added">
|
||||
- New ContextMenu component for organizing file and folder
|
||||
- Nested docs folder and file support with context menu
|
||||
</Changes>
|
||||
<Changes type="improved">
|
||||
- improve routes-config with context menu
|
||||
- improve docu.json with context menu
|
||||
- improve leftbar with context menu
|
||||
- improve docs-menu with context menu
|
||||
- improve search dialog limit result to 6 post per suggestion
|
||||
- improve search result typing 3 characters to show suggestion
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.12.0
|
||||
</div>
|
||||
|
||||
<Release version="1.12.0" date="2025-05-28" title="New File Tree Component and enhancements for existing components or features">
|
||||
<Changes type="added">
|
||||
- New FileTree component for displaying hierarchical file structures
|
||||
- Support for nested folders and files with expand/collapse functionality
|
||||
- Hover effects showing file extensions
|
||||
- Dark mode support with modern styling
|
||||
- Keyboard navigation and accessibility features
|
||||
- add toc-observer data attribute to detect toc section
|
||||
- cli to copy from path npm registry
|
||||
</Changes>
|
||||
<Changes type="improved">
|
||||
- search dialog hover effect return key
|
||||
- search icon showing on mobile screens
|
||||
</Changes>
|
||||
<Changes type="fixed">
|
||||
- fix search dialog on mobile screens
|
||||
- fix release note component eslint error on mdx when rendering
|
||||
- fix mob-toc callback function
|
||||
- fix toc height issue when toc section is longer than screen height
|
||||
</Changes>
|
||||
<Changes type="removed">
|
||||
- remove prompts depedencies
|
||||
- remove degit depedencies
|
||||
- remove prompts functions
|
||||
- remove degit functions
|
||||
- remove prompts and degit from package.json
|
||||
- remove clone repository using git
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<Note type="note" title="Note">
|
||||
on this version `1.12.0`, we remove clone repository using git and replace it with cli to copy from path npm registry
|
||||
</Note>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.11.0
|
||||
</div>
|
||||
|
||||
<Release version="1.11.0" date="2025-05-25" title="New Release Note components support multiple products or multiple changelogs">
|
||||
<Changes type="added">
|
||||
- New ReleaseNote component for structured changelog display
|
||||
- Added support for categorized changes (added, fixed, improved, deprecated, removed)
|
||||
- Integrated Lucide icons for better visual hierarchy
|
||||
- Support for multiple release notes
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Enhanced documentation with comprehensive usage examples
|
||||
- Better component organization and styling
|
||||
- Semantic versioning support
|
||||
- Nested release notes support
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Removed old changelog page in favor of the new ReleaseMdx component
|
||||
- Removed changelog.md
|
||||
- Removed changelog/page.tsx
|
||||
- Removed changelog.ts
|
||||
- Removed components/changelog
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.10.1
|
||||
</div>
|
||||
|
||||
<Release version="1.10.1" date="2025-05-24" title="Accessibility Improvements and Bug Fixes">
|
||||
<Changes type="fixed">
|
||||
- Added missing DialogDescription components for better accessibility
|
||||
- Fixed image aspect ratio issues in navbar logo
|
||||
- Resolved console warnings for missing image sizes
|
||||
- Improved keyboard navigation in search component
|
||||
- Fixed mobile layout for search result items
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Added proper ARIA labels for screen readers
|
||||
- Enhanced focus management in dialogs
|
||||
- Optimized image loading with proper sizing attributes
|
||||
- Better mobile experience with responsive design fixes
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove blog page
|
||||
- Remove blog functions on markdown
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.10.0
|
||||
</div>
|
||||
|
||||
<Release version="1.10.0" date="2025-05-21" title="Sidebar Improvements and Mobile TOC Enhancements">
|
||||
<Changes type="added">
|
||||
- New reusable ToggleButton component with animation
|
||||
- Mobile-friendly Table of Contents (TOC) component
|
||||
- Click-outside handler for better mobile navigation
|
||||
- Smooth scroll behavior for TOC navigation
|
||||
- Active section highlighting in TOC
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Sidebar now has a collapsible design
|
||||
- Enhanced mobile responsiveness for TOC
|
||||
- Better visual hierarchy in sidebar navigation
|
||||
- Smoother animations for sidebar toggle
|
||||
- Optimized TOC performance with intersection observer
|
||||
- Improved accessibility with proper ARIA labels
|
||||
- Better spacing and alignment in mobile view
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Fixed sidebar toggle button positioning
|
||||
- Resolved TOC highlighting issues during scroll
|
||||
- Fixed z-index conflicts in mobile view
|
||||
- Addressed minor UI glitches in dark mode
|
||||
- Fixed TOC not updating on route changes
|
||||
- Resolved scroll jank on mobile devices
|
||||
- Fixed incorrect active state in navigation
|
||||
</Changes>
|
||||
|
||||
<Changes type="deprecated">
|
||||
- No longer support changelog.md
|
||||
- No longer support changelog/page.tsx (will be removed in future update)
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.9.0
|
||||
</div>
|
||||
|
||||
<Release version="1.9.0" date="2025-05-19" title="New Keyboard component to show keyboard shortcut on docs page">
|
||||
<Changes type="added">
|
||||
- New Keyboard component with props show, type, children
|
||||
- Snippet keyboard component
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Support custom content
|
||||
- Support platform type (mac or window)
|
||||
- Support automatic rendering of platform-specific key symbols
|
||||
- Rename lowercase to camelCase for markdown component
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.8.5
|
||||
</div>
|
||||
|
||||
<Release version="1.8.5" date="2025-05-10" title="Add sponsor card on single docs page">
|
||||
<Changes type="added">
|
||||
- Expandables Leftbar
|
||||
- Sponsor badges or ads
|
||||
- Boolean show/hide 'edit on github'
|
||||
- With the same code run anywhere (bun or nodejs)
|
||||
- Add frontmatter (metadata) to playground editor
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Adjustment docu.json
|
||||
- Adjustment navbar, footer and components
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Bun compatibility: rename .js to common js
|
||||
- CLI manage packageManager on package.json
|
||||
- Inconsistent design moved to better UI/UX
|
||||
- Error handle render footer.social
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove confusing and verbose CLI on installer
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.8.0
|
||||
</div>
|
||||
|
||||
<Release version="1.8.0" date="2025-03-01" title="Now looks more modern and clean which is a big change in layout and design">
|
||||
<Changes type="added">
|
||||
- Social footer
|
||||
- Toggle group
|
||||
- Site description in footer
|
||||
- Site title in footer
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Header design changes
|
||||
- Footer design changes
|
||||
- New functions in theme provider
|
||||
- Object changes in docu.json
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Updates to path structure components
|
||||
- Groups to organize components
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.7.0
|
||||
</div>
|
||||
|
||||
<Release version="1.7.0" date="2025-02-23" title="Remove the old function in the search dialog and replace it with a new and more optimal feature">
|
||||
<Changes type="added">
|
||||
- Up and down navigation in search dialog
|
||||
- Enter (return) to select in search dialog
|
||||
- Escape to close the dialog
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Maintenance for anchor components
|
||||
- Anchor.tsx adjustments for all elements that use it
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove suboptimal search features
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.6.0
|
||||
</div>
|
||||
|
||||
<Release version="1.6.0" date="2025-02-21" title="New Feature Card Groups with arrays for more Flexible Content">
|
||||
<Changes type="added">
|
||||
- Card Groups Components
|
||||
- Props: href to url link
|
||||
- Props: horizontal boolean
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Card props styling
|
||||
- Compatibility for Cards components
|
||||
- Support for children props in card content
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove unused props cards components
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.5.0
|
||||
</div>
|
||||
|
||||
<Release version="1.5.0" date="2025-02-18" title="Minor Update - improved features and responsiveness on all devices">
|
||||
<Changes type="added">
|
||||
- New dialog footer on searchbox above medium screens
|
||||
- Icon X for close dialog on searchbox (ESC key on medium screen)
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Responsive Leftbar components on large screens
|
||||
- Menu Trigger on medium screens
|
||||
- Responsive Navbar components on medium screens
|
||||
- Better UX for searchbox dialog
|
||||
- Tooltips components can be written together with regular paragraphs
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Responsive issues
|
||||
- Compatibility for Bun
|
||||
- Changes postcss.config.js to .cjs for Bun
|
||||
- All CLI installer and updater not working
|
||||
- Adjustments for package managers (npm, pnpm, bun, yarn)
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.4.2
|
||||
</div>
|
||||
|
||||
<Release version="1.4.2" date="2025-02-16" title="Complex Content for Accordion Component props children">
|
||||
<Changes type="added">
|
||||
- New Props with children in accordion
|
||||
- Compatibility for markdown in accordion
|
||||
- Nested components inside an accordion
|
||||
- New icon on note components
|
||||
- Add CLI npx @docubook/create@latest
|
||||
- Add CLI npx @docubook/update@latest
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Better UI design for accordion
|
||||
- Styling Note components on markdown
|
||||
- Change accordion output on playground
|
||||
- Change accordion output on snippet
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove deprecated props on accordion
|
||||
- Remove CLI npx update_docu
|
||||
- Remove CLI npx create_docu
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.4.0
|
||||
</div>
|
||||
|
||||
<Release version="1.4.0" date="2025-02-11" title="Floating Button Version with Dynamic Tag version on Changelog page">
|
||||
<Changes type="added">
|
||||
- New components / changelog floating-version.tsx
|
||||
- Button popover to open version-toc below large screens
|
||||
- Dynamic tag by section ID #version
|
||||
- Dynamic url tag #version
|
||||
- Dynamic version indicator on floating version when scrolling section by ID
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Change icon version history
|
||||
- Responsive version-toc
|
||||
- Improvement components to changelog page
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.3.8
|
||||
</div>
|
||||
|
||||
<Release version="1.3.8" date="2025-02-08" title="Responsive Table of Content">
|
||||
<Changes type="added">
|
||||
- Components terminal MagicUI
|
||||
- Components card Shadcn
|
||||
- New mob-toc for a better experience on mobile devices
|
||||
- New Components scroll to top button
|
||||
- Scroll to top: blog-post
|
||||
- Scroll to top: docs-post
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- lib/markdown for generated dynamic toc on markdown
|
||||
- Responsive Table of Content below large screens
|
||||
- Improve docs page
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.3.6
|
||||
</div>
|
||||
|
||||
<Release version="1.3.6" date="2025-02-01" title="Appears more modern editor for Docu Play">
|
||||
|
||||
<Changes type="added">
|
||||
- Line Number for editor
|
||||
- editor.css
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Better Design for Editor
|
||||
- Similar to Github Editor
|
||||
- Moved Handler Element (copy, download, reset and fullscreen) on Header
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.3.5
|
||||
</div>
|
||||
|
||||
<Release version="1.3.5" date="2025-01-30" title="It's Easy to Write Markdown with Playground">
|
||||
|
||||
<Changes type="added">
|
||||
- New Playground Page
|
||||
- New Playground Layout
|
||||
- Toolbar for Markdown Components
|
||||
- Fullscreen Mode to Focus Editing Your Content
|
||||
- Copy to Clipboard Your Content
|
||||
- Download Your Content as index.mdx
|
||||
- Reset Your Content without refresh the Browser
|
||||
- Only Large Screen for Better Experience
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.3.1
|
||||
</div>
|
||||
|
||||
<Release version="1.3.1" date="2025-01-20" title="Snippet Feature to Easily Write Markdown and Call DocuBook Components">
|
||||
|
||||
<Changes type="added">
|
||||
- New Feature Snippet for Markdown Components
|
||||
- Support Snippet for Visual Studio Code
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove props icon and props description for accordion components
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.3.0
|
||||
</div>
|
||||
|
||||
<Release version="1.3.0" date="2024-12-31" title="Release Note Feature to Make it Easier to Write Changelogs">
|
||||
<Changes type="added">
|
||||
- New Release Note Feature
|
||||
- New Layout for Changelog page
|
||||
- New Changelog page
|
||||
- Add Release Note Component
|
||||
- Easily write release notes directly from the CHANGELOG.md file
|
||||
- TOC for versioning
|
||||
- Write with the markdown tag
|
||||
- Add lib / changelog.ts
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Improvement Responsive feature image for Version Entry
|
||||
- Improvement Layout for changelog page
|
||||
- Improvement Padding on mobile devices
|
||||
- Only use containers of md size
|
||||
- Improvement syntax.css for ul>li classes
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Fix og:image not showing on Page.tsx
|
||||
- Fix text-indent on class li
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove excessive padding
|
||||
- Remove Logo on Footer
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.2.0
|
||||
</div>
|
||||
|
||||
<Release version="1.2.0" date="2024-12-22" title="New Accordion Component: Support content plain text, html and all markdown component">
|
||||
<Changes type="added">
|
||||
- Add New Accordion Component
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Props Improvement
|
||||
- Support Dynamic Content for Accordion
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.1.0
|
||||
</div>
|
||||
|
||||
<Release version="1.1.0" date="2024-12-15" title="Minor Update: Easily manage set up with docu.json">
|
||||
<Changes type="added">
|
||||
- Add docu.json file
|
||||
- Add openGraph (title, description, image)
|
||||
- Add Dynamic metadata
|
||||
- Generate metadata as openGraph
|
||||
- OpenGraph support for .mdx
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Routes-config from json
|
||||
- Frontmatter improvement
|
||||
- Edit the content of footer.tsx simply via the docu.json file
|
||||
- Edit the content of navbar.tsx simply via the docu.json file
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.0.7
|
||||
</div>
|
||||
|
||||
<Release version="1.0.7" date="2024-12-14" title="Easily updates your DocuBook Version with CLI npx update_docu">
|
||||
<Changes type="added">
|
||||
- CLI npx update_docu (update features into docubook existing directory)
|
||||
- Playground (easily to written content)
|
||||
- New Button component
|
||||
- Navbar external link conditions
|
||||
- CLI npx create_docu
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Searchbar Improvement
|
||||
- Navigation Improvement
|
||||
- Edit on Github Improvement
|
||||
</Changes>
|
||||
|
||||
<Changes type="removed">
|
||||
- Remove CLI npx create-docu (on this version not usage dash `-`)
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.0.6
|
||||
</div>
|
||||
|
||||
<Release version="1.0.6" date="2024-11-24" title="New Components, Fix and Improvement">
|
||||
<Changes type="added">
|
||||
- New Card component
|
||||
- New Tooltips component
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Change root folder
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Logo on navbar & footer
|
||||
- Easily change logo
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.0.5
|
||||
</div>
|
||||
|
||||
<Release version="1.0.5" date="2024-11-16" title="Add New Features and Improvement for this version">
|
||||
<Changes type="added">
|
||||
- New Youtube component
|
||||
- Edit this page - easily manage directory content via the github repo
|
||||
- Support installation via CLI command npx create-docu
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Keyboard shortcut command + k or ctrl + k to open search dialog
|
||||
</Changes>
|
||||
</Release>
|
||||
|
||||
<div className="sr-only">
|
||||
### v 1.0.0
|
||||
</div>
|
||||
|
||||
<Release version="1.0.0" date="2024-11-10" title="Initial release of DocuBook to create interactive nested docs with MDX">
|
||||
<Changes type="added">
|
||||
- Initial release of DocuBook
|
||||
- Basic documentation structure
|
||||
- Markdown support with MDX
|
||||
- Responsive design
|
||||
- Search functionality
|
||||
- Dark mode support
|
||||
</Changes>
|
||||
</Release>
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
title: Accordion
|
||||
description: A component used to create collapsible content that can be hidden and shown again.
|
||||
date: 22-12-2024
|
||||
---
|
||||
|
||||
## Preview
|
||||
|
||||
### Basic Usage
|
||||
|
||||
<Accordion title="Click to expand" defaultOpen={true}>
|
||||
This is a simple accordion component that can be toggled by clicking the header. The content can include any valid React nodes, including text, components, and markdown.
|
||||
</Accordion>
|
||||
|
||||
### With Code Block
|
||||
|
||||
<Accordion title="Code Example" className="mt-4">
|
||||
```javascript:utils.js showLineNumbers
|
||||
// Example of using the Accordion component
|
||||
import Accordion from '@/components/markdown/AccordionMdx';
|
||||
|
||||
function Example() {
|
||||
return (
|
||||
<Accordion title="Click to see code">
|
||||
<pre>
|
||||
{`function greet() {\n console.log('Hello, world!');\n}`}
|
||||
</pre>
|
||||
</Accordion>
|
||||
);
|
||||
}
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
### With Markdown Content
|
||||
|
||||
<Accordion title="Markdown Example" className="mt-4">
|
||||
## This is a markdown heading
|
||||
|
||||
- List item 1
|
||||
- List item 2
|
||||
- List item 3
|
||||
|
||||
You can include **bold** and *italic* text, [links](#), and other markdown elements.
|
||||
</Accordion>
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `title` | string | - | **Required**. The text displayed in the accordion header. |
|
||||
| `children` | ReactNode | null | The content to be displayed when the accordion is expanded. Can be plain text, markdown, or React components. |
|
||||
| `defaultOpen` | boolean | false | When true, the accordion will be expanded by default. |
|
||||
| `className` | string | undefined | Additional CSS classes to apply to the accordion container. |
|
||||
|
||||
## Output Markdown
|
||||
|
||||
<Tabs defaultValue="markdown" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="markdown">Markdown</TabsTrigger>
|
||||
<TabsTrigger value="codeblock">Code Block</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="markdown">
|
||||
```plaintext
|
||||
<Accordion title="Markdown">
|
||||
this is an example of plain text content from the accordion component and below is markdown ;
|
||||
1. number one
|
||||
2. number two
|
||||
3. number three
|
||||
</Accordion>
|
||||
```
|
||||
</TabsContent>
|
||||
<TabsContent value="codeblock">
|
||||
````plaintext
|
||||
<Accordion title="Code Block" defaultOpen={true}>
|
||||
```javascript:main.js showLineNumbers {3-4}
|
||||
function isRocketAboutToCrash() {
|
||||
// Check if the rocket is stable
|
||||
if (!isStable()) {
|
||||
NoCrash(); // Prevent the crash
|
||||
}
|
||||
}
|
||||
```
|
||||
</Accordion>
|
||||
````
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
title: Button
|
||||
description: A component used to create buttons that can be used to trigger actions or navigate to other pages.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
## Preview
|
||||
|
||||
<Button
|
||||
text="Learn More"
|
||||
href="https://learn.example.com"
|
||||
icon="MoveUpRight"
|
||||
size="md"
|
||||
target="_blank"
|
||||
variation="primary"
|
||||
/>
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ----------- | -------- | ----------- | -------------------------------------------- |
|
||||
| `text` | string | undefined | The button text |
|
||||
| `href` | string | **required**| The URL to navigate to |
|
||||
| `icon` | string | undefined | Lucide icon name (e.g. "MoveUpRight") |
|
||||
| `size` | string | "md" | Button size: `"sm"`, `"md"`, or `"lg"` |
|
||||
| `target` | string | undefined | Link target (e.g. "_blank") |
|
||||
| `variation` | string | "primary" | Button style: `"primary"`, `"accent"`, or `"outline"` |
|
||||
|
||||
## Output Markdown
|
||||
|
||||
```markdown
|
||||
<Button
|
||||
text="Learn More"
|
||||
href="https://learn.example.com"
|
||||
icon="MoveUpRight"
|
||||
size="md"
|
||||
target="_blank"
|
||||
variation="primary"
|
||||
/>
|
||||
```
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
title: Card Group
|
||||
description: A component used to create card groups that can be used to display multiple cards in a compact and organized way.
|
||||
date: 20-02-2025
|
||||
---
|
||||
|
||||
## Preview
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Heading 1" icon="Heading1">
|
||||
This is an example of card content with columns.
|
||||
</Card>
|
||||
<Card title="Heading 2" icon="Heading2">
|
||||
This is an example of card content with columns.
|
||||
</Card>
|
||||
<Card title="Grid Card" icon="Grid" horizontal>
|
||||
This is a horizontal card layout.
|
||||
</Card>
|
||||
<Card title="Horizontal Card" icon="Layout" horizontal>
|
||||
This is a horizontal card layout.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ------------- | -------- | ------- | ------------------------------------------------------- |
|
||||
| `cols` | number | {2} | By default 2 The number of columns per row |
|
||||
|
||||
## Output Markdown
|
||||
|
||||
```markdown
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Heading 1" icon="Heading1">
|
||||
This is an example of card content with columns.
|
||||
</Card>
|
||||
<Card title="Heading 2" icon="Heading2">
|
||||
This is an example of card content with columns.
|
||||
</Card>
|
||||
<Card title="Grid Card" icon="Grid" horizontal>
|
||||
This is a horizontal card layout.
|
||||
</Card>
|
||||
<Card title="Horizontal Card" icon="Layout" horizontal>
|
||||
This is a horizontal card layout.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
```
|
||||
@@ -1,68 +0,0 @@
|
||||
---
|
||||
title: Cards
|
||||
description: A component used to create cards that can be used to display content in a compact and organized way.
|
||||
date: 20-02-2025
|
||||
---
|
||||
|
||||
## Example
|
||||
|
||||
### Card with Link and icon
|
||||
|
||||
<Card title="Click on me" icon="Link" href="/docs/components/card-group">
|
||||
This is how you use a card with an icon and a link. Clicking on this card
|
||||
brings you to the Card Group page.
|
||||
</Card>
|
||||
|
||||
### Card Horizontal
|
||||
|
||||
<Card title="Horizontal Card" icon="Layout" horizontal>
|
||||
This is a horizontal card layout.
|
||||
</Card>
|
||||
|
||||
### Card Simple
|
||||
|
||||
<Card title="Simple Card">
|
||||
This is a simple card without an icon or link.
|
||||
</Card>
|
||||
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ------------- | -------- | ------- | ------------------------------------------------------- |
|
||||
| `title` | string | null | The value of card title. |
|
||||
| `icon` | string | null | The value of card icon render from lucide. |
|
||||
| `href` | string | null | The value of card link url. |
|
||||
| `horizontal` | boolean | undefined | horizontal layout for card. |
|
||||
|
||||
## Output Markdown
|
||||
|
||||
<Tabs defaultValue="link" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="link">Link & Icon</TabsTrigger>
|
||||
<TabsTrigger value="horizontal">Horizontal</TabsTrigger>
|
||||
<TabsTrigger value="simple">Simple</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="link">
|
||||
```markdown
|
||||
<Card title="Click on me" icon="Link" href="/docs/getting-started/components/button">
|
||||
This is how you use a card with an icon and a link. Clicking on this card
|
||||
brings you to the Card Group page.
|
||||
</Card>
|
||||
```
|
||||
</TabsContent>
|
||||
<TabsContent value="horizontal">
|
||||
```markdown
|
||||
<Card title="Horizontal Card" icon="Layout" horizontal>
|
||||
This is a horizontal card layout.
|
||||
</Card>
|
||||
```
|
||||
</TabsContent>
|
||||
<TabsContent value="simple">
|
||||
```markdown
|
||||
<Card title="Simple Card">
|
||||
This is a simple card without an icon or link.
|
||||
</Card>
|
||||
```
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
title: Code Block
|
||||
description: A component used to display code snippets with optional line numbering and line highlighting.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
## Preview
|
||||
|
||||
```javascript:main.js showLineNumbers {3-4}
|
||||
function isRocketAboutToCrash() {
|
||||
// Check if the rocket is stable
|
||||
if (!isStable()) {
|
||||
NoCrash(); // Prevent the crash
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, line numbers are displayed for lines 1 to 4. You can specify which lines to highlight using the format `{2,3-5}`.
|
||||
|
||||
## Output Markdown
|
||||
|
||||
You can directly use the following syntax to create a code block with line numbers and highlight specific lines:
|
||||
|
||||
````plaintext
|
||||
```javascript:main.js showLineNumbers {3-4}
|
||||
function isRocketAboutToCrash() {
|
||||
// Check if the rocket is stable
|
||||
if (!isStable()) {
|
||||
NoCrash(); // Prevent the crash
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
## Features
|
||||
|
||||
- **Line Numbers**: Enable line numbers by adding `showLineNumbers` after the opening backticks.
|
||||
- **Highlight Lines**: Specify lines to highlight using curly braces (e.g., `{2,3-5}`).
|
||||
- **Syntax Highlighting**: Use the appropriate language for syntax highlighting.
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: Custom Components
|
||||
description: How to create custom components for Markdown.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
To add custom components in DocuBook, follow these steps:
|
||||
|
||||
1. **Create Your Component**: First, create your custom component in the `@components/markdown` folder. For example, you might create a file named `Outlet.tsx`.
|
||||
|
||||
2. **Import Your Component**: Next, open the `@lib/markdown.ts` file. This is where you'll register your custom component for use in Markdown.
|
||||
|
||||
3. **Add Your Component to the Components Object**: In the `@lib/markdown.ts` file, import your custom component and add it to the `components` object. Here’s how to do it:
|
||||
|
||||
```ts
|
||||
import Outlet from "@/components/markdown/outlet";
|
||||
|
||||
// Add custom components
|
||||
const components = {
|
||||
Outlet,
|
||||
};
|
||||
```
|
||||
|
||||
4. **Using Your Custom Component in Markdown**: After registering your component, you can now use it anywhere in your Markdown content. For instance, if your `Outlet` component is designed to display additional information, you can use it as follows:
|
||||
|
||||
### Markdown Example
|
||||
|
||||
```markdown
|
||||
<Outlet>
|
||||
This is some custom content rendered by the Outlet component!
|
||||
</Outlet>
|
||||
```
|
||||
|
||||
### Rendered Output
|
||||
|
||||
This will render the content inside the `Outlet` component, allowing you to create reusable and dynamic Markdown content.
|
||||
|
||||
By following these steps, you can extend the capabilities of your Markdown documentation and create a more engaging user experience.
|
||||
@@ -1,109 +0,0 @@
|
||||
---
|
||||
title: File Tree Component
|
||||
description: A customizable file tree component for displaying hierarchical file structures in your documentation.
|
||||
date: 28-05-2025
|
||||
---
|
||||
|
||||
The File Tree component allows you to display hierarchical file structures in your documentation with collapsible folders and files.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```
|
||||
<Files>
|
||||
<Folder name="src">
|
||||
<File name="App.tsx" />
|
||||
<File name="index.tsx" />
|
||||
<Folder name="components">
|
||||
<File name="Button.tsx" />
|
||||
<File name="Card.tsx" />
|
||||
</Folder>
|
||||
<Folder name="pages">
|
||||
<File name="Home.tsx" />
|
||||
<File name="About.tsx" />
|
||||
</Folder>
|
||||
</Folder>
|
||||
</Files>
|
||||
```
|
||||
|
||||
Render As:
|
||||
<Files>
|
||||
<Folder name="src">
|
||||
<File name="App.tsx" />
|
||||
<File name="index.tsx" />
|
||||
<Folder name="components">
|
||||
<File name="Button.tsx" />
|
||||
<File name="Card.tsx" />
|
||||
</Folder>
|
||||
<Folder name="pages">
|
||||
<File name="Home.tsx" />
|
||||
<File name="About.tsx" />
|
||||
</Folder>
|
||||
</Folder>
|
||||
</Files>
|
||||
|
||||
## Props
|
||||
|
||||
### Files
|
||||
|
||||
The root component that wraps the entire file tree.
|
||||
|
||||
### Folder
|
||||
|
||||
| Prop | Type | Required | Description |
|
||||
|----------|----------|----------|---------------------------------------|
|
||||
| `name` | string | Yes | The name of the folder |
|
||||
| `children` | ReactNode | No | Child elements (File or Folder) |
|
||||
|
||||
### File
|
||||
|
||||
| Prop | Type | Required | Description |
|
||||
|------|--------|----------|----------------------------|
|
||||
| `name` | string | Yes | The name of the file |
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
### Nested Folder Structure
|
||||
|
||||
```
|
||||
<Files>
|
||||
<Folder name="project-root">
|
||||
<File name="package.json" />
|
||||
<File name="tsconfig.json" />
|
||||
<Folder name="src">
|
||||
<File name="index.ts" />
|
||||
<Folder name="components">
|
||||
<File name="Button.tsx" />
|
||||
<File name="Card.tsx" />
|
||||
</Folder>
|
||||
</Folder>
|
||||
</Folder>
|
||||
</Files>
|
||||
```
|
||||
|
||||
### Minimal Example
|
||||
|
||||
```
|
||||
<Files>
|
||||
<Folder name="components">
|
||||
<File name="Button.tsx" />
|
||||
<File name="Input.tsx" />
|
||||
</Folder>
|
||||
</Files>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Keep the nesting level reasonable (recommended max 3-4 levels deep)
|
||||
2. Use clear and descriptive names for files and folders
|
||||
3. Consider the user experience when displaying large file structures
|
||||
4. Use consistent naming conventions throughout your file tree
|
||||
|
||||
## Accessibility
|
||||
|
||||
The File Tree component includes built-in accessibility features:
|
||||
|
||||
- Keyboard navigation support
|
||||
- ARIA attributes for screen readers
|
||||
- Focus management for interactive elements
|
||||
- High contrast mode support
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
title: Image
|
||||
description: A component used to display images in Markdown.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
In DocuBook, all images written in Markdown are automatically converted to their respective Next.js components. This allows for better optimization and performance in your application.
|
||||
|
||||
## Images
|
||||
|
||||
Similarly, images in Markdown are transformed into the Next.js `Image` component. This allows for automatic image optimization, such as lazy loading and resizing, which enhances performance and user experience. Here’s an example:
|
||||
|
||||
### Markdown
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
### Rendered Output
|
||||
|
||||
The above Markdown is converted to:
|
||||
|
||||
```jsx
|
||||
<Image
|
||||
src="https://via.placeholder.com/150"
|
||||
alt="Alt text for the image"
|
||||
width={800}
|
||||
height={350}
|
||||
/>
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Performance Optimization**: Automatic conversion to Next.js components ensures optimized loading of images.
|
||||
- **Responsive Images**: Next.js `Image` component handles responsive images, providing the best quality for various device sizes.
|
||||
|
||||
By utilizing these features, you can ensure that your documentation is not only visually appealing but also performs efficiently.
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
title: Components
|
||||
description: This section provides an overview of the custom components available in DocuBook.
|
||||
date: 29-11-2024
|
||||
---
|
||||
|
||||
Explore the custom components we've defined for easy integration and development within your projects. Each component is designed to enhance your workflow and streamline your development process.
|
||||
|
||||
<Outlet path="components" />
|
||||
@@ -1,117 +0,0 @@
|
||||
---
|
||||
title: Keyboard
|
||||
description: Display keyboard keys with platform-specific styling for Windows and macOS.
|
||||
date : 19-05-2025
|
||||
---
|
||||
|
||||
The `Keyboard` component automatically renders platform-appropriate key symbols for macOS and Windows. It's perfect for documenting keyboard shortcuts in your application.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Simply use the `Kbd` component with a `show` prop:
|
||||
|
||||
```tsx
|
||||
<Kbd show="cmd" type="mac" /> + <Kbd show="c" />
|
||||
```
|
||||
|
||||
Renders as:
|
||||
<Kbd show="cmd" type="mac" /> + <Kbd show="c" />
|
||||
|
||||
### Automatic Symbol Rendering
|
||||
|
||||
The component automatically renders appropriate symbols based on the platform:
|
||||
|
||||
```tsx
|
||||
{/* Windows style (default) */}
|
||||
<Kbd show="ctrl" /> + <Kbd show="v" />
|
||||
|
||||
{/* Mac style */}
|
||||
<Kbd show="cmd" type="mac" /> + <Kbd show="v" type="mac" />
|
||||
```
|
||||
|
||||
Renders as:
|
||||
- Windows: <Kbd show="ctrl" type="window" /> + <Kbd show="v" type="window" />
|
||||
- Mac: <Kbd show="cmd" type="mac" /> + <Kbd show="v" type="mac" />
|
||||
|
||||
### Custom Content
|
||||
|
||||
For custom key labels, provide children:
|
||||
|
||||
```tsx
|
||||
<Kbd show="custom">Custom</Kbd>
|
||||
```
|
||||
|
||||
Renders as: <Kbd show="custom">Custom</Kbd>
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|-----------|---------------------|------------|-------------|
|
||||
| `show` | string | (required) | The key identifier (e.g., 'cmd', 'ctrl', 'a') |
|
||||
| `type` | string | `window` | for device type `mac` or `window` | Platform style or custom content |
|
||||
| `children`| ReactNode | - | Custom content to display (overrides automatic rendering) |
|
||||
|
||||
## Supported Keys
|
||||
|
||||
The component includes special handling for common keys:
|
||||
|
||||
| Key Name | Windows | macOS |
|
||||
|-------------|---------|-------|
|
||||
| command/cmd | `Win` | `⌘` |
|
||||
| option/alt | `Alt` | `⌥` |
|
||||
| shift | `Shift` | `⇧` |
|
||||
| ctrl/control| `Ctrl` | `⌃` |
|
||||
| tab | `Tab` | `⇥` |
|
||||
| enter/return| `Enter` | `⏎` |
|
||||
| delete | `Del` | `⌫` |
|
||||
| escape/esc | `Esc` | `⎋` |
|
||||
| up/down/left/right | `↑` `↓` `←` `→` | `↑` `↓` `←` `→` |
|
||||
| space | `Space` | `␣` |
|
||||
|
||||
## Examples
|
||||
|
||||
### Common Shortcuts
|
||||
|
||||
```tsx
|
||||
{/* Copy shortcut */}
|
||||
<Kbd show="ctrl" /> + <Kbd show="c" />
|
||||
|
||||
{/* Paste shortcut */}
|
||||
<Kbd show="cmd" type="mac" /> + <Kbd show="v" type="mac" />
|
||||
|
||||
{/* Save shortcut */}
|
||||
<Kbd show="ctrl" /> + <Kbd show="s" />
|
||||
```
|
||||
|
||||
### Custom Key Combinations
|
||||
|
||||
```tsx
|
||||
{/* Custom application shortcut */}
|
||||
<Kbd show="cmd" type="mac" /> + <Kbd show="option" type="mac" /> + <Kbd show="a" type="mac"/>
|
||||
```
|
||||
|
||||
Render as: <Kbd show="cmd" type="mac" /> + <Kbd show="option" type="mac" /> + <Kbd show="a" type="mac"/>
|
||||
|
||||
### Arrow Key
|
||||
|
||||
```tsx
|
||||
<Kbd show="up" /> <Kbd show="down" /> <Kbd show="left" /> <Kbd show="right" />
|
||||
```
|
||||
|
||||
Render as: <Kbd show="up" /> <Kbd show="down" /> <Kbd show="left" /> <Kbd show="right" />
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Be Consistent**: Stick to one platform style within the same context
|
||||
2. **Use Type Wisely**:
|
||||
- Use `type="mac"` for Mac-specific documentation
|
||||
- Use `type="window"` (default) for Windows/Linux
|
||||
3. **Accessibility**: The component uses semantic `<kbd>` HTML for better accessibility
|
||||
|
||||
## Notes
|
||||
|
||||
- The component automatically capitalizes single letters (e.g., 'a' becomes 'A')
|
||||
- Unrecognized keys are displayed as-is
|
||||
- Dark mode is automatically supported through Tailwind's dark mode classes
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
title: Link
|
||||
description: A component used to create links that can be used to navigate to other pages.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
In DocuBook, all links written in Markdown are automatically converted to their respective Next.js components. This allows for better optimization and performance in your application.
|
||||
|
||||
## Links
|
||||
|
||||
When you create a link in your Markdown, it is converted to the Next.js `Link` component. This enables client-side navigation and improves loading times. Here’s an example of how a Markdown link is transformed:
|
||||
|
||||
### Markdown
|
||||
|
||||
```markdown
|
||||
[Visit OpenAI](https://www.openai.com)
|
||||
```
|
||||
|
||||
### Rendered Output
|
||||
|
||||
The above Markdown is converted to:
|
||||
|
||||
```jsx
|
||||
<Link href="https://www.openai.com" target="_blank" rel="noopener noreferrer">
|
||||
Visit OpenAI
|
||||
</Link>
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Performance Optimization**: Automatic conversion to Next.js components ensures optimized loading of links.
|
||||
- **Improved User Experience**: Client-side navigation with Next.js `Link` improves the browsing experience.
|
||||
|
||||
By utilizing these features, you can ensure that your documentation is not only visually appealing but also performs efficiently.
|
||||
@@ -1,44 +0,0 @@
|
||||
---
|
||||
title: Note
|
||||
description: A component used to display different types of messages such as general notes, warnings, or success notifications.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
## Preview
|
||||
|
||||
<Note type="note" title="Note">
|
||||
This is a general note to convey information to the user.
|
||||
</Note>
|
||||
<Note type="danger" title="Danger">
|
||||
This is a danger alert to notify the user of a critical issue.
|
||||
</Note>
|
||||
<Note type="warning" title="Warning">
|
||||
This is a warning alert for issues that require attention.
|
||||
</Note>
|
||||
<Note type="success" title="Success">
|
||||
This is a success message to inform the user of successful actions.
|
||||
</Note>
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ------- | ---------------------------------------------- | ------- | ---------------------------------------- |
|
||||
| `title` | string | "Note" | Sets the title of the note. |
|
||||
| `type` | "note" "danger" "success" "warning" | undefined | Determines the visual style of the note. |
|
||||
|
||||
## Output Markdown
|
||||
|
||||
```markdown
|
||||
<Note type="note" title="Note">
|
||||
This is a general note to convey information to the user.
|
||||
</Note>
|
||||
<Note type="danger" title="Danger">
|
||||
This is a danger alert to notify the user of a critical issue.
|
||||
</Note>
|
||||
<Note type="warning" title="Warning">
|
||||
This is a warning alert for issues that require attention.
|
||||
</Note>
|
||||
<Note type="success" title="Success">
|
||||
This is a success message to inform the user of successful actions.
|
||||
</Note>
|
||||
```
|
||||
@@ -1,130 +0,0 @@
|
||||
---
|
||||
title: Release Note
|
||||
description: The Release Note component makes it easy for you to write updates for each version of your application.
|
||||
date: 31-12-2024
|
||||
---
|
||||
|
||||
The Release Note component makes it easy for you to write and display changelogs in a structured and organized way. This component consists of two main parts: `Release` and `Changes` which can be used to display version, date, release title, and a list of changes categorized by type.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Here is a basic example of using the Release Note component:
|
||||
|
||||
```markdown
|
||||
<Release version="1.10.1" date="2025-05-24" title="Accessibility Improvements and Bug Fixes">
|
||||
<Changes type="added">
|
||||
- New feature to improve accessibility
|
||||
- Keyboard navigation support for dialog components
|
||||
</Changes>
|
||||
<Changes type="fixed">
|
||||
- Bug fix for mobile menu
|
||||
- Fixed loading issues on documentation pages
|
||||
</Changes>
|
||||
</Release>
|
||||
```
|
||||
|
||||
<Accordion title="Render As" defaultOpen={true}>
|
||||
<Release version="1.10.1" date="2025-05-24" title="Accessibility Improvements and Bug Fixes">
|
||||
<Changes type="added">
|
||||
- New feature to improve accessibility
|
||||
- Keyboard navigation support for dialog components
|
||||
</Changes>
|
||||
<Changes type="fixed">
|
||||
- Bug fix for mobile menu
|
||||
- Fixed loading issues on documentation pages
|
||||
</Changes>
|
||||
</Release>
|
||||
</Accordion>
|
||||
|
||||
## Release Component
|
||||
|
||||
The `Release` component is used to display key information about a release version, such as version number, release date, and title.
|
||||
|
||||
### Release Props
|
||||
|
||||
| Prop | Type | Required | Description |
|
||||
|------|------|----------|-------------|
|
||||
| `version` | string | ✅ | Version number to display (without "v" prefix) |
|
||||
| `title` | string | ✅ | Title or name of the release |
|
||||
| `date` | string | ❌ | Release date in a valid format (example: "2025-05-24") |
|
||||
| `children` | ReactNode | ✅ | Child content, typically `Changes` components |
|
||||
|
||||
```markdown
|
||||
<Release
|
||||
version="1.10.1"
|
||||
date="2025-05-24"
|
||||
title="Accessibility Improvements and Bug Fixes"
|
||||
>
|
||||
{/* Changes content here */}
|
||||
</Release>
|
||||
```
|
||||
|
||||
## Changes Component
|
||||
|
||||
The `Changes` component is used to group changes by category with appropriate icons and colors.
|
||||
|
||||
### Changes Props
|
||||
|
||||
| Prop | Type | Required | Description |
|
||||
|------|------|----------|-------------|
|
||||
| `type` | string | ✅ | Type of change: 'added', 'fixed', 'improved', 'deprecated', or 'removed' |
|
||||
| `children` | ReactNode | ✅ | List of changes, can be text with Markdown formatting |
|
||||
|
||||
### Changes Note
|
||||
|
||||
| Category | Description |
|
||||
|----------|-------------|
|
||||
| `added` | New features or functionality added |
|
||||
| `fixed` | Bugs or issues that have been fixed |
|
||||
| `improved` | Enhancements or optimizations to existing features |
|
||||
| `deprecated` | Features that are not recommended and may be removed in future |
|
||||
| `removed` | Features that have been completely removed |
|
||||
|
||||
### Changes Example
|
||||
|
||||
```jsx
|
||||
<Changes type="added">
|
||||
- New feature to improve accessibility
|
||||
- Keyboard navigation support for dialog components
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Bug fix for mobile menu
|
||||
- Fixed loading issues on documentation pages
|
||||
</Changes>
|
||||
```
|
||||
|
||||
## Complete Implementation
|
||||
|
||||
Here is a complete example of using the Release Note component in an MDX file:
|
||||
|
||||
````plaintext
|
||||
<!-- hidden heading for TOC -->
|
||||
|
||||
<Release version="1.10.1" date="2025-05-24" title="Accessibility Improvements and Bug Fixes">
|
||||
<Changes type="added">
|
||||
- Keyboard navigation for all interactive components
|
||||
- Screen reader support for table components
|
||||
- Dark mode feature with system preference detection
|
||||
</Changes>
|
||||
|
||||
<Changes type="fixed">
|
||||
- Fixed mobile menu bug that wouldn't close when navigating to another page
|
||||
- Fixed loading issues on documentation pages
|
||||
- Fixed display issues in Safari browser
|
||||
</Changes>
|
||||
|
||||
<Changes type="improved">
|
||||
- Improved page loading performance
|
||||
- Optimized JavaScript bundle size
|
||||
- Enhanced responsive design across all viewports
|
||||
</Changes>
|
||||
</Release>
|
||||
````
|
||||
|
||||
## Usage Tips
|
||||
|
||||
1. **Date Format**: Use a consistent date format for all releases.
|
||||
2. **Version Ordering**: Arrange versions in reverse chronological order (newest version at the top).
|
||||
3. **List Items**: You can use standard Markdown list format (`-` or `*`) or write text directly, the component will handle the formatting.
|
||||
4. **TOC**: Use hidden headings to ensure each version is detected in the Table of Contents. Use `<div className="sr-only">### v 1.10.1</div>`
|
||||
@@ -1,45 +0,0 @@
|
||||
---
|
||||
title: Stepper
|
||||
description: A component used to display step-by-step instructions directly within the markdown render.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
In this guide, we utilize a custom `Stepper` component, specifically designed for DocuBook, which enables users to display step-by-step instructions directly within the markdown render.
|
||||
|
||||
## Preview
|
||||
|
||||
<Stepper>
|
||||
<StepperItem title="Step 1: Clone the DocuBook Repository">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec interdum,
|
||||
felis sed efficitur tincidunt, justo nulla viverra enim, et maximus nunc
|
||||
dolor in lorem.
|
||||
</StepperItem>
|
||||
<StepperItem title="Step 2: Access the Project Directory">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin non neque ut
|
||||
eros auctor accumsan. Mauris a nisl vitae magna ultricies aliquam.
|
||||
</StepperItem>
|
||||
<StepperItem title="Step 3: Install Required Dependencies">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ut
|
||||
ipsum nec nulla ultricies porttitor et non justo.
|
||||
</StepperItem>
|
||||
</Stepper>
|
||||
|
||||
## Output Markdown
|
||||
|
||||
```markdown
|
||||
<Stepper>
|
||||
<StepperItem title="Step 1: Clone the DocuBook Repository">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec interdum,
|
||||
felis sed efficitur tincidunt, justo nulla viverra enim, et maximus nunc
|
||||
dolor in lorem.
|
||||
</StepperItem>
|
||||
<StepperItem title="Step 2: Access the Project Directory">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin non neque ut
|
||||
eros auctor accumsan. Mauris a nisl vitae magna ultricies aliquam.
|
||||
</StepperItem>
|
||||
<StepperItem title="Step 3: Install Required Dependencies">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ut
|
||||
ipsum nec nulla ultricies porttitor et non justo.
|
||||
</StepperItem>
|
||||
</Stepper>
|
||||
```
|
||||
@@ -1,70 +0,0 @@
|
||||
---
|
||||
title: Tabs
|
||||
description: Organize content into multiple sections with switchable tabs.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
The `Tabs` component allows you to organize content into multiple sections, enabling users to switch between them easily. This is particularly useful for displaying related content in a compact manner.
|
||||
|
||||
## Preview
|
||||
|
||||
<Tabs defaultValue="java" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="java">Java</TabsTrigger>
|
||||
<TabsTrigger value="typescript">TypeScript</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="java">
|
||||
```java
|
||||
// HelloWorld.java
|
||||
public class HelloWorld {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, World!");
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabsContent>
|
||||
<TabsContent value="typescript">
|
||||
```typescript
|
||||
// helloWorld.ts
|
||||
function helloWorld(): void {
|
||||
console.log("Hello, World!");
|
||||
}
|
||||
helloWorld();
|
||||
```
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| -------------- | -------- | ------- | ------------------------------------------------------ |
|
||||
| `defaultValue` | string | null | The value of the tab that is selected by default. |
|
||||
| `className` | string | null | Additional CSS classes for styling the Tabs component. |
|
||||
|
||||
## Output Markdown
|
||||
|
||||
````plaintext
|
||||
<Tabs defaultValue="java" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="java">Java</TabsTrigger>
|
||||
<TabsTrigger value="typescript">TypeScript</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="java">
|
||||
```java
|
||||
// HelloWorld.java
|
||||
public class HelloWorld {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, World!");
|
||||
}
|
||||
}
|
||||
```</TabsContent>
|
||||
<TabsContent value="typescript">
|
||||
```typescript
|
||||
// helloWorld.ts
|
||||
function helloWorld(): void {
|
||||
console.log("Hello, World!");
|
||||
}
|
||||
helloWorld();
|
||||
```</TabsContent>
|
||||
</Tabs>
|
||||
````
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: Tooltips
|
||||
description: A component used to display additional information when hovering over a word or phrase.
|
||||
date: 19-02-2025
|
||||
---
|
||||
|
||||
I have implemented the `tooltips` component into markdown which allows you to add additional information to a word or phrase when hovering. This feature is useful for providing definitions, explanations, or any other additional information that can enhance the user experience.
|
||||
|
||||
## Usage
|
||||
You can use tooltips in your Markdown content to provide additional information when hovering over a word or phrase.
|
||||
|
||||
### Preview
|
||||
|
||||
What do you know about <Tooltip text="DocuBook" tip="npx @docubook/create@latest" /> ? Create interactive nested documentations using MDX.
|
||||
|
||||
### Output Markdown
|
||||
|
||||
The above Markdown is converted to:
|
||||
|
||||
```markdown:index.mdx
|
||||
What do you know about <Tooltip text="DocuBook" tip="npx @docubook/create@latest" /> ? Create interactive nested documentations using MDX.
|
||||
```
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: Youtube
|
||||
description: A component used to embed YouTube videos directly into your documentation.
|
||||
date: 14-12-2024
|
||||
---
|
||||
|
||||
I have implemented a `YouTube` component for your documentation. This component allows you to easily embed YouTube videos directly into your documentation by simply inputting the video's ID.
|
||||
|
||||
## Preview
|
||||
|
||||
<Youtube videoId="8sM0Di7Ew9Q" />
|
||||
|
||||
## Output Markdown
|
||||
|
||||
```markdown
|
||||
<Youtube videoId="8sM0Di7Ew9Q" />
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
<Note type="note" title="Usage">
|
||||
for example the youtube URL show this https://www.youtube.com/watch?v=8sM0Di7Ew9Q the ID `8sM0Di7Ew9Q`
|
||||
</Note>
|
||||
135
contents/docs/configuration/appearance/index.mdx
Normal file
135
contents/docs/configuration/appearance/index.mdx
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
title: Appearance Settings
|
||||
description: Customize the look and feel of your WooNooW store
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Accessing Appearance Settings
|
||||
|
||||
Go to **WooNooW → Appearance** in the WordPress admin.
|
||||
|
||||
---
|
||||
|
||||
## General Settings
|
||||
|
||||
### Logo
|
||||
|
||||
Upload your store logo for display in the header.
|
||||
|
||||
- **Recommended size**: 200x60 pixels (width x height)
|
||||
- **Formats**: PNG (transparent background recommended), SVG, JPG
|
||||
- **Mobile**: Automatically resized for smaller screens
|
||||
|
||||
### SPA Page
|
||||
|
||||
Select which page hosts the WooNooW SPA. Default is "Store".
|
||||
|
||||
> **Note**: This page should contain the `[woonoow_spa]` shortcode.
|
||||
|
||||
### SPA Mode
|
||||
|
||||
Choose how WooNooW handles your store pages:
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| **Full** | All WooCommerce pages redirect to SPA |
|
||||
| **Disabled** | Native WooCommerce templates are used |
|
||||
|
||||
---
|
||||
|
||||
## Colors
|
||||
|
||||
### Primary Color
|
||||
|
||||
The main brand color used for:
|
||||
- Buttons
|
||||
- Links
|
||||
- Active states
|
||||
- Primary actions
|
||||
|
||||
**Default**: `#6366f1` (Indigo)
|
||||
|
||||
### Secondary Color
|
||||
|
||||
Secondary UI elements:
|
||||
- Less prominent buttons
|
||||
- Borders
|
||||
- Subtle backgrounds
|
||||
|
||||
**Default**: `#64748b` (Slate)
|
||||
|
||||
### Accent Color
|
||||
|
||||
Highlight color for:
|
||||
- Sale badges
|
||||
- Notifications
|
||||
- Call-to-action elements
|
||||
|
||||
**Default**: `#f59e0b` (Amber)
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
### Body Font
|
||||
|
||||
Font used for general text content.
|
||||
|
||||
**Options**: System fonts and Google Fonts
|
||||
- Inter
|
||||
- Open Sans
|
||||
- Roboto
|
||||
- Lato
|
||||
- Poppins
|
||||
- And more...
|
||||
|
||||
### Heading Font
|
||||
|
||||
Font used for titles and headings.
|
||||
|
||||
**Options**: Same as body fonts, plus:
|
||||
- Cormorant Garamond (Serif option)
|
||||
- Playfair Display
|
||||
- Merriweather
|
||||
|
||||
### Font Sizes
|
||||
|
||||
Font sizes are responsive and adjust automatically based on screen size.
|
||||
|
||||
---
|
||||
|
||||
## Layout
|
||||
|
||||
### Container Width
|
||||
|
||||
Maximum width of the content area.
|
||||
|
||||
| Option | Width |
|
||||
|--------|-------|
|
||||
| Narrow | 1024px |
|
||||
| Default | 1280px |
|
||||
| Wide | 1536px |
|
||||
| Full | 100% |
|
||||
|
||||
### Header Style
|
||||
|
||||
Configure the header appearance:
|
||||
- **Fixed**: Stays at top when scrolling
|
||||
- **Static**: Scrolls with page
|
||||
|
||||
### Product Grid
|
||||
|
||||
Columns in the shop page grid:
|
||||
- Mobile: 1-2 columns
|
||||
- Tablet: 2-3 columns
|
||||
- Desktop: 3-4 columns
|
||||
|
||||
---
|
||||
|
||||
## Saving Changes
|
||||
|
||||
1. Make your changes
|
||||
2. Click **Save Changes** button
|
||||
3. Refresh your store page to see updates
|
||||
|
||||
> **Tip**: Open your store in another tab to preview changes quickly.
|
||||
141
contents/docs/configuration/spa-mode/index.mdx
Normal file
141
contents/docs/configuration/spa-mode/index.mdx
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
title: SPA Mode
|
||||
description: Understanding and configuring WooNooW's SPA mode
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## What is SPA Mode?
|
||||
|
||||
SPA Mode controls how WooNooW handles your WooCommerce pages. It determines whether visitors experience the modern SPA interface or traditional WooCommerce templates.
|
||||
|
||||
---
|
||||
|
||||
## Available Modes
|
||||
|
||||
### Full Mode (Recommended)
|
||||
|
||||
**All WooCommerce pages redirect to the SPA.**
|
||||
|
||||
When a visitor navigates to:
|
||||
- `/shop` → Redirects to `/store/shop`
|
||||
- `/product/example` → Redirects to `/store/product/example`
|
||||
- `/cart` → Redirects to `/store/cart`
|
||||
- `/checkout` → Redirects to `/store/checkout`
|
||||
- `/my-account` → Redirects to `/store/my-account`
|
||||
|
||||
**Benefits**:
|
||||
- Instant page transitions
|
||||
- Modern, consistent UI
|
||||
- Better mobile experience
|
||||
- Smooth animations
|
||||
|
||||
**Best for**:
|
||||
- New stores
|
||||
- Stores wanting a modern look
|
||||
- Mobile-focused businesses
|
||||
|
||||
### Disabled Mode
|
||||
|
||||
**WooCommerce uses its native templates.**
|
||||
|
||||
WooCommerce pages work normally with your theme's templates. WooNooW admin features still work, but the customer-facing SPA is turned off.
|
||||
|
||||
**Benefits**:
|
||||
- Keep existing theme customizations
|
||||
- Compatibility with WooCommerce template overrides
|
||||
- Traditional page-by-page navigation
|
||||
|
||||
**Best for**:
|
||||
- Stores with heavy theme customizations
|
||||
- Testing before full rollout
|
||||
- Troubleshooting issues
|
||||
|
||||
---
|
||||
|
||||
## Switching Modes
|
||||
|
||||
### How to Switch
|
||||
|
||||
1. Go to **WooNooW → Appearance → General**
|
||||
2. Find **SPA Mode** setting
|
||||
3. Select your preferred mode
|
||||
4. Click **Save Changes**
|
||||
|
||||
### What Happens When Switching
|
||||
|
||||
**Switching to Full**:
|
||||
- WooCommerce pages start redirecting
|
||||
- SPA loads for shop experience
|
||||
- No data is changed
|
||||
|
||||
**Switching to Disabled**:
|
||||
- Redirects stop immediately
|
||||
- WooCommerce templates take over
|
||||
- No data is changed
|
||||
|
||||
> **Note**: All your products, orders, and settings remain unchanged when switching modes.
|
||||
|
||||
---
|
||||
|
||||
## URL Structure
|
||||
|
||||
### Full Mode URLs
|
||||
|
||||
```
|
||||
https://yourstore.com/store/ → Home/Shop
|
||||
https://yourstore.com/store/shop → Shop page
|
||||
https://yourstore.com/store/product/slug → Product page
|
||||
https://yourstore.com/store/cart → Cart
|
||||
https://yourstore.com/store/checkout → Checkout
|
||||
https://yourstore.com/store/my-account → Account
|
||||
```
|
||||
|
||||
### Disabled Mode URLs
|
||||
|
||||
Standard WooCommerce URLs:
|
||||
```
|
||||
https://yourstore.com/shop/ → Shop page
|
||||
https://yourstore.com/product/slug → Product page
|
||||
https://yourstore.com/cart/ → Cart
|
||||
https://yourstore.com/checkout/ → Checkout
|
||||
https://yourstore.com/my-account/ → Account
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SEO Considerations
|
||||
|
||||
### Full Mode SEO
|
||||
|
||||
- WooCommerce URLs (`/product/slug`) remain in sitemaps
|
||||
- When users click from search results, they're redirected to SPA
|
||||
- Meta tags are generated dynamically for social sharing
|
||||
- 302 (temporary) redirects preserve link equity
|
||||
|
||||
### Disabled Mode SEO
|
||||
|
||||
- Standard WooCommerce SEO applies
|
||||
- No redirects needed
|
||||
- Works with Yoast SEO, RankMath, etc.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Redirects Not Working
|
||||
|
||||
1. **Flush Permalinks**: Go to Settings → Permalinks → Save Changes
|
||||
2. **Check Store Page**: Ensure the Store page exists and has `[woonoow_spa]`
|
||||
3. **Clear Cache**: Purge all caching layers
|
||||
|
||||
### Blank Pages After Enabling
|
||||
|
||||
1. Verify SPA Mode is set to "Full"
|
||||
2. Clear browser cache
|
||||
3. Check for JavaScript errors in browser console
|
||||
|
||||
### Want to Test Before Enabling
|
||||
|
||||
1. Keep mode as "Disabled"
|
||||
2. Visit `/store/` directly to preview SPA
|
||||
3. Switch to "Full" when satisfied
|
||||
79
contents/docs/developer/addons/bridge-pattern/index.mdx
Normal file
79
contents/docs/developer/addons/bridge-pattern/index.mdx
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: Bridge Pattern
|
||||
description: Integrating third-party plugins with WooNooW
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
# Addon Bridge Pattern
|
||||
|
||||
## Philosophy
|
||||
|
||||
**WooNooW Core = Zero Addon Dependencies**
|
||||
|
||||
We don't integrate specific plugins into WooNooW core. Instead, we provide:
|
||||
1. **Hook system** for addons to extend functionality
|
||||
2. **Bridge snippets** for compatibility with existing plugins
|
||||
3. **Addon development guide** for building proper WooNooW addons
|
||||
|
||||
---
|
||||
|
||||
## The Problem
|
||||
|
||||
Example: **Rajaongkir** (Indonesian Shipping Plugin).
|
||||
It removes standard fields and adds custom dropdowns, storing data in WooCommerce sessions.
|
||||
It doesn't work with WooNooW OrderForm out of the box because the OrderForm uses standard fields and API-based validation.
|
||||
|
||||
---
|
||||
|
||||
## Solution: Bridge Snippet
|
||||
|
||||
### Option A: Standalone Bridge Plugin
|
||||
|
||||
Create a tiny bridge plugin that makes the third-party plugin work with WooNooW.
|
||||
|
||||
```php
|
||||
/**
|
||||
* Plugin Name: WooNooW Rajaongkir Bridge
|
||||
* Description: Makes Rajaongkir plugin work with WooNooW OrderForm
|
||||
* Version: 1.0.0
|
||||
*/
|
||||
|
||||
// Hook into WooNooW's shipping calculation
|
||||
add_filter('woonoow_before_shipping_calculate', function($shipping_data) {
|
||||
if ($shipping_data['country'] === 'ID' && !empty($shipping_data['city'])) {
|
||||
// Search API and set session data
|
||||
$api = Cekongkir_API::get_instance();
|
||||
$results = $api->search_destination_api($shipping_data['city']);
|
||||
|
||||
if (!empty($results[0])) {
|
||||
WC()->session->set('selected_destination_id', $results[0]['id']);
|
||||
}
|
||||
}
|
||||
return $shipping_data;
|
||||
});
|
||||
```
|
||||
|
||||
### Option B: Frontend Injection
|
||||
|
||||
Inject script to handle UI changes.
|
||||
|
||||
```typescript
|
||||
import { addonLoader, addFilter } from '@woonoow/hooks';
|
||||
|
||||
addonLoader.register({
|
||||
id: 'rajaongkir-bridge',
|
||||
init: () => {
|
||||
addFilter('woonoow_order_form_after_shipping', (content, formData, setFormData) => {
|
||||
if (formData.shipping?.country !== 'ID') return content;
|
||||
return (
|
||||
<>
|
||||
{content}
|
||||
<div className="custom-field">
|
||||
{/* Custom Destination Select */}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
50
contents/docs/developer/addons/module-integration/index.mdx
Normal file
50
contents/docs/developer/addons/module-integration/index.mdx
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: Module Integration
|
||||
description: Integrating Addons usage with Module Registry
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
# Addon-Module Integration
|
||||
|
||||
## Vision
|
||||
|
||||
**Module Registry as the Single Source of Truth.**
|
||||
Functionality extensions—whether built-in Modules or external Addons—should live in the same UI.
|
||||
|
||||
## Registration
|
||||
|
||||
Addons register themselves via the `woonoow/addon_registry` filter.
|
||||
|
||||
```php
|
||||
add_filter('woonoow/addon_registry', function($addons) {
|
||||
$addons['my-shipping-addon'] = [
|
||||
'id' => 'my-shipping-addon',
|
||||
'name' => 'My Shipping',
|
||||
'description' => 'Custom shipping integration',
|
||||
'version' => '1.0.0',
|
||||
'author' => 'My Company',
|
||||
'category' => 'shipping',
|
||||
'icon' => 'truck',
|
||||
'settings_url' => '/settings/shipping/my-addon',
|
||||
'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js',
|
||||
];
|
||||
return $addons;
|
||||
});
|
||||
```
|
||||
|
||||
This ensures your addon appears in the **WooNooW Modules** list with a consistent UI, toggle switch, and settings link.
|
||||
|
||||
## Settings Pages
|
||||
|
||||
Addons can register their own SPA routes for settings pages.
|
||||
|
||||
```php
|
||||
add_filter('woonoow/spa_routes', function($routes) {
|
||||
$routes[] = [
|
||||
'path' => '/settings/shipping/my-addon',
|
||||
'component_url' => plugin_dir_url(__FILE__) . 'dist/Settings.js',
|
||||
'title' => 'My Addon Settings',
|
||||
];
|
||||
return $routes;
|
||||
});
|
||||
```
|
||||
79
contents/docs/developer/addons/react-integration/index.mdx
Normal file
79
contents/docs/developer/addons/react-integration/index.mdx
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: React Integration
|
||||
description: Using React within WooNooW Addons
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
# Addon React Integration
|
||||
|
||||
## The Challenge
|
||||
|
||||
External addons cannot bundle React because WooNooW already ships with a React runtime. Bundling it again would cause conflicts and bloat.
|
||||
|
||||
## Solution: Exposed Runtime
|
||||
|
||||
WooNooW exposes its React instance and Component library on the `window` object.
|
||||
|
||||
### Core Setup (How it works internally)
|
||||
|
||||
```typescript
|
||||
// WooNooW Core
|
||||
window.WooNooW = {
|
||||
React: React,
|
||||
ReactDOM: ReactDOM,
|
||||
components: {
|
||||
Button: Button,
|
||||
Input: Input,
|
||||
Select: Select,
|
||||
},
|
||||
hooks: { addFilter, addAction }
|
||||
};
|
||||
```
|
||||
|
||||
### Addon implementation
|
||||
|
||||
#### Level 1: Vanilla JS (No Build)
|
||||
|
||||
Good for simple injections.
|
||||
|
||||
```javascript
|
||||
(function() {
|
||||
window.addEventListener('woonoow:loaded', function() {
|
||||
window.WooNooW.addFilter('woonoow_order_form_after_shipping', function(container) {
|
||||
// Manual DOM manipulation
|
||||
return container;
|
||||
});
|
||||
});
|
||||
})();
|
||||
```
|
||||
|
||||
#### Level 2: React with Build (Recommended)
|
||||
|
||||
Use `vite` or `webpack` and configure React as an **external**.
|
||||
|
||||
**vite.config.js**
|
||||
```javascript
|
||||
export default {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ['react', 'react-dom'],
|
||||
output: {
|
||||
globals: {
|
||||
react: 'window.WooNooW.React',
|
||||
'react-dom': 'window.WooNooW.ReactDOM'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Index.tsx**
|
||||
```typescript
|
||||
const { React, hooks, components } = window.WooNooW;
|
||||
const { Button } = components;
|
||||
|
||||
function MyAddonComponent() {
|
||||
return <Button>Click Me</Button>;
|
||||
}
|
||||
```
|
||||
143
contents/docs/features/checkout/index.mdx
Normal file
143
contents/docs/features/checkout/index.mdx
Normal file
@@ -0,0 +1,143 @@
|
||||
---
|
||||
title: Checkout
|
||||
description: Streamlined purchasing experience in WooNooW
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The checkout process includes:
|
||||
|
||||
1. **Cart Review** - Verify items before checkout
|
||||
2. **Customer Information** - Billing and shipping details
|
||||
3. **Payment Method** - Select how to pay
|
||||
4. **Order Confirmation** - Complete the purchase
|
||||
|
||||
---
|
||||
|
||||
## Checkout Flow
|
||||
|
||||
### Step 1: Cart
|
||||
|
||||
Before checkout, customers review their cart:
|
||||
- Product list with images
|
||||
- Quantity adjustments
|
||||
- Remove items
|
||||
- Apply coupon codes
|
||||
- See subtotal, shipping, and total
|
||||
|
||||
### Step 2: Customer Details
|
||||
|
||||
Customers provide:
|
||||
- **Email address**
|
||||
- **Billing information**
|
||||
- **Shipping address** (if different from billing)
|
||||
|
||||
> **Note**: Logged-in customers have their details pre-filled.
|
||||
|
||||
### Step 3: Shipping Method
|
||||
|
||||
If physical products are in the cart:
|
||||
- Available shipping methods are shown
|
||||
- Shipping cost is calculated
|
||||
- Customer selects preferred method
|
||||
|
||||
### Step 4: Payment
|
||||
|
||||
Customers choose their payment method:
|
||||
- Credit/Debit Card (Stripe, PayPal, etc.)
|
||||
- Bank Transfer
|
||||
- Cash on Delivery
|
||||
- Other configured gateways
|
||||
|
||||
### Step 5: Place Order
|
||||
|
||||
After reviewing everything:
|
||||
- Click "Place Order"
|
||||
- Payment is processed
|
||||
- Confirmation page is shown
|
||||
- Email receipt is sent
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Guest Checkout
|
||||
|
||||
Allow customers to checkout without creating an account.
|
||||
Configure in **WooCommerce → Settings → Accounts & Privacy**.
|
||||
|
||||
### Coupon Codes
|
||||
|
||||
Customers can apply discount codes:
|
||||
1. Enter code in the coupon field
|
||||
2. Click "Apply"
|
||||
3. Discount is reflected in total
|
||||
|
||||
### Order Notes
|
||||
|
||||
Optional field for customers to add special instructions.
|
||||
|
||||
---
|
||||
|
||||
## Payment Gateways
|
||||
|
||||
### Supported Gateways
|
||||
|
||||
WooNooW supports all WooCommerce payment gateways:
|
||||
|
||||
| Gateway | Type |
|
||||
|---------|------|
|
||||
| Bank Transfer (BACS) | Manual |
|
||||
| Check Payments | Manual |
|
||||
| Cash on Delivery | Manual |
|
||||
| PayPal | Card / PayPal |
|
||||
| Stripe | Card |
|
||||
| Square | Card |
|
||||
|
||||
### Configuring Gateways
|
||||
|
||||
1. Go to **WooNooW → Settings → Payments**
|
||||
2. Enable desired payment methods
|
||||
3. Configure API keys and settings
|
||||
4. Test with sandbox/test mode first
|
||||
|
||||
---
|
||||
|
||||
## After Checkout
|
||||
|
||||
### Order Confirmation Page
|
||||
|
||||
Shows:
|
||||
- Order number
|
||||
- Order summary
|
||||
- Next steps
|
||||
|
||||
### Confirmation Email
|
||||
|
||||
Automatically sent to customer with:
|
||||
- Order details
|
||||
- Payment confirmation
|
||||
- Shipping information (if applicable)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Place Order" Button Not Working
|
||||
|
||||
1. Check all required fields are filled
|
||||
2. Verify payment gateway is properly configured
|
||||
3. Check browser console for JavaScript errors
|
||||
|
||||
### Payment Declined
|
||||
|
||||
1. Customer should verify card details
|
||||
2. Check payment gateway dashboard for error details
|
||||
3. Ensure correct API keys are configured
|
||||
|
||||
### Shipping Not Showing
|
||||
|
||||
1. Verify shipping zones are configured in WooCommerce
|
||||
2. Check if products have weight/dimensions set
|
||||
3. Confirm customer's address is in a configured zone
|
||||
98
contents/docs/features/shop/index.mdx
Normal file
98
contents/docs/features/shop/index.mdx
Normal file
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: Shop Page
|
||||
description: Browsing and filtering your product catalog
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The WooNooW shop page provides:
|
||||
|
||||
- **Product Grid** - Visual display of products
|
||||
- **Search** - Find products by name
|
||||
- **Filters** - Category and sorting options
|
||||
- **Pagination** - Navigate through products
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Product Cards
|
||||
|
||||
Each product displays:
|
||||
- Product image
|
||||
- Product name
|
||||
- Price (with sale price if applicable)
|
||||
- Add to Cart button
|
||||
- Wishlist button (if enabled)
|
||||
|
||||
### Search
|
||||
|
||||
Type in the search box to filter products by name. Search is instant and updates the grid as you type.
|
||||
|
||||
### Category Filter
|
||||
|
||||
Filter products by category using the dropdown. Shows:
|
||||
- All Categories
|
||||
- Individual categories with product count
|
||||
|
||||
### Sorting
|
||||
|
||||
Sort products by:
|
||||
- Default sorting
|
||||
- Popularity
|
||||
- Average rating
|
||||
- Latest
|
||||
- Price: Low to High
|
||||
- Price: High to Low
|
||||
|
||||
---
|
||||
|
||||
## Customization
|
||||
|
||||
### Grid Layout
|
||||
|
||||
Configure the product grid in **WooNooW → Appearance**:
|
||||
|
||||
| Device | Options |
|
||||
|--------|---------|
|
||||
| Mobile | 1-2 columns |
|
||||
| Tablet | 2-4 columns |
|
||||
| Desktop | 2-6 columns |
|
||||
|
||||
### Product Card Style
|
||||
|
||||
Product cards can display:
|
||||
- **Image** - Product featured image
|
||||
- **Title** - Product name
|
||||
- **Price** - Current price and sale price
|
||||
- **Rating** - Star rating (if reviews enabled)
|
||||
- **Add to Cart** - Quick add button
|
||||
|
||||
---
|
||||
|
||||
## Navigation
|
||||
|
||||
### Clicking a Product
|
||||
|
||||
Clicking a product card navigates to the full product page where customers can:
|
||||
- View all images
|
||||
- Select variations
|
||||
- Read description
|
||||
- Add to cart
|
||||
|
||||
### Back to Shop
|
||||
|
||||
From any product page, use the breadcrumb or browser back button to return to the shop.
|
||||
|
||||
---
|
||||
|
||||
## Performance
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
Product images load as they come into view, improving initial page load time.
|
||||
|
||||
### Infinite Scroll vs Pagination
|
||||
|
||||
Currently uses pagination. Infinite scroll may be added in future versions.
|
||||
26
contents/docs/features/shortcodes/index.mdx
Normal file
26
contents/docs/features/shortcodes/index.mdx
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Shortcodes
|
||||
description: Available shortcodes in WooNooW
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## The Primary Shortcode
|
||||
|
||||
WooNooW operates as a Single Page Application (SPA). To render the entire store application, you only need one shortcode:
|
||||
|
||||
### `[woonoow_spa]`
|
||||
|
||||
This shortcode initializes the SPA router and renders the appropriate view based on the URL (Shop, Product, Cart, Checkout, Account).
|
||||
|
||||
**Usage:**
|
||||
Place this shortcode on your designated "Store" page.
|
||||
|
||||
```text
|
||||
[woonoow_spa]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Legacy Shortcodes
|
||||
|
||||
*Note: Previous versions utilize individual shortcodes (`[woonoow_shop]`, etc.). These are now consolidated into the single SPA entry point for better performance and routing state management.*
|
||||
@@ -1,92 +0,0 @@
|
||||
---
|
||||
title: Customize
|
||||
description: This guide provides instructions on customizing our application.
|
||||
date: 29-11-2024
|
||||
---
|
||||
|
||||
## Markdown Options
|
||||
|
||||
To customize Markdown parsing, navigate to `@lib/markdown.ts` and locate the `parseMdx` function. You can add your desired plugins in the `mdxOptions`. Here’s an example:
|
||||
|
||||
```ts:lib/markdown.ts
|
||||
async function parseMdx<Frontmatter>(rawMdx: string) {
|
||||
return await compileMDX<Frontmatter>({
|
||||
source: rawMdx,
|
||||
options: {
|
||||
parseFrontmatter: true,
|
||||
mdxOptions: {
|
||||
// Add your plugins here
|
||||
rehypePlugins: [Shiki],
|
||||
remarkPlugins: [remarkGfm],
|
||||
},
|
||||
},
|
||||
components,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Fonts
|
||||
|
||||
Currently, this project uses the `Geist` font. If you want to use other fonts, you can change the configuration in the main layout as shown below:
|
||||
|
||||
### Google Fonts
|
||||
|
||||
To use a Google font, import your desired font from `next/font/google`, initialize it with options, and apply the variable to the `body`:
|
||||
|
||||
```tsx:app/layout.tsx
|
||||
import { Space_Grotesk } from "next/font/google";
|
||||
|
||||
const fontSans = Space_Grotesk({
|
||||
display: "swap",
|
||||
variable: "--font-regular",
|
||||
weight: "400",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`${fontSans.variable} font-regular`}>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Local Fonts
|
||||
|
||||
To use a local font, you need to use the local font loader from Next.js. Pass the options and apply them to the `body`:
|
||||
|
||||
```tsx:app/layout.tsx
|
||||
import localFont from "next/font/local";
|
||||
|
||||
const geistSans = localFont({
|
||||
src: "./fonts/GeistVF.woff",
|
||||
variable: "--font-regular",
|
||||
weight: "100 900",
|
||||
});
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`${geistSans.variable} font-regular`}>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
For both options, ensure that you add the variable to `tailwind.config.ts`:
|
||||
|
||||
```ts:tailwind.config.ts
|
||||
{
|
||||
// ...
|
||||
extend: {
|
||||
fontFamily: {
|
||||
regular: ["var(--font-regular)"],
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
63
contents/docs/getting-started/development/index.mdx
Normal file
63
contents/docs/getting-started/development/index.mdx
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title : Development
|
||||
description : for Development server and production
|
||||
date : 10-12-2024
|
||||
---
|
||||
|
||||
## Heading 2
|
||||
|
||||
this is regular text written in markdown format with `inline code`, **bold**, and *italic*
|
||||
|
||||
### Heading 3
|
||||
|
||||
example of ordered list format :
|
||||
|
||||
- list one
|
||||
- sub list
|
||||
- list two
|
||||
- list three
|
||||
|
||||
#### Heading 4
|
||||
|
||||
Below is an example of how to write a code block :
|
||||
|
||||
````plaintext
|
||||
```javascript:main.js showLineNumbers {3-4}
|
||||
function isRocketAboutToCrash() {
|
||||
// Check if the rocket is stable
|
||||
if (!isStable()) {
|
||||
NoCrash(); // Prevent the crash
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
example note :
|
||||
```plaintext
|
||||
<Note type="note" title="Note">
|
||||
This is a general note to convey information to the user.
|
||||
</Note>
|
||||
```
|
||||
|
||||
displaying an image in markdown format :
|
||||
|
||||
```plaintext
|
||||

|
||||
```
|
||||
|
||||
render as :
|
||||

|
||||
|
||||
For a complete guide on using markdown content in DocuBook, please refer to the [Components](https://docubook.pro/docs/components) page.
|
||||
|
||||
<Note type="warning" title="Warning">
|
||||
every page that is indexed in a folder will have an `index.mdx` file with metadata :
|
||||
```plaintext
|
||||
---
|
||||
title : Introduction
|
||||
description : overview or synopsis of a project
|
||||
date : 10-12-2024
|
||||
image : example-img.png
|
||||
---
|
||||
```
|
||||
</Note>
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
title: Getting Started
|
||||
description: Set up Your Documentations with DocuBook
|
||||
date: 29-05-2025
|
||||
---
|
||||
|
||||
Welcome to DocuBook! This guide will help you set up and customize your documentation site quickly. Whether you're creating API references, user guides, or technical documentation, these components will help you build a professional and consistent documentation experience. Follow the steps below to get started with DocuBook and make the most of its powerful features.
|
||||
|
||||
<Outlet path="getting-started" />
|
||||
@@ -1,84 +1,94 @@
|
||||
---
|
||||
title: Installation
|
||||
description: Installation guide for our application.
|
||||
date: 17-02-2025
|
||||
title: Installation Guide
|
||||
description: Installing WooNooW on your WordPress site
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
Setting up DocuBook is straightforward, with options to clone the repository or use the convenient `npx` command. DocuBook requires [Node.js](https://nodejs.org/) version 18 or higher for optimal performance.
|
||||
## Requirements
|
||||
|
||||
## Clone Repository
|
||||
Before installing, ensure your site meets these requirements:
|
||||
|
||||
To get started, you can clone the DocuBook repository directly from GitHub.
|
||||
| Requirement | Minimum | Recommended |
|
||||
|-------------|---------|-------------|
|
||||
| WordPress | 6.0+ | Latest |
|
||||
| WooCommerce | 7.0+ | Latest |
|
||||
| PHP | 7.4+ | 8.1+ |
|
||||
| MySQL | 5.7+ | 8.0+ |
|
||||
|
||||
<Stepper>
|
||||
<StepperItem title="Step 1: Clone the DocuBook Repository">
|
||||
Begin by cloning the DocuBook repository from GitHub:
|
||||
## Installation Methods
|
||||
|
||||
```bash
|
||||
git clone --branch main https://github.com/DocuBook/docubook.git
|
||||
```
|
||||
### Method 1: WordPress Admin (Recommended)
|
||||
|
||||
</StepperItem>
|
||||
1. Go to **Plugins → Add New**
|
||||
2. Click **Upload Plugin**
|
||||
3. Select the `woonoow.zip` file
|
||||
4. Click **Install Now**
|
||||
5. Click **Activate**
|
||||
|
||||
<StepperItem title="Step 2: Access the Project Directory">
|
||||
After cloning, navigate into the project directory to start setting up:
|
||||
### Method 2: FTP Upload
|
||||
|
||||
```bash
|
||||
cd docubook
|
||||
```
|
||||
1. Extract `woonoow.zip` to get the `woonoow` folder
|
||||
2. Upload to `/wp-content/plugins/`
|
||||
3. Go to **Plugins → Installed Plugins**
|
||||
4. Find WooNooW and click **Activate**
|
||||
|
||||
</StepperItem>
|
||||
## Post-Installation
|
||||
|
||||
<StepperItem title="Step 3: Install Required Dependencies">
|
||||
Install all necessary project dependencies with npm:
|
||||
After activation, WooNooW automatically:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
### 1. Creates Store Page
|
||||
A new "Store" page is created with the SPA shortcode. This is your main storefront.
|
||||
|
||||
</StepperItem>
|
||||
### 2. Registers Rewrite Rules
|
||||
URL routes like `/store/shop` and `/store/product/...` are registered.
|
||||
|
||||
<StepperItem title="Step 4: Launch the Development Server">
|
||||
Finally, start the development server to view the project locally:
|
||||
> **Note**: If you see 404 errors, go to **Settings → Permalinks** and click **Save Changes** to flush rewrite rules.
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
### 3. Sets Default Configuration
|
||||
Basic appearance settings are configured with sensible defaults.
|
||||
|
||||
</StepperItem>
|
||||
</Stepper>
|
||||
## Verification Checklist
|
||||
|
||||
## Quick Setup with CLI
|
||||
After installation, verify everything works:
|
||||
|
||||
For a faster setup, use the `cli` command to create a new DocuBook project in one step:
|
||||
- [ ] Plugin activated without errors
|
||||
- [ ] WooNooW menu appears in admin sidebar
|
||||
- [ ] Store page exists (check **Pages**)
|
||||
- [ ] `/store` URL loads the SPA
|
||||
- [ ] Products display on shop page
|
||||
|
||||
<Tabs defaultValue="npm" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="npm">npm</TabsTrigger>
|
||||
<TabsTrigger value="pnpm">pnpm</TabsTrigger>
|
||||
<TabsTrigger value="bun">bun</TabsTrigger>
|
||||
<TabsTrigger value="yarn">yarn</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="npm">
|
||||
```shell
|
||||
npx @docubook/create@latest
|
||||
```
|
||||
</TabsContent>
|
||||
<TabsContent value="pnpm">
|
||||
```shell
|
||||
pnpm dlx @docubook/create@latest
|
||||
```
|
||||
</TabsContent>
|
||||
<TabsContent value="bun">
|
||||
```shell
|
||||
bunx @docubook/create@latest
|
||||
```
|
||||
</TabsContent>
|
||||
<TabsContent value="yarn">
|
||||
```shell
|
||||
yarn dlx @docubook/create@latest
|
||||
```
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
## WooCommerce Compatibility
|
||||
|
||||
With this setup, you’ll have a ready-to-use DocuBook instance to start building your documentation.
|
||||
WooNooW works alongside WooCommerce:
|
||||
|
||||
| WooCommerce Page | WooNooW Behavior (Full Mode) |
|
||||
|------------------|------------------------------|
|
||||
| `/shop` | Redirects to `/store/shop` |
|
||||
| `/product/...` | Redirects to `/store/product/...` |
|
||||
| `/cart` | Redirects to `/store/cart` |
|
||||
| `/checkout` | Redirects to `/store/checkout` |
|
||||
| `/my-account` | Redirects to `/store/my-account` |
|
||||
|
||||
When SPA Mode is **Disabled**, WooCommerce pages work normally.
|
||||
|
||||
## Updating
|
||||
|
||||
To update WooNooW:
|
||||
|
||||
1. Download the latest version
|
||||
2. Go to **Plugins → Installed Plugins**
|
||||
3. Deactivate WooNooW (optional but recommended)
|
||||
4. Delete the old version
|
||||
5. Install and activate the new version
|
||||
|
||||
Your settings are preserved in the database.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
To completely remove WooNooW:
|
||||
|
||||
1. Deactivate the plugin (restores WooCommerce page content)
|
||||
2. Delete the plugin
|
||||
3. (Optional) Delete WooNooW options from database
|
||||
|
||||
> **Note**: Deactivating restores original WooCommerce shortcodes to Cart, Checkout, and My Account pages.
|
||||
|
||||
@@ -1,50 +1,39 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: This section provides an overview of DocuBook.
|
||||
date: 29-11-2024
|
||||
image: example-img.png
|
||||
description: Overview of the WooNooW Plugin ecosystem
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
Welcome to **DocuBook**! This template provides a modern, flexible, and user-friendly foundation for creating engaging documentation. Whether you're building a knowledge base, project docs, or a personal blog, DocuBook makes it easy to set up and scale.
|
||||
## What is WooNooW?
|
||||
|
||||
## Open Source Philosophy
|
||||
|
||||
DocuBook is proudly **open-source**! 🎉 We believe in creating an accessible, collaborative platform that thrives on community contributions.
|
||||
|
||||
<Note title="Contribute">
|
||||
Interested in helping us improve? Check out our [GitHub
|
||||
repository](https://github.com/DocuBook/docubook) to get started! From
|
||||
feature suggestions to bug fixes, all contributions are welcome.
|
||||
</Note>
|
||||
|
||||
## Project Overview
|
||||
|
||||
**DocuBook** is more than just a documentation template. It's a **complete toolkit** designed for modern web development. Key features include:
|
||||
|
||||
- **Markdown & MDX Support:** Easily write documentation in Markdown, with the option to include interactive components via MDX.
|
||||
- **Customizable Themes:** Designed with a minimalist ShadCN-inspired theme that’s easy to style.
|
||||
- **SEO-Optimized:** Each page is SEO-ready, ensuring search engines can find and rank your content.
|
||||
- **Interactive Code Blocks:** Beautifully styled, language-specific code blocks for an enhanced reading experience.
|
||||
**WooNooW** is a comprehensive WooCommerce enhancement suite designed to power up your online store. It provides a robust set of tools for license management, subscription handling, and custom checkout flows.
|
||||
|
||||
### Key Features
|
||||
|
||||
| **Feature** | **Description** |
|
||||
| ------------------------------- | ----------------------------------------------------- |
|
||||
| MDX Support | Write interactive documentation with MDX. |
|
||||
| Nested Pages | Organize content in a nested, hierarchical structure. |
|
||||
| Pagination | Split content across multiple pages. |
|
||||
| Syntax Highlighting | Highlight code for better readability. |
|
||||
| Code Line Highlighting & Titles | Highlight specific lines with descriptive titles. |
|
||||
| Interactive Code Blocks | Language-specific and interactive code display. |
|
||||
| Custom Markdown Components | Embed custom, reusable components in your docs. |
|
||||
| Static Site Generation | Generate a static, high-performance site. |
|
||||
| SEO-Optimized | Structured for optimal search engine indexing. |
|
||||
* **License Management**: Sell and manage digital software licenses with ease.
|
||||
* **OAuth Activation**: Secure, user-verified license activation flow.
|
||||
* **Subscription Utilities**: Enhanced subscription notifications and manual renewal controls.
|
||||
* **Developer API**: Full REST API for extending functionality.
|
||||
|
||||
## Technology & Libraries
|
||||
---
|
||||
|
||||
DocuBook leverages cutting-edge technologies to ensure performance and flexibility:
|
||||
## Why use WooNooW?
|
||||
|
||||
- **Next.js 14** - The powerful React framework optimized for production.
|
||||
- **Tailwind CSS** - Utility-first styling for quick, clean designs.
|
||||
- **Shadcn-UI** - Elegant, accessible components for a polished look.
|
||||
- **next-mdx-remote** - Enables MDX support for dynamic, interactive Markdown content.
|
||||
If you are a plugin developer or a digital store owner using WooCommerce, WooNooW simplifies the complex parts of your business logic.
|
||||
|
||||
<CardGroup>
|
||||
<Card title="For Developers" icon="Terminal">
|
||||
Built with extensibility in mind. Use our hooks, filters, and REST API to build custom integrations.
|
||||
</Card>
|
||||
<Card title="For Store Owners" icon="Box">
|
||||
Manage your digital products, verified customers, and subscriptions all in one place.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Getting Help
|
||||
|
||||
Need assistance? Check out our support channels:
|
||||
|
||||
* [Official Support](https://woonoow.com/support)
|
||||
* [Community Forums](https://community.woonoow.com)
|
||||
* [Developer Docs](https://docs.woonoow.com)
|
||||
|
||||
7
contents/docs/getting-started/meta.json
Normal file
7
contents/docs/getting-started/meta.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"pages": [
|
||||
"introduction",
|
||||
"quick-start-guide",
|
||||
"development"
|
||||
]
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
---
|
||||
title: Project Structure
|
||||
description: This section provides an overview of Project Structure.
|
||||
date: 29-11-2024
|
||||
---
|
||||
|
||||
## app
|
||||
|
||||
This folder contains the main application code for Next.js, managing layouts, routing, and specific content pages. It is organized to support both the `docs` sections, with dedicated pages and layouts for each section.
|
||||
|
||||
```
|
||||
app // Main Next.js application folder
|
||||
├── page.tsx // Hero page - the entry point of the app showcasing key content
|
||||
├── layout.tsx // Main layout file, applies global navigation and footer
|
||||
└── docs
|
||||
├── layout.tsx // Documentation layout with sidebar, providing easy navigation across doc pages
|
||||
└── [[...slug]] // Catch-all route to handle nested documentation pages, allowing flexible doc structure
|
||||
```
|
||||
|
||||
## components
|
||||
|
||||
This folder contains all reusable components used throughout the project. It’s structured to categorize components, making it easy to locate and manage UI elements, Markdown customizations, and navigation.
|
||||
|
||||
```
|
||||
components // Reusable components
|
||||
├── ui // ShadCN components, includes standardized UI elements like buttons, forms, and modals
|
||||
├── markdown // Custom Markdown components for rendering rich Markdown content
|
||||
│ ├── CodeBlock.tsx // Component for rendering syntax-highlighted code blocks
|
||||
│ ├── Image.tsx // Component for handling responsive images in Markdown
|
||||
│ └── Table.tsx // Component to render tables with consistent styling
|
||||
└── navbar.tsx // Main navigation component for the site header, managing links and responsive behavior
|
||||
```
|
||||
|
||||
## styles
|
||||
|
||||
This folder contains global and component-specific CSS files, allowing for project-wide styling consistency and customizations.
|
||||
|
||||
```
|
||||
styles // CSS files
|
||||
├── globals.css // Global CSS file, includes Tailwind base, utilities, and custom global styles
|
||||
├── syntax.css // Syntax highlighting styles, providing consistent code block appearance across the site
|
||||
└── overrides.css // Additional custom styles that override specific component or plugin defaults
|
||||
```
|
||||
|
||||
## contents
|
||||
|
||||
This folder stores all Markdown content for the documentation and blog sections, with clear organization by content type. Each Markdown file represents a single piece of content, with frontmatter used for metadata.
|
||||
|
||||
```
|
||||
contents // Markdown content for blogs and documentation
|
||||
├── docs // Documentation content, structured to support nested sections and pages
|
||||
│ ├── getting-started // Main Folder at the Contents
|
||||
│ └─── installation // Subfolder for tutorial-style content
|
||||
| └── index.mdx // Step-by-step tutorial on a specific topic
|
||||
```
|
||||
|
||||
## public
|
||||
|
||||
This folder holds all static assets, such as images, videos, fonts, and icons. These files are directly accessible via URL, so it’s important to avoid sensitive or private content here.
|
||||
|
||||
```
|
||||
public // Publicly accessible assets
|
||||
├── images // Image assets, used across various parts of the app
|
||||
│ ├── og-image.png // Default opengraph image for thumbnail
|
||||
│ └── docu.svg // Your site Logo
|
||||
├── favicon.ico // Favicon for the app
|
||||
└── videos // Video files for media content, if any
|
||||
```
|
||||
|
||||
## lib
|
||||
|
||||
This folder contains helper functions and utilities used across the application, such as Markdown parsing and routing logic. These utilities help keep the codebase clean and organized by separating out common functionality.
|
||||
|
||||
```
|
||||
lib // Utility or helper functions
|
||||
├── changelog.ts // Change log for the app, used to display recent changes and updates
|
||||
├── markdown.ts // Markdown parsing logic, converts Markdown to HTML and adds custom components
|
||||
├── routes-config.ts // Routing configuration for docs, maps URLs to content files for dynamic routing
|
||||
└── utils.tsx // General utility functions used across the app, such as data formatting and validation helpers
|
||||
```
|
||||
|
||||
## Additional
|
||||
|
||||
- **`package.json`**: Contains metadata about the project, dependencies, and scripts for building and running the application.
|
||||
- **`tailwind.config.ts`**: Configures Tailwind CSS, allowing customization of theme colors, fonts, and responsive breakpoints specific to this project.
|
||||
|
||||
This structure organizes your project in a way that supports scalability and maintainability, making it easier to navigate and work on different sections of the application.
|
||||
@@ -1,145 +1,63 @@
|
||||
---
|
||||
title: Quick Start Guide
|
||||
description: Get up and running with DocuBook in minutes with this comprehensive guide
|
||||
date: 20-05-2025
|
||||
title : Quick Start Guide
|
||||
description : a quick way to understand how to use it
|
||||
date : 10-12-2024
|
||||
---
|
||||
|
||||
Welcome to DocuBook! This guide will help you set up and customize your documentation site efficiently.
|
||||
## Heading 2
|
||||
|
||||
## Prerequisites
|
||||
this is regular text written in markdown format with `inline code`, **bold**, and *italic*
|
||||
|
||||
Before we begin, ensure you have the following installed:
|
||||
### Heading 3
|
||||
|
||||
- [Git](https://git-scm.com/)
|
||||
- [Node.js 18+](https://nodejs.org/) or [Bun 1.0+](https://bun.sh/)
|
||||
- A package manager (npm, yarn, or pnpm)
|
||||
example of ordered list format :
|
||||
|
||||
## Installation
|
||||
- list one
|
||||
- sub list
|
||||
- list two
|
||||
- list three
|
||||
|
||||
<Note type="note" title="Initial Setup">
|
||||
Follow the [installation guide](/docs/getting-started/installation) to set up your project dependencies and configuration.
|
||||
#### Heading 4
|
||||
|
||||
Below is an example of how to write a code block :
|
||||
|
||||
````plaintext
|
||||
```javascript:main.js showLineNumbers {3-4}
|
||||
function isRocketAboutToCrash() {
|
||||
// Check if the rocket is stable
|
||||
if (!isStable()) {
|
||||
NoCrash(); // Prevent the crash
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
example note :
|
||||
```plaintext
|
||||
<Note type="note" title="Note">
|
||||
This is a general note to convey information to the user.
|
||||
</Note>
|
||||
```
|
||||
|
||||
## Project Setup
|
||||
|
||||
### Configuration
|
||||
|
||||
<Stepper>
|
||||
<StepperItem title="Add Favicon">
|
||||
Place your favicon at `public/favicon.ico` for browser tab display.
|
||||
</StepperItem>
|
||||
<StepperItem title="Add Logo">
|
||||
Add your logo at `public/images/docu.svg` (SVG format recommended for scalability).
|
||||
</StepperItem>
|
||||
<StepperItem title="Update Site Information">
|
||||
Customize your site's metadata in `docu.json`:
|
||||
- Site title and description
|
||||
- Navigation structure
|
||||
- Default theme settings
|
||||
</StepperItem>
|
||||
</Stepper>
|
||||
|
||||
## Content Management
|
||||
|
||||
### File Structure
|
||||
|
||||
DocuBook organizes content in a hierarchical structure:
|
||||
displaying an image in markdown format :
|
||||
|
||||
```plaintext
|
||||
contents/
|
||||
docs/ # Main documentation directory
|
||||
getting-started/ # Section for getting started guides
|
||||
quick-start-guide/ # Current guide
|
||||
index.mdx # Main content file
|
||||
guides/ # Additional documentation sections
|
||||
components/ # Component-specific documentation
|
||||
index.mdx
|
||||

|
||||
```
|
||||
|
||||
### Creating New Content
|
||||
render as :
|
||||

|
||||
|
||||
<Stepper>
|
||||
<StepperItem title="1. Create Content Directory">
|
||||
Organize your documentation by creating a new directory:
|
||||
```bash
|
||||
mkdir -p contents/docs/your-section/your-topic
|
||||
For a complete guide on using markdown content in DocuBook, please refer to the [Components](https://docubook.pro/docs/components) page.
|
||||
|
||||
<Note type="warning" title="Warning">
|
||||
every page that is indexed in a folder will have an `index.mdx` file with metadata :
|
||||
```plaintext
|
||||
---
|
||||
title : Introduction
|
||||
description : overview or synopsis of a project
|
||||
date : 10-12-2024
|
||||
image : example-img.png
|
||||
---
|
||||
```
|
||||
|
||||
Example for an API reference:
|
||||
```bash
|
||||
mkdir -p contents/docs/api/authentication
|
||||
```
|
||||
</StepperItem>
|
||||
|
||||
<StepperItem title="2. Create MDX Content">
|
||||
Add an `index.mdx` file with frontmatter metadata:
|
||||
````markdown
|
||||
---
|
||||
title: Authentication
|
||||
description: Learn how to implement user authentication
|
||||
date: 2025-05-29
|
||||
---
|
||||
|
||||
Your comprehensive guide to implementing authentication in your application.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Start by setting up your authentication provider...
|
||||
````
|
||||
</StepperItem>
|
||||
|
||||
<StepperItem title="3. Update Navigation">
|
||||
Add your new section to the navigation in `docu.json`. Here's how to add the authentication section we created earlier:
|
||||
|
||||
```json:docu.json showLineNumbers {4-16}
|
||||
{
|
||||
"routes": [
|
||||
// ... existing routes ...
|
||||
{
|
||||
"title": "API",
|
||||
"href": "/api",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Code2",
|
||||
"description": "API Reference and Integration",
|
||||
"title": "API"
|
||||
},
|
||||
"items": [
|
||||
{ "title": "Authentication", "href": "/authentication" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This will add a new "API" section with an "Authentication" page under it. The `context` object defines how this section appears in the navigation, including its icon and description.
|
||||
</StepperItem>
|
||||
</Stepper>
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Local Development
|
||||
|
||||
Start the development server with live reload:
|
||||
|
||||
```bash
|
||||
# Using npm
|
||||
npm run dev
|
||||
|
||||
# Or using Bun
|
||||
bun dev
|
||||
```
|
||||
|
||||
Access your site at [http://localhost:3000](http://localhost:3000)
|
||||
|
||||
### Building for Production
|
||||
|
||||
When ready to deploy:
|
||||
|
||||
```bash
|
||||
# Build the production version
|
||||
npm run build
|
||||
|
||||
# Start the production server
|
||||
npm start
|
||||
```
|
||||
</Note>
|
||||
@@ -1,165 +0,0 @@
|
||||
---
|
||||
title: Coffee
|
||||
description: A warm, minimalistic design inspired by early computing. This theme is a replica of the "Coffee" theme from the `shiki-twoslash` package.
|
||||
date: 2025-05-30
|
||||
---
|
||||
|
||||
## Styles
|
||||
|
||||
<Note type="note" title="note">
|
||||
You can override the default styles by adding your own CSS variables in the `globals.css` and `syntax.css` files.
|
||||
</Note>
|
||||
|
||||
<Tabs defaultValue="globals" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="globals">globals.css</TabsTrigger>
|
||||
<TabsTrigger value="syntax">syntax.css</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="globals">
|
||||
```css:globals.css
|
||||
/* Rich Coffee Theme */
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 35 40% 96%;
|
||||
--foreground: 25 25% 10%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 25 25% 10%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 25 25% 10%;
|
||||
--primary: 25 60% 40%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
--secondary: 35 30% 90%;
|
||||
--secondary-foreground: 25 25% 10%;
|
||||
--muted: 35 20% 94%;
|
||||
--muted-foreground: 25 15% 35%;
|
||||
--accent: 30 50% 38%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 5 85% 45%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 30 15% 85%;
|
||||
--input: 30 15% 88%;
|
||||
--ring: 25 60% 40%;
|
||||
--radius: 0.5rem;
|
||||
--chart-1: 25 60% 45%;
|
||||
--chart-2: 30 55% 45%;
|
||||
--chart-3: 35 50% 42%;
|
||||
--chart-4: 20 45% 38%;
|
||||
--chart-5: 40 45% 40%;
|
||||
--line-number-color: rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 30 10% 6%;
|
||||
--foreground: 35 20% 94%;
|
||||
--card: 30 10% 8%;
|
||||
--card-foreground: 35 20% 94%;
|
||||
--popover: 30 10% 8%;
|
||||
--popover-foreground: 35 20% 94%;
|
||||
--primary: 30 45% 52%;
|
||||
--primary-foreground: 30 10% 6%;
|
||||
--secondary: 30 12% 14%;
|
||||
--secondary-foreground: 35 20% 94%;
|
||||
--muted: 30 10% 16%;
|
||||
--muted-foreground: 30 15% 60%;
|
||||
--accent: 28 40% 48%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 5 80% 55%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 30 10% 20%;
|
||||
--input: 30 10% 20%;
|
||||
--ring: 30 45% 52%;
|
||||
--chart-1: 30 45% 52%;
|
||||
--chart-2: 28 40% 50%;
|
||||
--chart-3: 32 45% 50%;
|
||||
--chart-4: 25 35% 46%;
|
||||
--chart-5: 35 40% 48%;
|
||||
--line-number-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="syntax">
|
||||
```css:syntax.css
|
||||
/* Rich Coffee Theme - Syntax Highlighting */
|
||||
|
||||
/* Light Mode */
|
||||
.keyword {
|
||||
color: hsl(25 60% 35%); /* Rich coffee brown */
|
||||
}
|
||||
|
||||
.function {
|
||||
color: hsl(30 55% 38%); /* Warm coffee brown */
|
||||
}
|
||||
|
||||
.punctuation {
|
||||
color: hsl(30 15% 55%); /* Muted brown */
|
||||
}
|
||||
|
||||
.comment {
|
||||
color: hsl(25 15% 45%); /* Muted brown */
|
||||
font-style: italic;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.string,
|
||||
.constant,
|
||||
.annotation,
|
||||
.boolean,
|
||||
.number {
|
||||
color: hsl(32 50% 40%); /* Warm brown with hint of orange */
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: hsl(25 65% 30%); /* Dark rich coffee */
|
||||
}
|
||||
|
||||
.attr-name {
|
||||
color: hsl(28 55% 38%); /* Warm brown */
|
||||
}
|
||||
|
||||
.attr-value {
|
||||
color: hsl(35 55% 35%); /* Slightly orange brown */
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
.dark .keyword {
|
||||
color: hsl(30 50% 65%); /* Light warm brown */
|
||||
}
|
||||
|
||||
.dark .function {
|
||||
color: hsl(28 55% 68%); /* Light warm brown */
|
||||
}
|
||||
|
||||
.dark .string,
|
||||
.dark .constant,
|
||||
.dark .annotation,
|
||||
.dark .boolean,
|
||||
.dark .number {
|
||||
color: hsl(35 50% 72%); /* Light warm brown with hint of orange */
|
||||
}
|
||||
|
||||
.dark .tag {
|
||||
color: hsl(30 50% 75%); /* Light warm brown */
|
||||
}
|
||||
|
||||
.dark .attr-name {
|
||||
color: hsl(28 45% 70%); /* Light warm brown */
|
||||
}
|
||||
|
||||
.dark .attr-value {
|
||||
color: hsl(35 50% 70%); /* Light warm brown with hint of orange */
|
||||
}
|
||||
|
||||
.dark .comment {
|
||||
color: hsl(30 15% 65%); /* Light brown-gray */
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.dark .punctuation {
|
||||
color: hsl(30 15% 70%); /* Light brown-gray */
|
||||
opacity: 0.9;
|
||||
}
|
||||
```
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
@@ -1,160 +0,0 @@
|
||||
---
|
||||
title: Default Theme
|
||||
description: This page explains the Modern Blue theme colors used in DocuBook, which is a default theme provided by DocuBook.
|
||||
date: 2025-05-20
|
||||
---
|
||||
|
||||
## Styles
|
||||
<Note type="note" title="note">
|
||||
You can override the default styles by adding your own CSS variables in the `globals.css` and `syntax.css` files.
|
||||
</Note>
|
||||
|
||||
<Tabs defaultValue="globals" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="globals">globals.css</TabsTrigger>
|
||||
<TabsTrigger value="syntax">syntax.css</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="globals">
|
||||
```css:globals.css
|
||||
/* Modern Blue Theme */
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 210 40% 98%;
|
||||
--foreground: 220 30% 15%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 220 30% 15%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 220 30% 15%;
|
||||
--primary: 210 81% 56%; /* #2281E3 */
|
||||
--primary-foreground: 0 0% 100%;
|
||||
--secondary: 210 30% 90%;
|
||||
--secondary-foreground: 220 30% 15%;
|
||||
--muted: 210 20% 92%;
|
||||
--muted-foreground: 220 15% 50%;
|
||||
--accent: 200 100% 40%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 0 85% 60%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 210 20% 85%;
|
||||
--input: 210 20% 85%;
|
||||
--ring: 210 81% 56%;
|
||||
--radius: 0.5rem;
|
||||
--chart-1: 210 81% 56%;
|
||||
--chart-2: 200 100% 40%;
|
||||
--chart-3: 220 76% 60%;
|
||||
--chart-4: 190 90% 50%;
|
||||
--chart-5: 230 86% 45%;
|
||||
--line-number-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 220 25% 10%;
|
||||
--foreground: 210 30% 96%;
|
||||
--card: 220 25% 15%;
|
||||
--card-foreground: 210 30% 96%;
|
||||
--popover: 220 25% 15%;
|
||||
--popover-foreground: 210 30% 96%;
|
||||
--primary: 210 100% 65%;
|
||||
--primary-foreground: 220 25% 10%;
|
||||
--secondary: 215 25% 20%;
|
||||
--secondary-foreground: 210 30% 96%;
|
||||
--muted: 215 20% 25%;
|
||||
--muted-foreground: 215 20% 65%;
|
||||
--accent: 200 100% 60%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 0 85% 70%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 215 20% 25%;
|
||||
--input: 215 20% 25%;
|
||||
--ring: 210 100% 65%;
|
||||
--chart-1: 210 100% 65%;
|
||||
--chart-2: 200 100% 60%;
|
||||
--chart-3: 220 90% 70%;
|
||||
--chart-4: 190 100% 65%;
|
||||
--chart-5: 230 90% 60%;
|
||||
--line-number-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="syntax">
|
||||
```css:syntax.css
|
||||
/* Modern Blue Theme */
|
||||
/* Light Mode */
|
||||
.keyword {
|
||||
color: #1d4ed8; /* Darker blue for better contrast */
|
||||
}
|
||||
|
||||
.function {
|
||||
color: #0369a1; /* Deep blue */
|
||||
}
|
||||
|
||||
.punctuation {
|
||||
color: #4b5563; /* Slate gray */
|
||||
}
|
||||
|
||||
.comment {
|
||||
color: #6b7280; /* Muted gray */
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.string,
|
||||
.constant,
|
||||
.annotation,
|
||||
.boolean,
|
||||
.number {
|
||||
color: #0d9488; /* Teal for better distinction */
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: #1d4ed8; /* Matching keyword color */
|
||||
}
|
||||
|
||||
.attr-name {
|
||||
color: #0284c7; /* Sky blue */
|
||||
}
|
||||
|
||||
.attr-value {
|
||||
color: #2563eb; /* Primary blue */
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
.dark .keyword {
|
||||
color: #60a5fa; /* Soft blue */
|
||||
}
|
||||
|
||||
.dark .function {
|
||||
color: #38bdf8; /* Sky blue */
|
||||
}
|
||||
|
||||
.dark .string,
|
||||
.dark .constant,
|
||||
.dark .annotation,
|
||||
.dark .boolean,
|
||||
.dark .number {
|
||||
color: #2dd4bf; /* Teal */
|
||||
}
|
||||
|
||||
.dark .tag {
|
||||
color: #60a5fa; /* Matching keyword color */
|
||||
}
|
||||
|
||||
.dark .attr-name {
|
||||
color: #7dd3fc; /* Lighter blue */
|
||||
}
|
||||
|
||||
.dark .attr-value {
|
||||
color: #3b82f6; /* Brighter blue */
|
||||
}
|
||||
|
||||
.dark .comment {
|
||||
color: #9ca3af; /* Lighter gray for dark mode */
|
||||
}
|
||||
|
||||
.dark .punctuation {
|
||||
color: #9ca3af; /* Lighter gray for dark mode */
|
||||
}
|
||||
```
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
@@ -1,161 +0,0 @@
|
||||
---
|
||||
title: Fresh Lime
|
||||
description: A fresh and vibrant freshlime-themed color scheme that's easy on the eyes while maintaining excellent readability.
|
||||
date: 2025-05-30
|
||||
---
|
||||
|
||||
## Styles
|
||||
<Note type="note" title="note">
|
||||
You can override the default styles by adding your own CSS variables in the `globals.css` and `syntax.css` files.
|
||||
</Note>
|
||||
|
||||
<Tabs defaultValue="globals" className="pt-5 pb-1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="globals">globals.css</TabsTrigger>
|
||||
<TabsTrigger value="syntax">syntax.css</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="globals">
|
||||
```css:globals.css
|
||||
/* Fresh Lime Theme */
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 85 45% 98%;
|
||||
--foreground: 85 30% 10%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 85 30% 10%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 85 30% 10%;
|
||||
--primary: 85 70% 45%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
--secondary: 85 40% 90%;
|
||||
--secondary-foreground: 85 30% 10%;
|
||||
--muted: 85 30% 92%;
|
||||
--muted-foreground: 85 15% 45%;
|
||||
--accent: 85 60% 40%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 0 85% 60%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 85 25% 88%;
|
||||
--input: 85 25% 88%;
|
||||
--ring: 85 70% 45%;
|
||||
--radius: 0.5rem;
|
||||
--chart-1: 85 70% 45%;
|
||||
--chart-2: 85 60% 40%;
|
||||
--chart-3: 85 80% 40%;
|
||||
--chart-4: 85 85% 35%;
|
||||
--chart-5: 85 90% 30%;
|
||||
--line-number-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 85 20% 8%;
|
||||
--foreground: 85 30% 96%;
|
||||
--card: 85 20% 10%;
|
||||
--card-foreground: 85 30% 96%;
|
||||
--popover: 85 20% 10%;
|
||||
--popover-foreground: 85 30% 96%;
|
||||
--primary: 85 75% 55%;
|
||||
--primary-foreground: 85 20% 8%;
|
||||
--secondary: 85 25% 18%;
|
||||
--secondary-foreground: 85 30% 96%;
|
||||
--muted: 85 20% 20%;
|
||||
--muted-foreground: 85 20% 70%;
|
||||
--accent: 85 70% 50%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 0 85% 65%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 85 25% 22%;
|
||||
--input: 85 25% 22%;
|
||||
--ring: 85 75% 55%;
|
||||
--chart-1: 85 75% 55%;
|
||||
--chart-2: 85 70% 50%;
|
||||
--chart-3: 85 80% 45%;
|
||||
--chart-4: 85 85% 40%;
|
||||
--chart-5: 85 90% 35%;
|
||||
--line-number-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
```
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="syntax">
|
||||
```css:syntax.css
|
||||
/* Fresh Lime Theme - Syntax Highlighting */
|
||||
|
||||
/* Light Mode */
|
||||
.keyword {
|
||||
color: hsl(85 70% 30%); /* Dark lime green */
|
||||
}
|
||||
|
||||
.function {
|
||||
color: hsl(85 65% 35%); /* Slightly lighter lime */
|
||||
}
|
||||
|
||||
.punctuation {
|
||||
color: hsl(85 15% 50%); /* Muted green-gray */
|
||||
}
|
||||
|
||||
.comment {
|
||||
color: hsl(85 15% 50%); /* Muted green-gray */
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.string,
|
||||
.constant,
|
||||
.annotation,
|
||||
.boolean,
|
||||
.number {
|
||||
color: hsl(85 50% 35%); /* Medium lime green */
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: hsl(85 70% 25%); /* Darker lime */
|
||||
}
|
||||
|
||||
.attr-name {
|
||||
color: hsl(85 60% 35%); /* Lime green */
|
||||
}
|
||||
|
||||
.attr-value {
|
||||
color: hsl(85 70% 30%); /* Dark lime green */
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
.dark .keyword {
|
||||
color: hsl(85 75% 65%); /* Bright lime */
|
||||
}
|
||||
|
||||
.dark .function {
|
||||
color: hsl(85 75% 60%); /* Slightly less bright lime */
|
||||
}
|
||||
|
||||
.dark .string,
|
||||
.dark .constant,
|
||||
.dark .annotation,
|
||||
.dark .boolean,
|
||||
.dark .number {
|
||||
color: hsl(85 60% 70%); /* Light lime */
|
||||
}
|
||||
|
||||
.dark .tag {
|
||||
color: hsl(85 70% 70%); /* Bright lime */
|
||||
}
|
||||
|
||||
.dark .attr-name {
|
||||
color: hsl(85 65% 70%); /* Light lime */
|
||||
}
|
||||
|
||||
.dark .attr-value {
|
||||
color: hsl(85 75% 65%); /* Bright lime */
|
||||
}
|
||||
|
||||
.dark .comment {
|
||||
color: hsl(85 15% 60%); /* Light gray-green */
|
||||
}
|
||||
|
||||
.dark .punctuation {
|
||||
color: hsl(85 20% 70%); /* Light gray-green */
|
||||
}
|
||||
```
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
title : Theme Colors
|
||||
description : Color system used in DocuBook for styling UI elements
|
||||
date : 2025-05-20
|
||||
---
|
||||
|
||||
DocuBook comes with a carefully designed color system that ensures consistency and accessibility across your documentation. The theme includes both light and dark modes, automatically adapting to the user's system preferences.
|
||||
|
||||
<Outlet path="getting-started/theme-colors" />
|
||||
@@ -1,77 +0,0 @@
|
||||
---
|
||||
title: Llms.txt - Generate Custom Theme
|
||||
description: Complete guide for creating and using AI-generated custom themes based on LLMS context.
|
||||
date: 2025-05-31
|
||||
---
|
||||
|
||||
## Introduction
|
||||
This document explains how to create and implement custom color themes using AI with LLMS context. The context includes a consistent color palette for both light and dark modes, along with syntax highlighting colors for code.
|
||||
|
||||
## File Structure
|
||||
<Files>
|
||||
<Folder name="styles">
|
||||
<File name="globals.css" />
|
||||
<File name="syntax.css" />
|
||||
</Folder>
|
||||
</Files>
|
||||
|
||||
## Generate New Theme
|
||||
|
||||
<Stepper>
|
||||
<StepperItem title="Step 1: Access LLM for Color Generation">
|
||||
Ensure you have access to a language model (LLM) that supports color palette generation
|
||||
</StepperItem>
|
||||
<StepperItem title="Step 2: Prepare Color Context">
|
||||
Share the content of the [llms.txt](/llms.txt) file with the AI to provide the current color scheme context.
|
||||
</StepperItem>
|
||||
<StepperItem title="Step 3: Define Color Requirements">
|
||||
Determine your preferred color scheme or theme requirements
|
||||
</StepperItem>
|
||||
<StepperItem title="Step 4: Generate New Theme">
|
||||
Use the following prompt to request a new theme from the AI:
|
||||
|
||||
```markdown
|
||||
Create a new color theme based on the provided context with the following requirements:
|
||||
1. Different primary color #2281E3
|
||||
2. Maintain good contrast for accessibility
|
||||
3. Include variants for both light and dark modes
|
||||
4. Keep the same structure as the provided context
|
||||
```
|
||||
<Note type="danger" title="Colors example">
|
||||
changes the value of Hex color `#2281E3` into your brand colors.
|
||||
</Note>
|
||||
</StepperItem>
|
||||
</Stepper>
|
||||
|
||||
## Implementation
|
||||
After receiving the new color palette:
|
||||
|
||||
1. Copy the generated CSS code to your theme file
|
||||
2. Update CSS variables in `globals.css`
|
||||
3. Adjust syntax colors in `syntax.css` if needed
|
||||
4. Test the theme across different devices and display modes
|
||||
|
||||
## Example Implementation
|
||||
```css
|
||||
:root {
|
||||
--primary: 210 81% 56%; /* Primary color */
|
||||
--secondary: 210 30% 90%; /* Secondary color */
|
||||
/* ... and so on */
|
||||
}
|
||||
|
||||
.dark {
|
||||
--primary: 210 100% 65%; /* Dark mode primary color */
|
||||
/* ... and so on */
|
||||
}
|
||||
```
|
||||
|
||||
## Tips and Recommendations
|
||||
- Always test color contrast to ensure accessibility
|
||||
- Maintain consistency with existing themes
|
||||
- Use tools like [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/) to verify contrast ratios
|
||||
- Keep backups of previous theme versions before making major changes
|
||||
|
||||
## Troubleshooting
|
||||
- If colors don't change, ensure CSS variables are properly imported
|
||||
- Check CSS selector specificity if styles conflict
|
||||
- Verify dark/light mode toggling is working correctly
|
||||
21
contents/docs/hooks/frontend/index.mdx
Normal file
21
contents/docs/hooks/frontend/index.mdx
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Frontend Hooks
|
||||
description: Hooks affecting the storefront and checkout experience
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Filters
|
||||
|
||||
### woonoow_ssr_cache_ttl
|
||||
|
||||
Customize the Time-To-Live (TTL) for Server Side Rendered fragments.
|
||||
|
||||
**Parameters:**
|
||||
* `$ttl` (int): Time in seconds (Default: 3600).
|
||||
|
||||
### woonoow_standard_checkout_field_keys
|
||||
|
||||
Modify the standard set of checkout fields recognized by the system.
|
||||
|
||||
**Parameters:**
|
||||
* `$keys` (array): List of field aliases (e.g., ['billing_first_name', ...]).
|
||||
27
contents/docs/hooks/index.mdx
Normal file
27
contents/docs/hooks/index.mdx
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Hooks Overview
|
||||
description: Overview of Actions and Filters available in WooNooW
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
WooNooW provides a rich set of actions and filters allowing developers to customize almost every aspect of the plugin without modifying core files.
|
||||
|
||||
### Hook Categories
|
||||
|
||||
* [Notifications](/docs/hooks/notifications) - Customize email templates, subjects, and channels.
|
||||
* [Subscriptions](/docs/hooks/subscriptions) - Intercept payment logic and modify gateway behavior.
|
||||
* [Frontend & checkout](/docs/hooks/frontend) - Adjust checkout fields and SSR caching.
|
||||
* [Newsletter](/docs/hooks/newsletter) - Subscribe/unsubscribe events.
|
||||
|
||||
### Usage Example
|
||||
|
||||
```php
|
||||
add_filter('woonoow_email_default_subject', function($subject, $recipient, $event) {
|
||||
if ($event === 'subscription_renewal') {
|
||||
return 'Your subscription is renewing soon!';
|
||||
}
|
||||
return $subject;
|
||||
}, 10, 3);
|
||||
```
|
||||
9
contents/docs/hooks/meta.json
Normal file
9
contents/docs/hooks/meta.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"pages": [
|
||||
"index",
|
||||
"notifications",
|
||||
"subscriptions",
|
||||
"frontend",
|
||||
"newsletter"
|
||||
]
|
||||
}
|
||||
21
contents/docs/hooks/newsletter/index.mdx
Normal file
21
contents/docs/hooks/newsletter/index.mdx
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Newsletter Hooks
|
||||
description: Hooks related to the Newsletter module
|
||||
---
|
||||
|
||||
## Actions
|
||||
|
||||
### woonoow_newsletter_subscribed
|
||||
|
||||
Triggered when a user subscribes to the newsletter.
|
||||
|
||||
**Parameters:**
|
||||
* `$email` (string): The subscriber's email address.
|
||||
* `$user_id` (int|null): The user ID if logged in, or null.
|
||||
|
||||
### woonoow_newsletter_unsubscribed
|
||||
|
||||
Triggered when a user unsubscribes from the newsletter.
|
||||
|
||||
**Parameters:**
|
||||
* `$email` (string): The subscriber's email address.
|
||||
108
contents/docs/hooks/notifications/index.mdx
Normal file
108
contents/docs/hooks/notifications/index.mdx
Normal file
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: Notifications Hooks
|
||||
description: Hooks related to email and push notifications
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Filters
|
||||
|
||||
### woonoow_email_default_templates
|
||||
|
||||
Modify the list of available email templates.
|
||||
|
||||
**Parameters:**
|
||||
* `$templates` (array): Associative array of template paths.
|
||||
|
||||
### woonoow_email_default_subject
|
||||
|
||||
Customize the default subject line for emails.
|
||||
|
||||
**Parameters:**
|
||||
* `$subject` (string): The default subject.
|
||||
* `$recipient` (string): The recipient type (e.g., 'customer', 'admin').
|
||||
* `$event` (string): The event triggering the email.
|
||||
|
||||
### woonoow_notification_channels
|
||||
|
||||
Register or modify available notification channels.
|
||||
|
||||
**Parameters:**
|
||||
* `$channels` (array): list of channels.
|
||||
|
||||
### woonoow_email_variables
|
||||
|
||||
Add custom variables to be replaced in email templates.
|
||||
|
||||
**Parameters:**
|
||||
* `$variables` (array): Key-value pairs of variables.
|
||||
* `$event_id` (string): The current event ID.
|
||||
* `$data` (array): Function context data.
|
||||
|
||||
### woonoow_email_template
|
||||
|
||||
Override the resolved template path for an email.
|
||||
|
||||
**Parameters:**
|
||||
* `$template_path` (string): Absolute path to the template file.
|
||||
|
||||
---
|
||||
|
||||
## Actions
|
||||
|
||||
### woonoow_email_sent
|
||||
|
||||
Triggered after an email is successfully sent.
|
||||
|
||||
**Parameters:**
|
||||
* `$event_id` (string): The event ID.
|
||||
* `$recipient_type` (string): Type of recipient.
|
||||
* `$email` (string): The email address it was sent to.
|
||||
|
||||
### woonoow_send_push_notification
|
||||
|
||||
Triggered when the system determines a push notification should be sent.
|
||||
|
||||
**Parameters:**
|
||||
* `$event_id` (string): The event ID.
|
||||
* `$recipient` (object): The recipient user object.
|
||||
* `$data` (array): Payload data.
|
||||
* `$recipient_type` (string): Type of recipient.
|
||||
* `$email` (string): The email address it was sent to.
|
||||
|
||||
### woonoow_send_push_notification
|
||||
|
||||
Triggered to send a push notification.
|
||||
|
||||
**Parameters:**
|
||||
* `$event_id` (string): The event key.
|
||||
* `$recipient` (WP_User): The recipient user object.
|
||||
* `$data` (array): Notification payload data.
|
||||
|
||||
### woonoow_notification_events_registry
|
||||
|
||||
Filter to register custom notification events.
|
||||
|
||||
**Parameters:**
|
||||
* `$events` (array): The array of registered events.
|
||||
|
||||
**Example:**
|
||||
```php
|
||||
add_filter('woonoow_notification_events_registry', function($events) {
|
||||
$events['my_custom_event'] = [
|
||||
'title' => 'My Custom Event',
|
||||
'description' => 'Triggered when something happens',
|
||||
'recipient' => 'customer',
|
||||
];
|
||||
return $events;
|
||||
});
|
||||
```
|
||||
|
||||
### woonoow_notification_event_updated
|
||||
|
||||
Triggered when a notification event's settings are updated via API.
|
||||
|
||||
**Parameters:**
|
||||
* `$event_id` (string): The event key.
|
||||
* `$channel_id` (string): The channel (email/push).
|
||||
* `$enabled` (bool): New status.
|
||||
* `$recipient` (string): Recipient type.
|
||||
26
contents/docs/hooks/subscriptions/index.mdx
Normal file
26
contents/docs/hooks/subscriptions/index.mdx
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Subscription Hooks
|
||||
description: Hooks for customizing subscription flows and payments
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Filters
|
||||
|
||||
### woonoow_pre_process_subscription_payment
|
||||
|
||||
Intercept the subscription payment process before it begins.
|
||||
|
||||
**Parameters:**
|
||||
* `$result` (null|mixed): Return non-null to short-circuit the process.
|
||||
* `$subscription` (WC_Subscription): The subscription object.
|
||||
* `$order` (WC_Order): The renewal order.
|
||||
|
||||
### woonoow_process_subscription_payment
|
||||
|
||||
Modify or handle the payment processing via a custom gateway logic.
|
||||
|
||||
**Parameters:**
|
||||
* `$result` (null|bool): The result of the payment.
|
||||
* `$gateway` (object): The payment gateway instance.
|
||||
* `$order` (WC_Order): The order being paid.
|
||||
* `$subscription` (WC_Subscription): The subscription object.
|
||||
5
contents/docs/licensing/meta.json
Normal file
5
contents/docs/licensing/meta.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"pages": [
|
||||
"oauth-flow"
|
||||
]
|
||||
}
|
||||
114
contents/docs/licensing/oauth-flow/index.mdx
Normal file
114
contents/docs/licensing/oauth-flow/index.mdx
Normal file
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: OAuth Activation Flow
|
||||
description: Implementation guide for secure user-verified license activation
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Secure OAuth Activation flow ensures that licenses are only activated by their legitimate owners. Unlike simple API activation, this method requires the user to log in to the WooNooW portal and explicitly authorize the activation request.
|
||||
|
||||
### When to use OAuth?
|
||||
|
||||
* ✅ When you want strict control over license usage
|
||||
* ✅ To prevent license key sharing (key + auth required)
|
||||
* ✅ If specific user consent is legally required
|
||||
|
||||
---
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
The flow involves three parties:
|
||||
1. **Client Application**: The software requesting activation (e.g., a customer's WordPress site)
|
||||
2. **Vendor Portal**: The WooNooW dashboard where the user manages licenses
|
||||
3. **Vendor API**: The backend handling the activation logic
|
||||
|
||||
<Stepper>
|
||||
<StepperItem title="Step 1: Client Requests Activation">
|
||||
The client sends a request to the activation API with `activation_mode: "oauth"`.
|
||||
|
||||
```bash
|
||||
POST /woonoow/v1/licenses/activate
|
||||
{
|
||||
"license_key": "XXXX-YYYY-ZZZZ-WWWW",
|
||||
"domain": "https://client-site.com",
|
||||
"activation_mode": "oauth"
|
||||
}
|
||||
```
|
||||
</StepperItem>
|
||||
|
||||
<StepperItem title="Step 2: API Request Authorization">
|
||||
The API responds with `oauth_required: true` and a redirect URL.
|
||||
|
||||
```json
|
||||
{
|
||||
"oauth_required": true,
|
||||
"oauth_redirect": "https://woonoow.com/my-account/license-connect/...",
|
||||
"state": "abc12345"
|
||||
}
|
||||
```
|
||||
</StepperItem>
|
||||
|
||||
<StepperItem title="Step 3: User Authorizes Request">
|
||||
The client redirects the user to the `oauth_redirect` URL. The user logs in and sees a confirmation screen:
|
||||
|
||||
> **Authorize this Request?**
|
||||
> Site: https://client-site.com
|
||||
> License: XXXX-YYYY-ZZZZ-WWWW
|
||||
|
||||
Once confirmed, the vendor generates a temporary **activation token**.
|
||||
</StepperItem>
|
||||
|
||||
<StepperItem title="Step 4: Token Exchange">
|
||||
The user is redirected back to the client site with the token. The client exchanges this token for the final activation.
|
||||
|
||||
```bash
|
||||
POST /woonoow/v1/licenses/activate
|
||||
{
|
||||
"activation_token": "temporary-token-123"
|
||||
}
|
||||
```
|
||||
</StepperItem>
|
||||
</Stepper>
|
||||
|
||||
---
|
||||
|
||||
## Implementation Guide
|
||||
|
||||
### 1. Handling the Redirect
|
||||
|
||||
When your application receives the `oauth_redirect` response, you must open this URL in the user's browser.
|
||||
|
||||
<Note type="note" title="Security Check">
|
||||
Always verify the `state` parameter when the user returns to your application to prevent CSRF attacks.
|
||||
</Note>
|
||||
|
||||
### 2. Processing the Callback
|
||||
|
||||
Your application needs a callback route (e.g., `/admin.php?page=my-plugin&action=callback`). This URL must be provided in the initial `return_url` parameter.
|
||||
|
||||
The callback will receive:
|
||||
* `activation_token`: The token needed to complete activation
|
||||
* `license_key`: The license key being activated
|
||||
* `nonce`: Random standard nonce for verification
|
||||
|
||||
### 3. Completing Activation
|
||||
|
||||
Once you have the `activation_token`, compare the `state` (if you stored it) and make the final request.
|
||||
|
||||
```javascript
|
||||
const response = await fetch('https://api.woonoow.com/woonoow/v1/licenses/activate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
license_key: licenseKey,
|
||||
activation_token: urlParams.get('activation_token')
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
console.log('License Activated!', data);
|
||||
}
|
||||
```
|
||||
9
contents/docs/meta.json
Normal file
9
contents/docs/meta.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"pages": [
|
||||
"getting-started",
|
||||
"licensing",
|
||||
"hooks",
|
||||
"api-reference",
|
||||
"changelog"
|
||||
]
|
||||
}
|
||||
114
contents/docs/resources/faq/index.mdx
Normal file
114
contents/docs/resources/faq/index.mdx
Normal file
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: Frequently Asked Questions
|
||||
description: Quick answers to common questions about WooNooW
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## General
|
||||
|
||||
### What is WooNooW?
|
||||
|
||||
WooNooW is a WooCommerce plugin that transforms your store into a modern Single Page Application (SPA). It provides instant page loads, a beautiful UI, and seamless shopping experience.
|
||||
|
||||
### Do I need WooCommerce?
|
||||
|
||||
Yes. WooNooW is an enhancement layer for WooCommerce. You need WooCommerce installed and activated.
|
||||
|
||||
### Will WooNooW affect my existing products?
|
||||
|
||||
No. WooNooW reads from WooCommerce. Your products, orders, and settings remain untouched.
|
||||
|
||||
---
|
||||
|
||||
## SPA Mode
|
||||
|
||||
### What's the difference between Full and Disabled mode?
|
||||
|
||||
| Mode | Behavior |
|
||||
|------|----------|
|
||||
| **Full** | All WooCommerce pages redirect to SPA. Modern, fast experience. |
|
||||
| **Disabled** | WooCommerce pages use native templates. WooNooW admin still works. |
|
||||
|
||||
### Can I switch modes anytime?
|
||||
|
||||
Yes. Go to **WooNooW → Appearance → General** and change the SPA Mode. Changes take effect immediately.
|
||||
|
||||
### Which mode should I use?
|
||||
|
||||
- **Full**: For the best customer experience with instant loads
|
||||
- **Disabled**: If you have theme customizations you want to keep
|
||||
|
||||
---
|
||||
|
||||
## Compatibility
|
||||
|
||||
### Does WooNooW work with my theme?
|
||||
|
||||
WooNooW's SPA is independent of your WordPress theme. In Full mode, the SPA uses its own styling. Your theme affects the rest of your site normally.
|
||||
|
||||
### Does WooNooW work with page builders?
|
||||
|
||||
The SPA pages are self-contained. Page builders work on other pages of your site.
|
||||
|
||||
### Which payment gateways are supported?
|
||||
|
||||
WooNooW supports all WooCommerce-compatible payment gateways:
|
||||
- PayPal
|
||||
- Stripe
|
||||
- Bank Transfer (BACS)
|
||||
- Cash on Delivery
|
||||
- And more...
|
||||
|
||||
---
|
||||
|
||||
## SEO
|
||||
|
||||
### Is WooNooW SEO-friendly?
|
||||
|
||||
Yes. WooNooW uses:
|
||||
- Clean URLs (`/store/product/product-name`)
|
||||
- Dynamic meta tags for social sharing
|
||||
- Proper redirects (302) from WooCommerce URLs
|
||||
|
||||
### What about my existing SEO?
|
||||
|
||||
WooCommerce URLs remain the indexed source. WooNooW redirects users to the SPA but preserves SEO value.
|
||||
|
||||
### Will my product pages be indexed?
|
||||
|
||||
Yes. Search engines index the WooCommerce URLs. When users click from search results, they're redirected to the fast SPA experience.
|
||||
|
||||
---
|
||||
|
||||
## Performance
|
||||
|
||||
### Is WooNooW faster than regular WooCommerce?
|
||||
|
||||
Yes, for navigation. After the initial load, page transitions are instant because the SPA doesn't reload the entire page.
|
||||
|
||||
### Will WooNooW slow down my site?
|
||||
|
||||
The initial load is similar to regular WooCommerce. Subsequent navigation is much faster.
|
||||
|
||||
### Does WooNooW work with caching?
|
||||
|
||||
Yes. Use page caching and object caching for best results.
|
||||
|
||||
---
|
||||
|
||||
## Customization
|
||||
|
||||
### Can I customize colors and fonts?
|
||||
|
||||
Yes. Go to **WooNooW → Appearance** to customize:
|
||||
- Primary, secondary, and accent colors
|
||||
- Body and heading fonts
|
||||
- Logo and layout options
|
||||
|
||||
### Can I add custom CSS?
|
||||
|
||||
Currently, use your theme's Additional CSS feature. A custom CSS field may be added in future versions.
|
||||
|
||||
### Can I modify the SPA templates?
|
||||
|
||||
The SPA is built with React. Advanced customizations require development knowledge.
|
||||
175
contents/docs/resources/troubleshooting/index.mdx
Normal file
175
contents/docs/resources/troubleshooting/index.mdx
Normal file
@@ -0,0 +1,175 @@
|
||||
---
|
||||
title: Troubleshooting
|
||||
description: Common issues and their solutions
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Blank Pages
|
||||
|
||||
### Symptom
|
||||
WooCommerce pages (shop, cart, checkout) show blank content.
|
||||
|
||||
### Solutions
|
||||
|
||||
**1. Check SPA Mode Setting**
|
||||
- Go to **WooNooW → Appearance → General**
|
||||
- Ensure **SPA Mode** is set to "Full"
|
||||
- If you want native WooCommerce, set to "Disabled"
|
||||
|
||||
**2. Flush Permalinks**
|
||||
- Go to **Settings → Permalinks**
|
||||
- Click **Save Changes** (no changes needed)
|
||||
- This refreshes rewrite rules
|
||||
|
||||
**3. Clear Cache**
|
||||
If using a caching plugin:
|
||||
- Clear page cache
|
||||
- Clear object cache
|
||||
- Purge CDN cache (if applicable)
|
||||
|
||||
---
|
||||
|
||||
## 404 Errors on SPA Routes
|
||||
|
||||
### Symptom
|
||||
Visiting `/store/shop` or `/store/product/...` shows a 404 error.
|
||||
|
||||
### Solutions
|
||||
|
||||
**1. Flush Permalinks**
|
||||
- Go to **Settings → Permalinks**
|
||||
- Click **Save Changes**
|
||||
|
||||
**2. Check Store Page Exists**
|
||||
- Go to **Pages**
|
||||
- Verify "Store" page exists and is published
|
||||
- The page should contain `[woonoow_spa]` shortcode
|
||||
|
||||
**3. Check SPA Page Setting**
|
||||
- Go to **WooNooW → Appearance → General**
|
||||
- Ensure **SPA Page** is set to the Store page
|
||||
|
||||
---
|
||||
|
||||
## Product Images Not Loading
|
||||
|
||||
### Symptom
|
||||
Products show placeholder images instead of actual images.
|
||||
|
||||
### Solutions
|
||||
|
||||
**1. Regenerate Thumbnails**
|
||||
- Install "Regenerate Thumbnails" plugin
|
||||
- Run regeneration for all images
|
||||
|
||||
**2. Check Image URLs**
|
||||
- Ensure images have valid URLs
|
||||
- Check for mixed content (HTTP vs HTTPS)
|
||||
|
||||
---
|
||||
|
||||
## Slow Performance
|
||||
|
||||
### Symptom
|
||||
SPA feels slow or laggy.
|
||||
|
||||
### Solutions
|
||||
|
||||
**1. Enable Caching**
|
||||
- Install a caching plugin (WP Super Cache, W3 Total Cache)
|
||||
- Enable object caching (Redis/Memcached)
|
||||
|
||||
**2. Optimize Images**
|
||||
- Use WebP format
|
||||
- Compress images before upload
|
||||
- Use lazy loading
|
||||
|
||||
**3. Check Server Resources**
|
||||
- Upgrade hosting if on shared hosting
|
||||
- Consider VPS or managed WordPress hosting
|
||||
|
||||
---
|
||||
|
||||
## Checkout Not Working
|
||||
|
||||
### Symptom
|
||||
Checkout page won't load or payment fails.
|
||||
|
||||
### Solutions
|
||||
|
||||
**1. Check Payment Gateway**
|
||||
- Go to **WooCommerce → Settings → Payments**
|
||||
- Verify payment method is enabled
|
||||
- Check API credentials
|
||||
|
||||
**2. Check SSL Certificate**
|
||||
- Checkout requires HTTPS
|
||||
- Verify SSL is properly installed
|
||||
|
||||
**3. Check for JavaScript Errors**
|
||||
- Open browser Developer Tools (F12)
|
||||
- Check Console for errors
|
||||
- Look for blocked scripts
|
||||
|
||||
---
|
||||
|
||||
## Emails Not Sending
|
||||
|
||||
### Symptom
|
||||
Order confirmation emails not being received.
|
||||
|
||||
### Solutions
|
||||
|
||||
**1. Check Email Settings**
|
||||
- Go to **WooNooW → Settings → Notifications**
|
||||
- Verify email types are enabled
|
||||
|
||||
**2. Check WordPress Email**
|
||||
- Test with a plugin like "Check & Log Email"
|
||||
- Consider using SMTP plugin (WP Mail SMTP)
|
||||
|
||||
**3. Check Spam Folder**
|
||||
- Emails may be in recipient's spam folder
|
||||
- Add sender to whitelist
|
||||
|
||||
---
|
||||
|
||||
## Plugin Conflicts
|
||||
|
||||
### Symptom
|
||||
WooNooW doesn't work after installing another plugin.
|
||||
|
||||
### Steps to Diagnose
|
||||
|
||||
1. **Deactivate other plugins** one by one
|
||||
2. **Switch to default theme** (Twenty Twenty-Three)
|
||||
3. **Check error logs** in `wp-content/debug.log`
|
||||
|
||||
### Common Conflicting Plugins
|
||||
|
||||
- Other WooCommerce template overrides
|
||||
- Page builder plugins (sometimes)
|
||||
- Heavy caching plugins (misconfigured)
|
||||
|
||||
---
|
||||
|
||||
## Getting More Help
|
||||
|
||||
If you can't resolve the issue:
|
||||
|
||||
1. **Collect Information**
|
||||
- WordPress version
|
||||
- WooCommerce version
|
||||
- WooNooW version
|
||||
- PHP version
|
||||
- Error messages (from debug.log)
|
||||
|
||||
2. **Enable Debug Mode**
|
||||
Add to `wp-config.php`:
|
||||
```php
|
||||
define('WP_DEBUG', true);
|
||||
define('WP_DEBUG_LOG', true);
|
||||
```
|
||||
|
||||
3. **Contact Support**
|
||||
Provide the collected information for faster resolution.
|
||||
277
docu.json
277
docu.json
@@ -1,61 +1,50 @@
|
||||
{
|
||||
"navbar": {
|
||||
"logo": {
|
||||
"src": "/images/docu.svg",
|
||||
"alt": "DocuBook Logo"
|
||||
},
|
||||
"logoText": "DocuBook",
|
||||
"menu": [
|
||||
{ "title": "Home", "href": "/" },
|
||||
{ "title": "Docs", "href": "/docs/getting-started/introduction" },
|
||||
{ "title": "Community", "href": "https://docubook.pro" }
|
||||
]
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "DocuBook",
|
||||
"social": [
|
||||
{
|
||||
"name": "Instagram",
|
||||
"url": "https://www.instagram.com/wildan.nrs",
|
||||
"iconName": "InstagramIcon"
|
||||
},
|
||||
{
|
||||
"name": "Facebook",
|
||||
"url": "https://www.facebook.com/wildan.nrsh",
|
||||
"iconName": "FacebookIcon"
|
||||
},
|
||||
{
|
||||
"name": "Twitter",
|
||||
"url": "https://x.com/wildan_nrss",
|
||||
"iconName": "TwitterIcon"
|
||||
},
|
||||
{
|
||||
"name": "Youtube",
|
||||
"url": "https://www.youtube.com/@wildan.nrs_",
|
||||
"iconName": "YoutubeIcon"
|
||||
}
|
||||
]
|
||||
},
|
||||
"$schema": "https://docubook.pro/docu.schema.json",
|
||||
"meta": {
|
||||
"baseURL": "https://docubook.pro",
|
||||
"title": "DocuBook",
|
||||
"description": "DocuBook is a modern documentation platform for building, deploying, and managing your docs with ease.",
|
||||
"baseURL": "https://docs.woonoow.com",
|
||||
"title": "WooNooW Docs",
|
||||
"description": "Official documentation for WooNooW Plugin - The ultimate WooCommerce enhancement suite.",
|
||||
"favicon": "/favicon.ico"
|
||||
},
|
||||
"navbar": {
|
||||
"logo": {
|
||||
"src": "/images/logo.png",
|
||||
"alt": "WooNooW Logo"
|
||||
},
|
||||
"logoText": "WooNooW Docs",
|
||||
"menu": [
|
||||
{
|
||||
"title": "Home",
|
||||
"href": "/"
|
||||
},
|
||||
{
|
||||
"title": "Developer Docs",
|
||||
"href": "/docs"
|
||||
},
|
||||
{
|
||||
"title": "Plugin Site",
|
||||
"href": "https://woonoow.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/DocuBook/docubook",
|
||||
"editPathTemplate": "/blob/main/{filePath}",
|
||||
"editLink": true
|
||||
"url": "https://git.backoffice.biz.id/dwindown/WooNooW",
|
||||
"editPathTemplate": "/blob/main/woonoow-docs/contents/{filePath}",
|
||||
"editLink": false
|
||||
},
|
||||
"sponsor": {
|
||||
"title": "Hosted on",
|
||||
"title": "Powered by",
|
||||
"item": {
|
||||
"title": "Vercel",
|
||||
"description": "Deploy your DocuBook app with zero configuration.",
|
||||
"image": "/images/vercel.png",
|
||||
"url": "https://vercel.com/import/project?template=https://github.com/DocuBook/docubook"
|
||||
"title": "WooNooW",
|
||||
"description": "Enhance your WooCommerce store.",
|
||||
"image": "/images/logo.png",
|
||||
"url": "https://woonoow.com"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "WooNooW",
|
||||
"social": []
|
||||
},
|
||||
"routes": [
|
||||
{
|
||||
"title": "Getting Started",
|
||||
@@ -63,66 +52,174 @@
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Book",
|
||||
"description": "Set up your Documentation",
|
||||
"title": "Guides"
|
||||
"description": "Guides and References",
|
||||
"title": "Docs"
|
||||
},
|
||||
"items": [
|
||||
{ "title": "Introduction", "href": "/introduction" },
|
||||
{ "title": "Installation", "href": "/installation" },
|
||||
{ "title": "Quick Start Guide", "href": "/quick-start-guide" },
|
||||
{ "title": "Project Structure", "href": "/project-structure" },
|
||||
{ "title": "Customize", "href": "/customize" },
|
||||
{
|
||||
"title": "Theme Colors",
|
||||
"href": "/theme-colors",
|
||||
"items": [
|
||||
{ "title": "Default", "href": "/default" },
|
||||
{ "title": "Fresh Lime", "href": "/freshlime" },
|
||||
{ "title": "Coffee", "href": "/coffee" },
|
||||
{ "title": "llms.txt", "href": "/llms" }
|
||||
]
|
||||
"title": "Introduction",
|
||||
"href": "/introduction"
|
||||
},
|
||||
{
|
||||
"title": "Installation",
|
||||
"href": "/installation"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Components",
|
||||
"href": "/components",
|
||||
"title": "Configuration",
|
||||
"href": "/configuration",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Layers",
|
||||
"description": "Write with Markdown",
|
||||
"title": "Markdown"
|
||||
"icon": "Settings",
|
||||
"description": "Setup & Options",
|
||||
"title": "Config"
|
||||
},
|
||||
"items": [
|
||||
{ "title": "Accordion", "href": "/accordion" },
|
||||
{ "title": "Button", "href": "/button" },
|
||||
{ "title": "Card", "href": "/card" },
|
||||
{ "title": "Card Group", "href": "/card-group" },
|
||||
{ "title": "Code Block", "href": "/code-block" },
|
||||
{ "title": "File Tree", "href": "/file-tree" },
|
||||
{ "title": "Image", "href": "/image" },
|
||||
{ "title": "Keyboard", "href": "/keyboard" },
|
||||
{ "title": "Link", "href": "/link" },
|
||||
{ "title": "Note", "href": "/note" },
|
||||
{ "title": "Release Note", "href": "/release-note" },
|
||||
{ "title": "Stepper", "href": "/stepper" },
|
||||
{ "title": "Tabs", "href": "/tabs" },
|
||||
{ "title": "Tooltips", "href": "/tooltips" },
|
||||
{ "title": "Youtube", "href": "/youtube" },
|
||||
{ "title": "Custom", "href": "/custom" }
|
||||
{
|
||||
"title": "SPA Mode",
|
||||
"href": "/spa-mode"
|
||||
},
|
||||
{
|
||||
"title": "Appearance",
|
||||
"href": "/appearance"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Release",
|
||||
"href": "/changelog",
|
||||
"title": "Core Features",
|
||||
"href": "/features",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "History",
|
||||
"description": "Updates and changes",
|
||||
"title": "Changelog"
|
||||
"icon": "Layout",
|
||||
"description": "Store Functionality",
|
||||
"title": "Features"
|
||||
},
|
||||
"items": [
|
||||
{ "title": "Version 1.0+", "href": "/version-1" }
|
||||
{
|
||||
"title": "Shop Page",
|
||||
"href": "/shop"
|
||||
},
|
||||
{
|
||||
"title": "Checkout",
|
||||
"href": "/checkout"
|
||||
},
|
||||
{
|
||||
"title": "Shortcodes",
|
||||
"href": "/shortcodes"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Licensing & OAuth",
|
||||
"href": "/licensing",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Key",
|
||||
"description": "License Management",
|
||||
"title": "Licensing"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"title": "OAuth Flow",
|
||||
"href": "/oauth-flow"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "API Reference",
|
||||
"href": "/api-reference",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Terminal",
|
||||
"description": "API Endpoints",
|
||||
"title": "API"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"title": "Licensing API",
|
||||
"href": "/licensing"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Developer Guides",
|
||||
"href": "/developer",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Code",
|
||||
"description": "Advanced Integration",
|
||||
"title": "Dev"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"title": "Addons: Bridge Pattern",
|
||||
"href": "/addons/bridge-pattern"
|
||||
},
|
||||
{
|
||||
"title": "Addons: React Integration",
|
||||
"href": "/addons/react-integration"
|
||||
},
|
||||
{
|
||||
"title": "Addons: Module Registry",
|
||||
"href": "/addons/module-integration"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Hooks & Filters",
|
||||
"href": "/hooks",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Anchor",
|
||||
"description": "Actions and Filters",
|
||||
"title": "Hooks"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"title": "Overview",
|
||||
"href": "/"
|
||||
},
|
||||
{
|
||||
"title": "Notifications",
|
||||
"href": "/notifications"
|
||||
},
|
||||
{
|
||||
"title": "Subscriptions",
|
||||
"href": "/subscriptions"
|
||||
},
|
||||
{
|
||||
"title": "Frontend",
|
||||
"href": "/frontend"
|
||||
},
|
||||
{
|
||||
"title": "Newsletter",
|
||||
"href": "/newsletter"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Resources",
|
||||
"href": "/resources",
|
||||
"noLink": true,
|
||||
"context": {
|
||||
"icon": "Box",
|
||||
"description": "Tools and Assets",
|
||||
"title": "Resources"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"title": "FAQ",
|
||||
"href": "/faq"
|
||||
},
|
||||
{
|
||||
"title": "Troubleshooting",
|
||||
"href": "/troubleshooting"
|
||||
},
|
||||
{
|
||||
"title": "Changelog",
|
||||
"href": "/changelog"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
35
eslint.config.mjs
Normal file
35
eslint.config.mjs
Normal file
@@ -0,0 +1,35 @@
|
||||
import { defineConfig } from "eslint/config";
|
||||
import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
|
||||
import nextTypescript from "eslint-config-next/typescript";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import js from "@eslint/js";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
});
|
||||
|
||||
export default defineConfig([{
|
||||
extends: [
|
||||
...nextCoreWebVitals,
|
||||
...nextTypescript,
|
||||
...compat.extends("plugin:@typescript-eslint/recommended")
|
||||
],
|
||||
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
|
||||
"@typescript-eslint/no-unused-vars": ["warn", {
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
caughtErrorsIgnorePattern: "^_",
|
||||
}],
|
||||
|
||||
"@typescript-eslint/no-empty-object-type": "off",
|
||||
},
|
||||
}]);
|
||||
@@ -16,6 +16,7 @@ export function useScrollPosition(threshold = 0.5) {
|
||||
// Add scroll event listener
|
||||
useEffect(() => {
|
||||
// Initial check
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
handleScroll();
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
|
||||
@@ -8,7 +8,7 @@ import rehypeSlug from "rehype-slug";
|
||||
import rehypeCodeTitles from "rehype-code-titles";
|
||||
import { page_routes, ROUTES } from "./routes-config";
|
||||
import { visit } from "unist-util-visit";
|
||||
import type { Node } from "unist";
|
||||
import type { Node, Parent } from "unist";
|
||||
import matter from "gray-matter";
|
||||
|
||||
// Type definitions for unist-util-visit
|
||||
@@ -16,6 +16,7 @@ interface Element extends Node {
|
||||
type: string;
|
||||
tagName?: string;
|
||||
properties?: Record<string, unknown> & {
|
||||
className?: string[];
|
||||
raw?: string;
|
||||
};
|
||||
children?: Node[];
|
||||
@@ -45,6 +46,7 @@ import CardGroup from "@/components/markdown/CardGroupMdx";
|
||||
import Kbd from "@/components/markdown/KeyboardMdx";
|
||||
import { Release, Changes } from "@/components/markdown/ReleaseMdx";
|
||||
import { File, Files, Folder } from "@/components/markdown/FileTreeMdx";
|
||||
import AccordionGroup from "@/components/markdown/AccordionGroupMdx";
|
||||
|
||||
// add custom components
|
||||
const components = {
|
||||
@@ -73,6 +75,50 @@ const components = {
|
||||
File,
|
||||
Files,
|
||||
Folder,
|
||||
AccordionGroup
|
||||
};
|
||||
|
||||
// helper function to handle rehype code titles, since by default we can't inject into the className of rehype-code-titles
|
||||
const handleCodeTitles = () => (tree: Node) => {
|
||||
visit(tree, "element", (node: Element, index: number | null, parent: Parent | null) => {
|
||||
// Ensure the visited node is valid
|
||||
if (!parent || index === null || node.tagName !== 'div') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is the title div from rehype-code-titles
|
||||
const isTitleDiv = node.properties?.className?.includes('rehype-code-title');
|
||||
if (!isTitleDiv) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the next <pre> element, skipping over other nodes like whitespace text
|
||||
let nextElement = null;
|
||||
for (let i = index + 1; i < parent.children.length; i++) {
|
||||
const sibling = parent.children[i];
|
||||
if (sibling.type === 'element') {
|
||||
nextElement = sibling as Element;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the next element is a <pre>, move the title to it
|
||||
if (nextElement && nextElement.tagName === 'pre') {
|
||||
const titleNode = node.children?.[0] as TextNode;
|
||||
if (titleNode && titleNode.type === 'text') {
|
||||
if (!nextElement.properties) {
|
||||
nextElement.properties = {};
|
||||
}
|
||||
nextElement.properties['data-title'] = titleNode.value;
|
||||
|
||||
// Remove the original title div
|
||||
parent.children.splice(index, 1);
|
||||
|
||||
// Return the same index to continue visiting from the correct position
|
||||
return index;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// can be used for other pages like blogs, Guides etc
|
||||
@@ -85,6 +131,7 @@ async function parseMdx<Frontmatter>(rawMdx: string) {
|
||||
rehypePlugins: [
|
||||
preProcess,
|
||||
rehypeCodeTitles,
|
||||
handleCodeTitles,
|
||||
rehypePrism,
|
||||
rehypeSlug,
|
||||
rehypeAutolinkHeadings,
|
||||
|
||||
85
package.json
85
package.json
@@ -1,62 +1,67 @@
|
||||
{
|
||||
"name": "docubook",
|
||||
"version": "1.15.1",
|
||||
"version": "2.0.0-beta.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@docsearch/css": "3",
|
||||
"@docsearch/css": "^3.9.0",
|
||||
"@docsearch/react": "^3.9.0",
|
||||
"@radix-ui/react-accordion": "^1.2.0",
|
||||
"@radix-ui/react-avatar": "^1.1.0",
|
||||
"@radix-ui/react-collapsible": "^1.1.0",
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-scroll-area": "^1.2.0",
|
||||
"@radix-ui/react-separator": "^1.0.3",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-tabs": "^1.1.0",
|
||||
"@radix-ui/react-toggle": "^1.1.2",
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"algoliasearch": "^5.35.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-avatar": "^1.1.11",
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-popover": "^1.1.15",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-toggle": "^1.1.10",
|
||||
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||
"algoliasearch": "^5.46.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "1.0.0",
|
||||
"framer-motion": "^12.4.1",
|
||||
"geist": "^1.3.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"framer-motion": "^12.26.2",
|
||||
"geist": "^1.5.1",
|
||||
"gray-matter": "^4.0.3",
|
||||
"install": "^0.13.0",
|
||||
"lucide-react": "^0.511.0",
|
||||
"next": "^14.2.6",
|
||||
"next": "16.1.3",
|
||||
"next-mdx-remote": "^5.0.0",
|
||||
"next-themes": "^0.3.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"next-themes": "^0.4.4",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"react-icons": "^5.5.0",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-code-titles": "^1.2.0",
|
||||
"rehype-prism-plus": "^2.0.0",
|
||||
"rehype-code-titles": "^1.2.1",
|
||||
"rehype-prism-plus": "^2.0.1",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"sonner": "^1.4.3",
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.14",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "^14.2.6",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"typescript": "^5"
|
||||
"@tailwindcss/postcss": "^4.1.18",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@types/node": "^20.19.30",
|
||||
"@types/react": "19.2.8",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-next": "16.1.3",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"overrides": {
|
||||
"@types/react": "19.2.8",
|
||||
"@types/react-dom": "19.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
'@tailwindcss/postcss': {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
BIN
public/images/logo.png
Normal file
BIN
public/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
@@ -1,71 +1,191 @@
|
||||
@import "@docsearch/css";
|
||||
@import "./algolia.css";
|
||||
@import 'tailwindcss';
|
||||
@plugin '@tailwindcss/typography';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import url("./syntax.css");
|
||||
/* Modern Blue Theme */
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@utility container {
|
||||
margin-inline: auto;
|
||||
padding-inline: 2rem;
|
||||
|
||||
@media (width >=--theme(--breakpoint-sm)) {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
@media (width >=1440px) {
|
||||
max-width: 1440px;
|
||||
}
|
||||
}
|
||||
|
||||
@theme {
|
||||
--color-border: hsl(var(--border));
|
||||
--color-input: hsl(var(--input));
|
||||
--color-ring: hsl(var(--ring));
|
||||
--color-background: hsl(var(--background));
|
||||
--color-foreground: hsl(var(--foreground));
|
||||
|
||||
--color-primary: hsl(var(--primary));
|
||||
--color-primary-foreground: hsl(var(--primary-foreground));
|
||||
|
||||
--color-secondary: hsl(var(--secondary));
|
||||
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
||||
|
||||
--color-destructive: hsl(var(--destructive));
|
||||
--color-destructive-foreground: hsl(var(--destructive-foreground));
|
||||
|
||||
--color-muted: hsl(var(--muted));
|
||||
--color-muted-foreground: hsl(var(--muted-foreground));
|
||||
|
||||
--color-accent: hsl(var(--accent));
|
||||
--color-accent-foreground: hsl(var(--accent-foreground));
|
||||
|
||||
--color-popover: hsl(var(--popover));
|
||||
--color-popover-foreground: hsl(var(--popover-foreground));
|
||||
|
||||
--color-card: hsl(var(--card));
|
||||
--color-card-foreground: hsl(var(--card-foreground));
|
||||
|
||||
--color-sidebar: hsl(var(--sidebar-background));
|
||||
--color-sidebar-foreground: hsl(var(--sidebar-foreground));
|
||||
--color-sidebar-primary: hsl(var(--sidebar-primary));
|
||||
--color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));
|
||||
--color-sidebar-accent: hsl(var(--sidebar-accent));
|
||||
--color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));
|
||||
--color-sidebar-border: hsl(var(--sidebar-border));
|
||||
--color-sidebar-ring: hsl(var(--sidebar-ring));
|
||||
|
||||
--radius-lg: var(--radius);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
|
||||
--font-code: var(--font-geist-mono);
|
||||
--font-regular: var(--font-geist-sans);
|
||||
|
||||
--animate-accordion-down: accordion-down 0.2s ease-out;
|
||||
--animate-accordion-up: accordion-up 0.2s ease-out;
|
||||
--animate-shiny-text: shiny-text 8s infinite;
|
||||
|
||||
@keyframes accordion-down {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes accordion-up {
|
||||
from {
|
||||
height: var(--radix-accordion-content-height);
|
||||
}
|
||||
|
||||
to {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shiny-text {
|
||||
|
||||
0%,
|
||||
90%,
|
||||
100% {
|
||||
background-position: calc(-100% - var(--shiny-width)) 0;
|
||||
}
|
||||
|
||||
30%,
|
||||
60% {
|
||||
background-position: calc(100% + var(--shiny-width)) 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
||||
so we've added these compatibility styles to make sure everything still
|
||||
looks the same as it did with Tailwind CSS v3.
|
||||
|
||||
If we ever want to remove these styles, we need to add an explicit border
|
||||
color utility to any element that depends on these defaults.
|
||||
*/
|
||||
@layer base {
|
||||
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: var(--color-gray-200, currentcolor);
|
||||
}
|
||||
}
|
||||
|
||||
@utility animate-shine {
|
||||
--animate-shine: shine var(--duration) infinite linear;
|
||||
animation: var(--animate-shine);
|
||||
background-size: 200% 200%;
|
||||
}
|
||||
|
||||
/* Fresh Lime Theme */
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 210 40% 98%;
|
||||
--foreground: 220 30% 15%;
|
||||
--background: 85 45% 98%;
|
||||
--foreground: 85 30% 10%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 220 30% 15%;
|
||||
--card-foreground: 85 30% 10%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 220 30% 15%;
|
||||
--primary: 210 81% 56%; /* #2281E3 */
|
||||
--popover-foreground: 85 30% 10%;
|
||||
--primary: 85 70% 45%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
--secondary: 210 30% 90%;
|
||||
--secondary-foreground: 220 30% 15%;
|
||||
--muted: 210 20% 92%;
|
||||
--muted-foreground: 220 15% 50%;
|
||||
--accent: 200 100% 40%;
|
||||
--secondary: 85 40% 90%;
|
||||
--secondary-foreground: 85 30% 10%;
|
||||
--muted: 85 30% 92%;
|
||||
--muted-foreground: 85 15% 45%;
|
||||
--accent: 85 60% 40%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 0 85% 60%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 210 20% 85%;
|
||||
--input: 210 20% 85%;
|
||||
--ring: 210 81% 56%;
|
||||
--border: 85 25% 88%;
|
||||
--input: 85 25% 88%;
|
||||
--ring: 85 70% 45%;
|
||||
--radius: 0.5rem;
|
||||
--chart-1: 210 81% 56%;
|
||||
--chart-2: 200 100% 40%;
|
||||
--chart-3: 220 76% 60%;
|
||||
--chart-4: 190 90% 50%;
|
||||
--chart-5: 230 86% 45%;
|
||||
--chart-1: 85 70% 45%;
|
||||
--chart-2: 85 60% 40%;
|
||||
--chart-3: 85 80% 40%;
|
||||
--chart-4: 85 85% 35%;
|
||||
--chart-5: 85 90% 30%;
|
||||
--line-number-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 220 25% 10%;
|
||||
--foreground: 210 30% 96%;
|
||||
--card: 220 25% 15%;
|
||||
--card-foreground: 210 30% 96%;
|
||||
--popover: 220 25% 15%;
|
||||
--popover-foreground: 210 30% 96%;
|
||||
--primary: 210 100% 65%;
|
||||
--primary-foreground: 220 25% 10%;
|
||||
--secondary: 215 25% 20%;
|
||||
--secondary-foreground: 210 30% 96%;
|
||||
--muted: 215 20% 25%;
|
||||
--muted-foreground: 215 20% 65%;
|
||||
--accent: 200 100% 60%;
|
||||
--background: 85 20% 8%;
|
||||
--foreground: 85 30% 96%;
|
||||
--card: 85 20% 10%;
|
||||
--card-foreground: 85 30% 96%;
|
||||
--popover: 85 20% 10%;
|
||||
--popover-foreground: 85 30% 96%;
|
||||
--primary: 85 75% 55%;
|
||||
--primary-foreground: 85 20% 8%;
|
||||
--secondary: 85 25% 18%;
|
||||
--secondary-foreground: 85 30% 96%;
|
||||
--muted: 85 20% 20%;
|
||||
--muted-foreground: 85 20% 70%;
|
||||
--accent: 85 70% 50%;
|
||||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 0 85% 70%;
|
||||
--destructive: 0 85% 65%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 215 20% 25%;
|
||||
--input: 215 20% 25%;
|
||||
--ring: 210 100% 65%;
|
||||
--chart-1: 210 100% 65%;
|
||||
--chart-2: 200 100% 60%;
|
||||
--chart-3: 220 90% 70%;
|
||||
--chart-4: 190 100% 65%;
|
||||
--chart-5: 230 90% 60%;
|
||||
--border: 85 25% 22%;
|
||||
--input: 85 25% 22%;
|
||||
--ring: 85 75% 55%;
|
||||
--chart-1: 85 75% 55%;
|
||||
--chart-2: 85 70% 50%;
|
||||
--chart-3: 85 80% 45%;
|
||||
--chart-4: 85 85% 40%;
|
||||
--chart-5: 85 90% 35%;
|
||||
--line-number-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
@@ -76,28 +196,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
.prose {
|
||||
@layer utilities {
|
||||
.prose {
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
pre {
|
||||
padding: 2px 0 !important;
|
||||
width: inherit !important;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
pre>code {
|
||||
pre>code {
|
||||
display: grid;
|
||||
max-width: inherit !important;
|
||||
padding: 14px 0 !important;
|
||||
}
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.code-line {
|
||||
.code-line {
|
||||
padding: 0.75px 16px;
|
||||
@apply border-l-2 border-transparent
|
||||
}
|
||||
@apply border-l-2 border-transparent;
|
||||
}
|
||||
|
||||
.line-number::before {
|
||||
.line-number::before {
|
||||
display: inline-block;
|
||||
width: 1rem;
|
||||
margin-right: 22px;
|
||||
@@ -106,36 +228,34 @@ pre>code {
|
||||
content: attr(line);
|
||||
font-size: 13.5px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.highlight-line {
|
||||
.highlight-line {
|
||||
@apply bg-primary/5 border-l-2 border-primary/30;
|
||||
}
|
||||
}
|
||||
|
||||
.rehype-code-title {
|
||||
.rehype-code-title {
|
||||
@apply px-2 -mb-8 w-full text-sm pb-5 font-medium mt-5 font-code;
|
||||
}
|
||||
}
|
||||
|
||||
.highlight-comp>code {
|
||||
.highlight-comp>code {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.animate-shine {
|
||||
--animate-shine: shine var(--duration) infinite linear;
|
||||
animation: var(--animate-shine);
|
||||
background-size: 200% 200%;
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
|
||||
50% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,3 +93,87 @@
|
||||
border: none;
|
||||
border-radius: 8px; /* Sudut melengkung pada iframe */
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Custom styling for code blocks */
|
||||
/* ======================================================================== */
|
||||
|
||||
.code-block-container {
|
||||
position: relative;
|
||||
margin: 1.5rem 0;
|
||||
border: 1px solid hsl(var(--border));
|
||||
overflow: hidden;
|
||||
font-size: 0.875rem;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.code-block-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background-color: hsl(var(--muted));
|
||||
padding: 0.5rem 1rem;
|
||||
border-bottom: 1px solid hsl(var(--border));
|
||||
color: hsl(var(--muted-foreground));
|
||||
font-family: monospace;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.code-block-actions {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.75rem;
|
||||
z-index: 10;
|
||||
}
|
||||
.code-block-actions button {
|
||||
color: hsl(var(--muted-foreground));
|
||||
transition: color 0.2s ease-in-out;
|
||||
}
|
||||
.code-block-actions button:hover {
|
||||
color: hsl(var(--foreground));
|
||||
}
|
||||
|
||||
|
||||
.code-block-body pre[class*="language-"] {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.line-numbers-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 3rem;
|
||||
padding-top: 1rem;
|
||||
text-align: right;
|
||||
color: var(--line-number-color);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.line-highlight {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: hsl(var(--primary) / 0.1);
|
||||
border-left: 2px solid hsl(var(--primary));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.code-block-body pre[data-line-numbers="true"] .line-highlight {
|
||||
padding-left: 3.5rem;
|
||||
}
|
||||
|
||||
.code-block-body::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
}
|
||||
.code-block-body::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
.code-block-body::-webkit-scrollbar-thumb {
|
||||
background: hsl(var(--border));
|
||||
border-radius: 4px;
|
||||
}
|
||||
.code-block-body::-webkit-scrollbar-thumb:hover {
|
||||
background: hsl(var(--muted));
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
import tailwindAnimate from "tailwindcss-animate";
|
||||
import typography from "@tailwindcss/typography";
|
||||
|
||||
const config = {
|
||||
darkMode: ["class"],
|
||||
darkMode: "class",
|
||||
content: [
|
||||
"./pages/**/*.{ts,tsx}",
|
||||
"./components/**/*.{ts,tsx}",
|
||||
@@ -105,7 +107,7 @@ const config = {
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
|
||||
plugins: [tailwindAnimate, typography],
|
||||
} satisfies Config;
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
@@ -10,7 +14,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
@@ -18,9 +22,20 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"target": "ES2017"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user