Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions docs/getting-started/introduction.md

This file was deleted.

19 changes: 19 additions & 0 deletions docs/getting-started/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: Introduction
---

import BenefitGrid from '@site/src/components/BenefitGrid';

[PHP Debugger](https://github.com/php-debugger/php-debugger) is a step debugger for PHP, and nothing else. Every other feature that
normally ships alongside one — the profiler, the coverage collector, the tracer — has
been left out. What remains is a debugger you can leave switched on permanently,
because when you are not using it you can barely tell it is there.

<BenefitGrid />

## What's Next?

Ready to get started? Install PHP Debugger and try the quick start guide:

- [Installation Guide](./installation.md)
- [Quick Start](./quick-start.md)
115 changes: 115 additions & 0 deletions src/components/BenefitGrid/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import styles from './styles.module.css';

const iconProps = {
width: 26,
height: 26,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
strokeWidth: 1.8,
strokeLinecap: 'round',
strokeLinejoin: 'round',
};

const benefits = [
{
title: 'Near-zero overhead when idle',
text: 'With no debug client connected, the debugger stays out of the way. A typical web request does around 1% more work than running with no debugger at all.',
icon: (
<svg {...iconProps}>
<path d="M3 16a9 9 0 1 1 18 0" />
<path d="M12 16l5.5-6" />
<circle cx="12" cy="16" r="1.4" />
</svg>
),
},
{
title: 'Cheap while you are attached',
text: 'Keep your IDE connected all day. A session you are attached to but not actively stepping through still costs very little.',
icon: (
<svg {...iconProps}>
<circle cx="12" cy="12" r="9" />
<path d="M10 9v6M14 9v6" />
</svg>
),
},
{
title: 'Drop-in compatible',
text: 'Existing INI settings, IDE configurations, and helper functions keep working. In most projects there is almost nothing to migrate — just the line that loads the extension.',
icon: (
<svg {...iconProps}>
<path d="M9 3v6M15 3v6" />
<path d="M7 9h10v3a5 5 0 0 1-10 0V9z" />
<path d="M12 17v4" />
</svg>
),
},
{
title: 'Works with your editor',
text: 'Full DBGp protocol support means any IDE or tool that speaks it just works — PhpStorm, VS Code, Neovim, and anything else in your setup.',
icon: (
<svg {...iconProps}>
<rect x="3" y="4" width="18" height="13" rx="2" />
<path d="M8 21h8M12 17v4" />
</svg>
),
},
{
title: 'Everything you expect',
text: 'Breakpoints and conditional breakpoints. Step over, into, and out. Inspect variables, objects, and arrays, and watch expressions change as you go.',
icon: (
<svg {...iconProps}>
<rect x="6" y="7" width="12" height="13" rx="6" />
<path d="M9 7.5V6a3 3 0 0 1 6 0v1.5" />
<path d="M12 11v8" />
<path d="M2.5 11.5H6M18 11.5h3.5" />
<path d="M3.5 17.5 6 16M20.5 17.5 18 16" />
</svg>
),
},
{
title: 'One job, done well',
text: 'No profiler, no code coverage, no tracing. Step debugging is the only thing here, which is exactly why the rest of the time it costs you so little.',
icon: (
<svg {...iconProps}>
<circle cx="12" cy="12" r="9" />
<circle cx="12" cy="12" r="5" />
<circle cx="12" cy="12" r="1.4" />
</svg>
),
},
{
title: 'Nothing to install',
text: 'Use it as a regular extension, or reach for a container image with the debugger compiled straight into the interpreter. Change one line of your Dockerfile and you are done.',
icon: (
<svg {...iconProps}>
<path d="M12 2.5 20.5 7v10L12 21.5 3.5 17V7z" />
<path d="M8.5 12l2.5 2.5 4.5-4.5" />
</svg>
),
},
{
title: 'Ready the moment you are',
text: 'However you install it, debugging is on by default and starts with every request. Set a breakpoint, hit your app, and the session is already there — no trigger to remember.',
icon: (
<svg {...iconProps}>
<circle cx="12" cy="12" r="9" />
<path d="M10 8.5l6 3.5-6 3.5z" />
</svg>
),
},
];

export default function BenefitGrid() {
return (
<div className={styles.grid}>
{benefits.map(({title, text, icon}) => (
<div key={title} className={styles.card}>
<span className={styles.icon}>{icon}</span>
<h3 className={styles.cardTitle}>{title}</h3>
<p className={styles.cardText}>{text}</p>
</div>
))}
</div>
);
}
38 changes: 38 additions & 0 deletions src/components/BenefitGrid/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
margin: 2rem 0 2.5rem;
}

.card {
border: 1px solid var(--phpdbg-card-border);
border-radius: 10px;
background: var(--phpdbg-surface);
padding: 1.25rem 1.35rem 1.35rem;
}

.icon {
display: block;
color: var(--ifm-color-primary);
margin-bottom: 0.75rem;
}

