release version 1.8.5
This commit is contained in:
15
CHANGELOG.md
15
CHANGELOG.md
@@ -4,13 +4,28 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Expandables Leftbar
|
||||||
|
- sponsor badges or ads
|
||||||
- boolean show/hide `edit on github`
|
- boolean show/hide `edit on github`
|
||||||
|
- with the same code run anywhere (bun or nodejs)
|
||||||
|
- add fronmatter (metadata) to playground editor
|
||||||
|
|
||||||
### Improved
|
### Improved
|
||||||
|
|
||||||
- adjusment docu.json
|
- adjusment docu.json
|
||||||
- adjustment navbar, footer and components
|
- adjustment navbar, footer and components
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- bun compability rename .js to common js
|
||||||
|
- cli manage packageManager on package.json
|
||||||
|
- inconsistent design moved to better UI/UX
|
||||||
|
- error handle render footer.social
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- remove confused and verbose cli on installer
|
||||||
|
|
||||||
## [1.8.0] - 2025-03-01
|
## [1.8.0] - 2025-03-01
|
||||||
|
|
||||||
> Now looks more modern and clean which is a big change in layout and design
|
> Now looks more modern and clean which is a big change in layout and design
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export default async function DocsPage({ params: { slug = [] } }: PageProps) {
|
|||||||
<p className="-mt-4 text-muted-foreground text-[16.5px]">{description}</p>
|
<p className="-mt-4 text-muted-foreground text-[16.5px]">{description}</p>
|
||||||
<div>{res.content}</div>
|
<div>{res.content}</div>
|
||||||
<div
|
<div
|
||||||
className={`my-8 flex items-center border-b-2 border-x-muted-foreground ${
|
className={`my-8 flex items-center border-b-2 border-dashed border-x-muted-foreground ${
|
||||||
docuConfig.repository?.editLink ? "justify-between" : "justify-end"
|
docuConfig.repository?.editLink ? "justify-between" : "justify-end"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
23
components/SidebarToggle.tsx
Normal file
23
components/SidebarToggle.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isOpen: boolean;
|
||||||
|
onToggle: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SidebarToggle({ isOpen, onToggle }: Props) {
|
||||||
|
return (
|
||||||
|
<div className="absolute left-0 top-4 z-20">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
onClick={onToggle}
|
||||||
|
className="rounded-full border shadow bg-background"
|
||||||
|
aria-label="Toggle Sidebar"
|
||||||
|
>
|
||||||
|
{isOpen ? <ChevronLeft size={18} /> : <ChevronRight size={18} />}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
37
components/Sponsor.tsx
Normal file
37
components/Sponsor.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import docuConfig from "@/docu.json";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export function Sponsor() {
|
||||||
|
const sponsor = docuConfig.sponsor;
|
||||||
|
const item = sponsor?.item;
|
||||||
|
|
||||||
|
if (!item) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-4">
|
||||||
|
<h2 className="mb-4 text-sm font-medium">{sponsor.title || "Sponsor"}</h2>
|
||||||
|
<Link
|
||||||
|
href={item.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex flex-col justify-center gap-2 p-4 border rounded-lg hover:shadow transition-shadow"
|
||||||
|
>
|
||||||
|
<div className="relative w-8 h-8 flex-shrink-0">
|
||||||
|
<Image
|
||||||
|
src={item.image}
|
||||||
|
alt={item.title}
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-center sm:text-left">
|
||||||
|
<h3 className="text-sm font-medium">{item.title}</h3>
|
||||||
|
<p className="text-muted-foreground text-sm">{item.description}</p>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Sponsor;
|
||||||
@@ -24,13 +24,13 @@ interface VersionEntryProps {
|
|||||||
isLast?: boolean;
|
isLast?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function VersionEntry({
|
export function VersionEntry({
|
||||||
version,
|
version,
|
||||||
date,
|
date,
|
||||||
description,
|
description,
|
||||||
image,
|
image,
|
||||||
changes,
|
changes,
|
||||||
isLast
|
isLast
|
||||||
}: VersionEntryProps) {
|
}: VersionEntryProps) {
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ export function VersionEntry({
|
|||||||
{formatDate2(date)}
|
{formatDate2(date)}
|
||||||
</time>
|
</time>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{description && (
|
{description && (
|
||||||
<p className="text-dark text-xl">{description}</p>
|
<p className="text-dark text-xl">{description}</p>
|
||||||
)}
|
)}
|
||||||
@@ -69,8 +69,8 @@ export function VersionEntry({
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{Object.entries(changes).map(([type, items]) => (
|
{Object.entries(changes).map(([type, items]) => (
|
||||||
items && items.length > 0 && (
|
items && items.length > 0 && (
|
||||||
<ChangeGroup
|
<ChangeGroup
|
||||||
key={type}
|
key={type}
|
||||||
type={type as keyof typeof changes}
|
type={type as keyof typeof changes}
|
||||||
changes={items}
|
changes={items}
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
@@ -82,10 +82,10 @@ export function VersionEntry({
|
|||||||
{/* Show more/less button */}
|
{/* Show more/less button */}
|
||||||
{Object.values(changes).some(items => items && items.length > 5) && (
|
{Object.values(changes).some(items => items && items.length > 5) && (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setExpanded(!expanded)}
|
onClick={() => setExpanded(!expanded)}
|
||||||
className="mt-4 text-muted-foreground hover:text-foreground"
|
className="mt-4 text-muted-foreground hover:bg-transparent hover:text-accent border-none"
|
||||||
>
|
>
|
||||||
{expanded ? (
|
{expanded ? (
|
||||||
<>
|
<>
|
||||||
@@ -110,4 +110,4 @@ export function VersionEntry({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,12 +30,20 @@ export function Footer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function FooterButtons() {
|
export function FooterButtons() {
|
||||||
const { footer } = docuConfig;
|
const footer = docuConfig?.footer;
|
||||||
|
|
||||||
|
// Jangan render apapun jika tidak ada data sosial
|
||||||
|
if (!footer?.social || !Array.isArray(footer.social) || footer.social.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{footer.social?.map((item) => {
|
{footer.social.map((item) => {
|
||||||
const IconComponent = (LucideIcons[item.iconName as keyof typeof LucideIcons] ?? LucideIcons["Globe"]) as unknown as React.FC<{ className?: string }>;
|
const IconComponent =
|
||||||
|
(LucideIcons[item.iconName as keyof typeof LucideIcons] ??
|
||||||
|
LucideIcons["Globe"]) as React.FC<{ className?: string }>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={item.name}
|
key={item.name}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client"
|
||||||
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetClose,
|
SheetClose,
|
||||||
@@ -7,7 +9,7 @@ import {
|
|||||||
} from "@/components/ui/sheet";
|
} from "@/components/ui/sheet";
|
||||||
import { Logo, NavMenu } from "@/components/navbar";
|
import { Logo, NavMenu } from "@/components/navbar";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { AlignLeftIcon } from "lucide-react";
|
import { AlignLeftIcon, ArrowLeftFromLine, ArrowRightFromLine } from "lucide-react";
|
||||||
import { FooterButtons } from "@/components/footer";
|
import { FooterButtons } from "@/components/footer";
|
||||||
import { DialogTitle } from "@/components/ui/dialog";
|
import { DialogTitle } from "@/components/ui/dialog";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
@@ -15,10 +17,32 @@ import DocsMenu from "@/components/docs-menu";
|
|||||||
import { ModeToggle } from "@/components/theme-toggle";
|
import { ModeToggle } from "@/components/theme-toggle";
|
||||||
|
|
||||||
export function Leftbar() {
|
export function Leftbar() {
|
||||||
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="lg:flex hidden flex-[1.5] min-w-[238px] sticky top-16 flex-col h-[93.75vh] overflow-y-auto">
|
<aside
|
||||||
<ScrollArea className="py-4">
|
className={`sticky lg:flex hidden top-16 h-[calc(100vh-4rem)] border-r bg-background transition-all duration-300
|
||||||
<DocsMenu />
|
${collapsed ? "w-[0px]" : "w-[250px]"} flex flex-col pr-2`}
|
||||||
|
>
|
||||||
|
{/* Toggle Button */}
|
||||||
|
<div className="absolute top-0 right-0 py-2 px-0 ml-6 z-10">
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
variant="outline"
|
||||||
|
className="hover:bg-transparent hover:text-inherit border-none text-muted-foreground"
|
||||||
|
onClick={() => setCollapsed((prev) => !prev)}
|
||||||
|
>
|
||||||
|
{collapsed ? (
|
||||||
|
<ArrowRightFromLine size={18} />
|
||||||
|
) : (
|
||||||
|
<ArrowLeftFromLine size={18} />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Scrollable DocsMenu */}
|
||||||
|
<ScrollArea className="flex-1 px-2 pb-4">
|
||||||
|
{!collapsed && <DocsMenu />}
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
@@ -36,7 +60,7 @@ export function SheetLeftbar() {
|
|||||||
<DialogTitle className="sr-only">Menu</DialogTitle>
|
<DialogTitle className="sr-only">Menu</DialogTitle>
|
||||||
<SheetHeader>
|
<SheetHeader>
|
||||||
<SheetClose className="px-5" asChild>
|
<SheetClose className="px-5" asChild>
|
||||||
<Logo />
|
<span className="px-2"><Logo /></span>
|
||||||
</SheetClose>
|
</SheetClose>
|
||||||
</SheetHeader>
|
</SheetHeader>
|
||||||
<div className="flex flex-col gap-4 overflow-y-auto">
|
<div className="flex flex-col gap-4 overflow-y-auto">
|
||||||
|
|||||||
@@ -2,19 +2,25 @@ import { getDocsTocs } from "@/lib/markdown";
|
|||||||
import TocObserver from "./toc-observer";
|
import TocObserver from "./toc-observer";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
import { ListIcon } from "lucide-react";
|
import { ListIcon } from "lucide-react";
|
||||||
|
import Sponsor from "./Sponsor";
|
||||||
|
|
||||||
|
|
||||||
export default async function Toc({ path }: { path: string }) {
|
export default async function Toc({ path }: { path: string }) {
|
||||||
const tocs = await getDocsTocs(path);
|
const tocs = await getDocsTocs(path);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="lg:flex hidden toc flex-[1.5] min-w-[238px] py-9 sticky top-16 h-[96.95vh]">
|
<div className="lg:flex hidden toc flex-[1.5] min-w-[238px] py-9 sticky top-16 h-[96.95vh]">
|
||||||
<div className="flex flex-col gap-3 w-full pl-2">
|
<div className="flex flex-col gap-6 w-full pl-2 h-full">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-col gap-3">
|
||||||
<ListIcon className="w-5 h-5" /><h3 className="font-medium text-sm">On this page</h3>
|
<div className="flex items-center gap-2">
|
||||||
|
<ListIcon className="w-5 h-5" />
|
||||||
|
<h3 className="font-medium text-sm">On this page</h3>
|
||||||
|
</div>
|
||||||
|
<ScrollArea className="pb-2 pt-0.5 overflow-y-auto">
|
||||||
|
<TocObserver data={tocs} />
|
||||||
|
</ScrollArea>
|
||||||
</div>
|
</div>
|
||||||
<ScrollArea className="pb-2 pt-0.5 overflow-y-auto">
|
<Sponsor />
|
||||||
<TocObserver data={tocs} />
|
|
||||||
</ScrollArea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
13
docu.json
13
docu.json
@@ -17,12 +17,12 @@
|
|||||||
"social": [
|
"social": [
|
||||||
{
|
{
|
||||||
"name": "Gitlab",
|
"name": "Gitlab",
|
||||||
"url": "https://gitlab.com/mywildancloud/docubook",
|
"url": "https://gitlab.com/mywildancloud",
|
||||||
"iconName": "GitlabIcon"
|
"iconName": "GitlabIcon"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Instagram",
|
"name": "Instagram",
|
||||||
"url": "https://www.instagram.com/wildan.nrs/",
|
"url": "https://www.instagram.com/wildan.nrs",
|
||||||
"iconName": "InstagramIcon"
|
"iconName": "InstagramIcon"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -53,6 +53,15 @@
|
|||||||
"editPathTemplate": "/blob/main/{filePath}",
|
"editPathTemplate": "/blob/main/{filePath}",
|
||||||
"editLink": true
|
"editLink": true
|
||||||
},
|
},
|
||||||
|
"sponsor": {
|
||||||
|
"title": "Our Sponsor",
|
||||||
|
"item": {
|
||||||
|
"title": "Vercel",
|
||||||
|
"description": "Deploy your Next.js app with zero configuration.",
|
||||||
|
"image": "/images/vercel.png",
|
||||||
|
"url": "https://vercel.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"title": "Getting Started",
|
"title": "Getting Started",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docubook",
|
"name": "docubook",
|
||||||
"version": "1.8.0",
|
"version": "1.8.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
BIN
public/images/vercel.png
Normal file
BIN
public/images/vercel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
@@ -14,7 +14,7 @@ const config = {
|
|||||||
center: true,
|
center: true,
|
||||||
padding: '2rem',
|
padding: '2rem',
|
||||||
screens: {
|
screens: {
|
||||||
'2xl': '1300px'
|
'2xl': '1440px'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
extend: {
|
extend: {
|
||||||
|
|||||||
Reference in New Issue
Block a user