mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 12:43:12 +08:00
website: add sidebar structure
This commit is contained in:
@ -56,7 +56,32 @@ html[data-theme='dark'] {
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
margin-top: 1rem;
|
||||
font-size: 2.25em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 1.5em;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 1.25em;
|
||||
font-weight: 600;
|
||||
margin-top: 1.6em;
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
border-left-color: var(--ifm-color-emphasis-200);
|
||||
border-left-width: 0.5rem;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
}
|
||||
|
||||
.markdown ul blockquote {
|
||||
font-size: 0.9em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
@ -163,4 +188,3 @@ html[data-theme='dark'] .navbar-icon-telegram:before {
|
||||
height: 28px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ export default [
|
||||
wasn't sure what to expect and where to start. This handbook together
|
||||
with the{' '}
|
||||
<a
|
||||
href="https://frontendinterviewhandbook.com"
|
||||
href="https://www.frontendinterviewhandbook.com"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener">
|
||||
Front End Interview Handbook
|
||||
|
@ -23,7 +23,7 @@ const FEATURES = [
|
||||
interview experience needed.
|
||||
</>
|
||||
),
|
||||
link: '/introduction',
|
||||
link: '/software-engineering-interview-guide/',
|
||||
},
|
||||
{
|
||||
title: <>📝 Curated practice questions</>,
|
||||
@ -36,17 +36,17 @@ const FEATURES = [
|
||||
to tell you which the best questions are.
|
||||
</>
|
||||
),
|
||||
link: '/best-practice-questions',
|
||||
link: '/coding-interview-study-plan/',
|
||||
},
|
||||
{
|
||||
title: <>📋 Interview cheatsheet</>,
|
||||
title: <>📋 Interview best practices</>,
|
||||
description: (
|
||||
<>
|
||||
Straight-to-the-point Do's and Don'ts during an interview. The battle is
|
||||
already half won.
|
||||
</>
|
||||
),
|
||||
link: '/cheatsheet',
|
||||
link: '/coding-interview-best-practices/',
|
||||
},
|
||||
{
|
||||
title: <>💁♀️ Practical algorithm tips</>,
|
||||
@ -56,7 +56,7 @@ const FEATURES = [
|
||||
cases to look out for.
|
||||
</>
|
||||
),
|
||||
link: '/algorithms/introduction',
|
||||
link: '/algorithms/study-cheatsheet/',
|
||||
},
|
||||
{
|
||||
title: <>💬 Behavioral questions</>,
|
||||
@ -66,7 +66,7 @@ const FEATURES = [
|
||||
prepare your answers ahead of time.
|
||||
</>
|
||||
),
|
||||
link: '/behavioral-questions',
|
||||
link: '/behavioral-interview-questions/',
|
||||
},
|
||||
{
|
||||
title: <>🧪 Tested and proven</>,
|
||||
@ -145,7 +145,7 @@ function HeroSection() {
|
||||
<div className={styles.buttons}>
|
||||
<Link
|
||||
className={classnames('button button--primary button--lg')}
|
||||
to="/introduction">
|
||||
to="/software-engineering-interview-guide/">
|
||||
Start reading now →
|
||||
</Link>
|
||||
</div>
|
||||
@ -324,7 +324,7 @@ function HowToUseSection() {
|
||||
<>Software engineering specific resume content</>,
|
||||
<>Optimizing and and testing your resume</>,
|
||||
]}
|
||||
ctaLink="/resume/guide"
|
||||
ctaLink="/resume/"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@ -342,7 +342,7 @@ function HowToUseSection() {
|
||||
<>System design interview preparation</>,
|
||||
<>Behavioral interview preparation</>,
|
||||
]}
|
||||
ctaLink="/interview-formats"
|
||||
ctaLink="/coding-interview-prep/"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@ -358,7 +358,7 @@ function HowToUseSection() {
|
||||
<>Negotiation strategies for software engineers</>,
|
||||
<>Guide on how compensation works for software engineers</>,
|
||||
]}
|
||||
ctaLink="/understanding-compensation"
|
||||
ctaLink="/understanding-compensation/"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@ -818,7 +818,7 @@ function PreFooterSection() {
|
||||
</p>
|
||||
<Link
|
||||
className={classnames('button button--primary button--lg')}
|
||||
to="/introduction">
|
||||
to="/software-engineering-interview-guide/">
|
||||
Start reading now →
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -107,7 +107,7 @@ function DocItemContent(props) {
|
||||
</div>
|
||||
</div>
|
||||
{renderTocDesktop && (
|
||||
<div className="col col--4">
|
||||
<div className="col col--3">
|
||||
<TOC
|
||||
toc={DocContent.toc}
|
||||
minHeadingLevel={tocMinHeadingLevel}
|
||||
|
265
website/src/theme/DocSidebarItem/index.js
Normal file
265
website/src/theme/DocSidebarItem/index.js
Normal file
@ -0,0 +1,265 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
import React, {useEffect, useMemo} from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {
|
||||
isActiveSidebarItem,
|
||||
usePrevious,
|
||||
Collapsible,
|
||||
useCollapsible,
|
||||
findFirstCategoryLink,
|
||||
ThemeClassNames,
|
||||
useThemeConfig,
|
||||
useDocSidebarItemsExpandedState,
|
||||
isSamePath,
|
||||
} from '@docusaurus/theme-common';
|
||||
import Link from '@docusaurus/Link';
|
||||
import isInternalUrl from '@docusaurus/isInternalUrl';
|
||||
import {translate} from '@docusaurus/Translate';
|
||||
import IconExternalLink from '@theme/IconExternalLink';
|
||||
import DocSidebarItems from '@theme/DocSidebarItems';
|
||||
import styles from './styles.module.css';
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
export default function DocSidebarItem({item, ...props}) {
|
||||
switch (item.type) {
|
||||
case 'category':
|
||||
return <DocSidebarItemCategory item={item} {...props} />;
|
||||
|
||||
case 'html':
|
||||
return <DocSidebarItemHtml item={item} {...props} />;
|
||||
|
||||
case 'link':
|
||||
default:
|
||||
return <DocSidebarItemLink item={item} {...props} />;
|
||||
}
|
||||
} // If we navigate to a category and it becomes active, it should automatically
|
||||
// expand itself
|
||||
|
||||
function useAutoExpandActiveCategory({isActive, collapsed, setCollapsed}) {
|
||||
const wasActive = usePrevious(isActive);
|
||||
useEffect(() => {
|
||||
const justBecameActive = isActive && !wasActive;
|
||||
|
||||
if (justBecameActive && collapsed) {
|
||||
setCollapsed(false);
|
||||
}
|
||||
}, [isActive, wasActive, collapsed, setCollapsed]);
|
||||
}
|
||||
/**
|
||||
* When a collapsible category has no link, we still link it to its first child
|
||||
* during SSR as a temporary fallback. This allows to be able to navigate inside
|
||||
* the category even when JS fails to load, is delayed or simply disabled
|
||||
* React hydration becomes an optional progressive enhancement
|
||||
* see https://github.com/facebookincubator/infima/issues/36#issuecomment-772543188
|
||||
* see https://github.com/facebook/docusaurus/issues/3030
|
||||
*/
|
||||
|
||||
function useCategoryHrefWithSSRFallback(item) {
|
||||
const isBrowser = useIsBrowser();
|
||||
return useMemo(() => {
|
||||
if (item.href) {
|
||||
return item.href;
|
||||
} // In these cases, it's not necessary to render a fallback
|
||||
// We skip the "findFirstCategoryLink" computation
|
||||
|
||||
if (isBrowser || !item.collapsible) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return findFirstCategoryLink(item);
|
||||
}, [item, isBrowser]);
|
||||
}
|
||||
|
||||
function DocSidebarItemCategory({
|
||||
item,
|
||||
onItemClick,
|
||||
activePath,
|
||||
level,
|
||||
index,
|
||||
...props
|
||||
}) {
|
||||
const {items, label, collapsible, className, href} = item;
|
||||
const hrefWithSSRFallback = useCategoryHrefWithSSRFallback(item);
|
||||
const isActive = isActiveSidebarItem(item, activePath);
|
||||
const isCurrentPage = isSamePath(href, activePath);
|
||||
const {collapsed, setCollapsed} = useCollapsible({
|
||||
// active categories are always initialized as expanded
|
||||
// the default (item.collapsed) is only used for non-active categories
|
||||
initialState: () => {
|
||||
if (!collapsible) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isActive ? false : item.collapsed;
|
||||
},
|
||||
});
|
||||
useAutoExpandActiveCategory({
|
||||
isActive,
|
||||
collapsed,
|
||||
setCollapsed,
|
||||
});
|
||||
const {expandedItem, setExpandedItem} = useDocSidebarItemsExpandedState();
|
||||
|
||||
function updateCollapsed(toCollapsed = !collapsed) {
|
||||
setExpandedItem(toCollapsed ? null : index);
|
||||
setCollapsed(toCollapsed);
|
||||
}
|
||||
|
||||
const {autoCollapseSidebarCategories} = useThemeConfig();
|
||||
useEffect(() => {
|
||||
if (
|
||||
collapsible &&
|
||||
expandedItem &&
|
||||
expandedItem !== index &&
|
||||
autoCollapseSidebarCategories
|
||||
) {
|
||||
setCollapsed(true);
|
||||
}
|
||||
}, [
|
||||
collapsible,
|
||||
expandedItem,
|
||||
index,
|
||||
setCollapsed,
|
||||
autoCollapseSidebarCategories,
|
||||
]);
|
||||
return (
|
||||
<li
|
||||
className={clsx(
|
||||
ThemeClassNames.docs.docSidebarItemCategory,
|
||||
ThemeClassNames.docs.docSidebarItemCategoryLevel(level),
|
||||
'menu__list-item',
|
||||
{
|
||||
'menu__list-item--collapsed': collapsed,
|
||||
},
|
||||
className,
|
||||
)}>
|
||||
<div
|
||||
className={clsx('menu__list-item-collapsible', {
|
||||
'menu__list-item-collapsible--active': isCurrentPage,
|
||||
})}>
|
||||
<Link
|
||||
className={clsx('menu__link', {
|
||||
'menu__link--sublist': collapsible,
|
||||
'menu__link--sublist-caret': !href && collapsible,
|
||||
'menu__link--active': isActive,
|
||||
})}
|
||||
onClick={
|
||||
collapsible
|
||||
? (e) => {
|
||||
onItemClick?.(item);
|
||||
|
||||
if (href) {
|
||||
updateCollapsed(false);
|
||||
} else {
|
||||
e.preventDefault();
|
||||
updateCollapsed();
|
||||
}
|
||||
}
|
||||
: () => {
|
||||
onItemClick?.(item);
|
||||
}
|
||||
}
|
||||
aria-current={isCurrentPage ? 'page' : undefined}
|
||||
aria-expanded={collapsible ? !collapsed : undefined}
|
||||
href={collapsible ? hrefWithSSRFallback ?? '#' : hrefWithSSRFallback}
|
||||
{...props}>
|
||||
{label}
|
||||
</Link>
|
||||
{href && collapsible && (
|
||||
<button
|
||||
aria-label={translate(
|
||||
{
|
||||
id: 'theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel',
|
||||
message: "Toggle the collapsible sidebar category '{label}'",
|
||||
description:
|
||||
'The ARIA label to toggle the collapsible sidebar category',
|
||||
},
|
||||
{
|
||||
label,
|
||||
},
|
||||
)}
|
||||
type="button"
|
||||
className="clean-btn menu__caret"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
updateCollapsed();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}>
|
||||
<DocSidebarItems
|
||||
items={items}
|
||||
tabIndex={collapsed ? -1 : 0}
|
||||
onItemClick={onItemClick}
|
||||
activePath={activePath}
|
||||
level={level + 1}
|
||||
/>
|
||||
</Collapsible>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function DocSidebarItemHtml({item, level, index}) {
|
||||
const {value, defaultStyle, className} = item;
|
||||
return (
|
||||
<li
|
||||
className={clsx(
|
||||
ThemeClassNames.docs.docSidebarItemLink,
|
||||
ThemeClassNames.docs.docSidebarItemLinkLevel(level),
|
||||
defaultStyle && `${styles.menuHtmlItem} menu__list-item`,
|
||||
className,
|
||||
)}
|
||||
key={index} // eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: value,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function DocSidebarItemLink({
|
||||
item,
|
||||
onItemClick,
|
||||
activePath,
|
||||
level,
|
||||
index,
|
||||
...props
|
||||
}) {
|
||||
const {href, label, className} = item;
|
||||
const isActive = isActiveSidebarItem(item, activePath);
|
||||
const isInternalLink = isInternalUrl(href);
|
||||
return (
|
||||
<li
|
||||
className={clsx(
|
||||
ThemeClassNames.docs.docSidebarItemLink,
|
||||
ThemeClassNames.docs.docSidebarItemLinkLevel(level),
|
||||
'menu__list-item',
|
||||
className,
|
||||
)}
|
||||
key={label}>
|
||||
<Link
|
||||
className={clsx(
|
||||
'menu__link',
|
||||
!isInternalLink && styles.menuExternalLink,
|
||||
{
|
||||
'menu__link--active': isActive,
|
||||
},
|
||||
)}
|
||||
aria-current={isActive ? 'page' : undefined}
|
||||
to={href}
|
||||
{...(isInternalLink && {
|
||||
onClick: onItemClick ? () => onItemClick(item) : undefined,
|
||||
})}
|
||||
{...props}>
|
||||
{label}
|
||||
{!isInternalLink && <IconExternalLink />}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
17
website/src/theme/DocSidebarItem/styles.module.css
Normal file
17
website/src/theme/DocSidebarItem/styles.module.css
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
@media (min-width: 997px) {
|
||||
.menuHtmlItem {
|
||||
padding: var(--ifm-menu-link-padding-vertical)
|
||||
var(--ifm-menu-link-padding-horizontal);
|
||||
}
|
||||
}
|
||||
|
||||
.menuExternalLink {
|
||||
align-items: center;
|
||||
}
|
@ -14,7 +14,14 @@ function TOC({className, ...props}) {
|
||||
<div className="margin--md">
|
||||
<SidebarAd position="table_of_contents" />
|
||||
</div>
|
||||
<h3 className="padding-left--md padding-top--md margin-bottom--none">
|
||||
<h3
|
||||
className="padding-left--md padding-top--md margin-bottom--none"
|
||||
style={{
|
||||
textTransform: 'uppercase',
|
||||
fontSize: '0.75em',
|
||||
color: 'var(--ifm-color-emphasis-700)',
|
||||
letterSpacing: '0.5px',
|
||||
}}>
|
||||
Table of Contents
|
||||
</h3>
|
||||
<TOCItems
|
||||
|
Reference in New Issue
Block a user