mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat: replace tabs components (#51361)
Co-authored-by: ahmad abdolsaheb <ahmad.abdolsaheb@gmail.com>
This commit is contained in:
@@ -639,16 +639,6 @@ pre {
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.nav-tabs > li.active > a,
|
||||
.nav-tabs > li.active > a:hover,
|
||||
.nav-tabs > li.active > a:focus {
|
||||
color: var(--secondary-background);
|
||||
}
|
||||
|
||||
.nav-tabs > li > a {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
blockquote footer,
|
||||
blockquote small,
|
||||
blockquote .small {
|
||||
|
||||
@@ -93,62 +93,43 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#mobile-layout .nav-tabs {
|
||||
#mobile-layout .nav-lists {
|
||||
margin: 0 1px;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--quaternary-color);
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
/* Need to narrow width to make room for preview toggle button */
|
||||
#mobile-layout .nav-tabs[data-haspreview='true'] {
|
||||
#mobile-layout .nav-lists[data-haspreview='true'] {
|
||||
width: calc(100% - 2rem - 2px);
|
||||
}
|
||||
|
||||
#mobile-layout .nav-tabs > li {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#mobile-layout .nav-tabs > li > a {
|
||||
margin-inline-end: 0;
|
||||
text-decoration: none;
|
||||
#mobile-layout .nav-lists > button {
|
||||
height: 2.5em;
|
||||
font-size: 0.8em;
|
||||
border: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: calc(2rem - 1px);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#mobile-layout .nav-tabs > li.active > a {
|
||||
color: var(--secondary-background);
|
||||
background-color: var(--quaternary-color);
|
||||
border: 0;
|
||||
font-weight: 900;
|
||||
height: 100%;
|
||||
#mobile-layout .nav-lists button[data-state='active'] {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#mobile-layout .nav-tabs > li:not(.active) > a:hover,
|
||||
#mobile-layout
|
||||
.nav-lists
|
||||
> button:is([aria-selected='false'], [aria-expanded='false']) {
|
||||
color: inherit;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
#mobile-layout .nav-lists > button:hover,
|
||||
.portal-button:hover {
|
||||
background: var(--quaternary-background);
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.portal-button {
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
top: 0;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
border: 0;
|
||||
/* This is the default for the a elements in the nav-tabs, inherited from bootstrap */
|
||||
/* We need to set this here to override our default button styles. */
|
||||
background: transparent;
|
||||
border-bottom: 1px solid var(--quaternary-color);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -163,14 +144,15 @@
|
||||
}
|
||||
|
||||
#mobile-layout .tab-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
padding-block-end: 37px;
|
||||
}
|
||||
|
||||
#mobile-layout-pane-preview .preview-external-window {
|
||||
#mobile-layout .tab-content[data-state='inactive'] {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
#mobile-layout .preview-external-window {
|
||||
text-align: center;
|
||||
margin-top: 60px;
|
||||
}
|
||||
@@ -180,15 +162,6 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
[data-has-editable-boundaries='true'] #mobile-layout .tab-content {
|
||||
padding-block-end: 0;
|
||||
}
|
||||
|
||||
#mobile-layout .tab-pane {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#mobile-layout #mobile-layout-pane-instructions {
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -214,6 +187,6 @@
|
||||
}
|
||||
|
||||
/* Focus indicator for tab panel */
|
||||
.nav-tabs [role='tab']:focus {
|
||||
.nav-lists [role='tab']:focus {
|
||||
outline-offset: -3px;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { TabPane, Tabs } from '@freecodecamp/react-bootstrap';
|
||||
import i18next from 'i18next';
|
||||
import React, { Component, ReactElement } from 'react';
|
||||
import { faWindowRestore } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { createSelector } from 'reselect';
|
||||
import { connect } from 'react-redux';
|
||||
import { Tabs, TabsContent, TabsTrigger, TabsList } from '@freecodecamp/ui';
|
||||
|
||||
import {
|
||||
removePortalWindow,
|
||||
setShowPreviewPortal,
|
||||
@@ -161,11 +162,6 @@ class MobileLayout extends Component<MobileLayoutProps, MobileLayoutState> {
|
||||
usesMultifileEditor
|
||||
} = this.props;
|
||||
|
||||
const editorTabPaneProps = {
|
||||
mountOnEnter: true,
|
||||
unmountOnExit: true
|
||||
};
|
||||
|
||||
const displayPreviewPane = hasPreview && showPreviewPane;
|
||||
const displayPreviewPortal = hasPreview && showPreviewPortal;
|
||||
|
||||
@@ -211,77 +207,35 @@ class MobileLayout extends Component<MobileLayoutProps, MobileLayoutState> {
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
activeKey={currentTab}
|
||||
animation={false}
|
||||
defaultActiveKey={currentTab}
|
||||
id='mobile-layout'
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onMouseDown={this.handleClick}
|
||||
onSelect={this.switchTab}
|
||||
onTouchStart={this.handleClick}
|
||||
defaultValue={currentTab}
|
||||
{...(hasPreview && { 'data-haspreview': 'true' })}
|
||||
>
|
||||
{!hasEditableBoundaries && (
|
||||
<TabPane
|
||||
eventKey={Tab.Instructions}
|
||||
title={i18next.t('learn.editor-tabs.instructions')}
|
||||
tabIndex={0}
|
||||
>
|
||||
{instructions}
|
||||
</TabPane>
|
||||
)}
|
||||
<TabPane
|
||||
eventKey={Tab.Editor}
|
||||
title={i18next.t('learn.editor-tabs.code')}
|
||||
{...editorTabPaneProps}
|
||||
>
|
||||
{usesMultifileEditor && <EditorTabs />}
|
||||
{editor}
|
||||
</TabPane>
|
||||
<TabPane
|
||||
eventKey={Tab.Console}
|
||||
title={i18next.t('learn.editor-tabs.console')}
|
||||
{...editorTabPaneProps}
|
||||
>
|
||||
{testOutput}
|
||||
</TabPane>
|
||||
{hasNotes && usesMultifileEditor && (
|
||||
<TabPane
|
||||
eventKey={Tab.Notes}
|
||||
title={i18next.t('learn.editor-tabs.notes')}
|
||||
>
|
||||
{notes}
|
||||
</TabPane>
|
||||
)}
|
||||
{hasPreview && (
|
||||
<TabPane
|
||||
eventKey={Tab.Preview}
|
||||
title={i18next.t('learn.editor-tabs.preview')}
|
||||
>
|
||||
<button
|
||||
className='portal-button'
|
||||
aria-expanded={!!showPreviewPortal}
|
||||
onClick={() => togglePane('showPreviewPortal')}
|
||||
>
|
||||
<span className='sr-only'>{getPortalBtnSrText()}</span>
|
||||
<FontAwesomeIcon icon={faWindowRestore} />
|
||||
</button>
|
||||
{displayPreviewPane && preview}
|
||||
{showPreviewPortal && (
|
||||
<p className='preview-external-window'>
|
||||
{i18next.t('learn.preview-external-window')}
|
||||
</p>
|
||||
)}
|
||||
</TabPane>
|
||||
)}
|
||||
{!hasEditableBoundaries && (
|
||||
<ToolPanel
|
||||
guideUrl={guideUrl}
|
||||
isMobile={true}
|
||||
videoUrl={videoUrl}
|
||||
/>
|
||||
)}
|
||||
{hasPreview && this.state.currentTab !== 'preview' && (
|
||||
<TabsList className='nav-lists'>
|
||||
{!hasEditableBoundaries && (
|
||||
<TabsTrigger value={Tab.Instructions}>
|
||||
{i18next.t('learn.editor-tabs.instructions')}
|
||||
</TabsTrigger>
|
||||
)}
|
||||
<TabsTrigger value={Tab.Editor}>
|
||||
{i18next.t('learn.editor-tabs.code')}
|
||||
</TabsTrigger>
|
||||
{hasNotes && usesMultifileEditor && (
|
||||
<TabsTrigger value={Tab.Notes}>
|
||||
{i18next.t('learn.editor-tabs.notes')}
|
||||
</TabsTrigger>
|
||||
)}
|
||||
<TabsTrigger value={Tab.Console}>
|
||||
{i18next.t('learn.editor-tabs.console')}
|
||||
</TabsTrigger>
|
||||
{hasPreview && (
|
||||
<TabsTrigger value={Tab.Preview}>
|
||||
{i18next.t('learn.editor-tabs.preview')}
|
||||
</TabsTrigger>
|
||||
)}
|
||||
<button
|
||||
className='portal-button'
|
||||
aria-expanded={!!showPreviewPortal}
|
||||
@@ -290,6 +244,58 @@ class MobileLayout extends Component<MobileLayoutProps, MobileLayoutState> {
|
||||
<span className='sr-only'>{getPortalBtnSrText()}</span>
|
||||
<FontAwesomeIcon icon={faWindowRestore} />
|
||||
</button>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent tabIndex={-1} className='tab-content' value={Tab.Editor}>
|
||||
{usesMultifileEditor && <EditorTabs />}
|
||||
{editor}
|
||||
</TabsContent>
|
||||
{!hasEditableBoundaries && (
|
||||
<TabsContent
|
||||
tabIndex={-1}
|
||||
className='tab-content'
|
||||
value={Tab.Instructions}
|
||||
>
|
||||
{instructions}
|
||||
</TabsContent>
|
||||
)}
|
||||
<TabsContent
|
||||
tabIndex={-1}
|
||||
className='tab-content'
|
||||
value={Tab.Console}
|
||||
>
|
||||
{testOutput}
|
||||
</TabsContent>
|
||||
{hasNotes && usesMultifileEditor && (
|
||||
<TabsContent
|
||||
tabIndex={-1}
|
||||
className='tab-content'
|
||||
value={Tab.Notes}
|
||||
>
|
||||
{notes}
|
||||
</TabsContent>
|
||||
)}
|
||||
{hasPreview && (
|
||||
<TabsContent
|
||||
tabIndex={-1}
|
||||
className='tab-content'
|
||||
value={Tab.Preview}
|
||||
forceMount
|
||||
>
|
||||
{displayPreviewPane && preview}
|
||||
{showPreviewPortal && (
|
||||
<p className='preview-external-window'>
|
||||
{i18next.t('learn.preview-external-window')}
|
||||
</p>
|
||||
)}
|
||||
</TabsContent>
|
||||
)}
|
||||
{!hasEditableBoundaries && (
|
||||
<ToolPanel
|
||||
guideUrl={guideUrl}
|
||||
isMobile={true}
|
||||
videoUrl={videoUrl}
|
||||
/>
|
||||
)}
|
||||
</Tabs>
|
||||
{displayPreviewPortal && (
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
export { Dropdown } from './drop-down';
|
||||
export { MenuItem } from './drop-down/menu-item';
|
||||
export { Container } from './container';
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent } from './tabs';
|
||||
|
||||
Reference in New Issue
Block a user