.cardTitle {
font-size: 1.05rem;
line-height: 1.3;
margin: 0 0 0.4rem;
}

.cardText {
font-size: 0.9rem;
line-height: 1.6;
color: var(--ifm-color-emphasis-700);
margin: 0;
}

@media (max-width: 768px) {
.grid {
grid-template-columns: minmax(0, 1fr);
}
}
2 changes: 1 addition & 1 deletion src/components/HomeCards/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function HomeCards() {
</svg>
}
title="Key Features"
linkTo="/getting-started/introduction#key-features"
linkTo="/getting-started/introduction"
linkLabel="Explore all features">
<ul className={styles.checkList}>
{keyFeatures.map((feature) => (
Expand Down
7 changes: 7 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,10 @@ article a {
.breadcrumbs__link {
font-size: 0.8rem;
}

/* Anchor that src/theme/DocItem/Content puts on the page title, so the "on this
page" title entry has something to link to. Docusaurus only gives its own
headings the offset that clears the sticky navbar, so set it here too. */
#page-top {
scroll-margin-top: calc(var(--ifm-navbar-height) + 1rem);
}
38 changes: 38 additions & 0 deletions src/theme/DocItem/Content/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import clsx from 'clsx';
import {ThemeClassNames} from '@docusaurus/theme-common';
import {useDoc} from '@docusaurus/plugin-content-docs/client';
import Heading from '@theme/Heading';
import MDXContent from '@theme/MDXContent';

/* Ejected from @docusaurus/theme-classic so the synthetic page title can carry
an anchor. The table of contents is built from h2/h3 headings only, so the
title is never in it; without an id here there is nothing for the "on this
page" entry to link to. src/theme/TOC prepends that entry and targets this id. */
export const PAGE_TOP_ID = 'page-top';

/* Docusaurus renders a "synthetic title" from front matter only when the page
has not asked to hide it and the content does not already open with its own
h1. src/theme/TOC repeats this test, so keep the two in step. */
function useSyntheticTitle() {
const {metadata, frontMatter, contentTitle} = useDoc();
const shouldRender =
!frontMatter.hide_title && typeof contentTitle === 'undefined';
if (!shouldRender) {
return null;
}
return metadata.title;
}

export default function DocItemContent({children}) {
const syntheticTitle = useSyntheticTitle();
return (
<div className={clsx(ThemeClassNames.docs.docMarkdown, 'markdown')}>
{syntheticTitle && (
<header id={PAGE_TOP_ID}>
<Heading as="h1">{syntheticTitle}</Heading>
</header>
)}
<MDXContent>{children}</MDXContent>
</div>
);
}
71 changes: 71 additions & 0 deletions src/theme/TOCItems/Tree/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import Link from '@docusaurus/Link';
import {useDoc} from '@docusaurus/plugin-content-docs/client';
import {PAGE_TOP_ID} from '@theme/DocItem/Content';

/* Ejected from @docusaurus/theme-classic to put the page title at the top of
the table of contents. Docusaurus builds the list from h2/h3 headings alone,
so the title -- rendered as a synthetic h1 from front matter -- never appears.

Ejected rather than wrapped because the component recurses into itself, so a
wrapper cannot reach inside the list it renders. Both the desktop sidebar and
the mobile "on this page" dropdown render through here, so they stay in step. */

/* Docusaurus only renders a synthetic title when the page has not hidden it and
the content does not already open with its own h1. src/theme/DocItem/Content
makes the same test before adding the anchor; keep the two in step. */
function useSyntheticTitle() {
const {metadata, frontMatter, contentTitle} = useDoc();
if (frontMatter.hide_title || typeof contentTitle !== 'undefined') {
return null;
}
return metadata.title;
}

/* A plain <a>, not a Docusaurus <Link>, on purpose. The build-time broken-anchor
checker inspects <Link> only, and derives the valid anchors from the page's
headings -- it cannot see an id added by a theme component, so a <Link> here
reports a broken anchor on every page that has a title. */
function PageTitleItem({linkClassName}) {
const title = useSyntheticTitle();
if (!title) {
return null;
}
return (
<li>
<a className={linkClassName ?? undefined} href={`#${PAGE_TOP_ID}`}>
{title}
</a>
</li>
);
}

function TOCItemTree({toc, className, linkClassName, isChild}) {
if (!toc.length) {
return null;
}
return (
<ul className={isChild ? undefined : className}>
{!isChild && <PageTitleItem linkClassName={linkClassName} />}
{toc.map((heading) => (
<li key={heading.id}>
<Link
to={`#${heading.id}`}
className={linkClassName ?? undefined}
// Developer provided the HTML, so assume it's safe.
dangerouslySetInnerHTML={{__html: heading.value}}
/>
<TOCItemTree
isChild
toc={heading.children}
className={className}
linkClassName={linkClassName}
/>
</li>
))}
</ul>
);
}

// Memo only the tree root is enough
export default React.memo(TOCItemTree);
Loading