Merge pull request #22222 from overleaf/td-thin-footer-react
Implement thin footer in Bootstrap 5 GitOrigin-RevId: c45f63b3d2536e6266eb55cc95df11b53a6b77ec
This commit is contained in:
@@ -83,8 +83,7 @@ describe('LearnWiki', function () {
|
||||
})
|
||||
|
||||
function checkDisabled() {
|
||||
// eslint-disable-next-line mocha/no-skipped-tests
|
||||
it.skip('should not add a documentation entry to the nav bar', () => {
|
||||
it('should not add a documentation entry to the nav bar', () => {
|
||||
login(REGULAR_USER)
|
||||
cy.visit('/project')
|
||||
cy.findByText('Documentation').should('not.exist')
|
||||
|
||||
@@ -244,8 +244,8 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
||||
}
|
||||
|
||||
// This function is used to add translations from the server for main
|
||||
// navigation items because it's tricky to get them in the front end
|
||||
// otherwise.
|
||||
// navigation and footer items because it's tricky to get them in the front
|
||||
// end otherwise.
|
||||
res.locals.cloneAndTranslateText = obj => {
|
||||
const clone = _.cloneDeep(obj)
|
||||
addTranslatedTextDeep(clone)
|
||||
|
||||
@@ -17,7 +17,10 @@ block body
|
||||
|
||||
if (typeof suppressFooter === "undefined")
|
||||
if showThinFooter
|
||||
include layout/footer-marketing
|
||||
if bootstrapVersion === 5
|
||||
include layout/thin-footer-bootstrap-5
|
||||
else
|
||||
include layout/thin-footer
|
||||
else
|
||||
include layout/fat-footer
|
||||
|
||||
|
||||
@@ -40,8 +40,12 @@ block append meta
|
||||
items: cloneAndTranslateText(nav.header_extras)
|
||||
})
|
||||
meta(name="ol-footer" data-type="json" content={
|
||||
showThinFooter: showThinFooter,
|
||||
showPoweredBy: !hasFeature('saas') && !settings.nav.hide_powered_by,
|
||||
subdomainLang: settings.i18n.subdomainLang,
|
||||
translatedLanguages: settings.translatedLanguages
|
||||
translatedLanguages: settings.translatedLanguages,
|
||||
leftItems: cloneAndTranslateText(settings.nav.left_footer),
|
||||
rightItems: settings.nav.right_footer
|
||||
})
|
||||
|
||||
block body
|
||||
@@ -55,7 +59,10 @@ block body
|
||||
|
||||
if (typeof suppressFooter === "undefined")
|
||||
if showThinFooter
|
||||
include layout/footer-marketing
|
||||
if bootstrapVersion === 5
|
||||
include layout/thin-footer-bootstrap-5
|
||||
else
|
||||
include layout/thin-footer
|
||||
else
|
||||
if bootstrapVersion === 5
|
||||
include layout/fat-footer-react-bootstrap-5
|
||||
|
||||
@@ -16,7 +16,7 @@ block body
|
||||
|
||||
if (typeof(suppressFooter) == "undefined")
|
||||
if showThinFooter
|
||||
include layout/footer-marketing
|
||||
include layout/thin-footer-bootstrap-5
|
||||
else
|
||||
include layout/fat-footer-website-redesign
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ block body
|
||||
|
||||
if (typeof(suppressFooter) == "undefined")
|
||||
if showThinFooter
|
||||
include layout/footer-marketing
|
||||
include layout/thin-footer
|
||||
else
|
||||
include layout/fat-footer-website-redesign
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#fat-footer-container
|
||||
#footer-container
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
li.dropdown.dropup.subdued(dropdown).language-picker
|
||||
a#language-picker-toggle(
|
||||
href="#",
|
||||
button#language-picker-toggle.btn.btn-link.btn-inline-link(
|
||||
dropdown-toggle,
|
||||
data-ol-lang-selector-tooltip,
|
||||
data-bs-toggle="dropdown",
|
||||
role="button"
|
||||
aria-haspopup="true",
|
||||
aria-expanded="false",
|
||||
aria-label="Select " + translate('language'),
|
||||
tooltip=translate('language')
|
||||
title=translate('language')
|
||||
)
|
||||
i.fa.fa-fw.fa-language
|
||||
|
|
||||
| #{settings.translatedLanguages[currentLngCode]}
|
||||
span.material-symbols(aria-hidden="true") translate
|
||||
|
|
||||
span.language-picker-text #{settings.translatedLanguages[currentLngCode]}
|
||||
|
||||
ul.dropdown-menu(role="menu" aria-labelledby="language-picker-toggle")
|
||||
ul.dropdown-menu.dropdown-menu-sm-width(role="menu" aria-labelledby="language-picker-toggle")
|
||||
li.dropdown-header #{translate("language")}
|
||||
each subdomainDetails, subdomain in settings.i18n.subdomainLang
|
||||
if !subdomainDetails.hide
|
||||
@@ -24,4 +22,4 @@ li.dropdown.dropup.subdued(dropdown).language-picker
|
||||
a.menu-indent(href=subdomainDetails.url+currentUrlWithQueryParams, role="menuitem", class=isActive ? 'dropdown-item active' : 'dropdown-item', aria-selected=isActive ? 'true' : 'false')
|
||||
| #{settings.translatedLanguages[subdomainDetails.lngCode]}
|
||||
if subdomainDetails.lngCode === currentLngCode
|
||||
span.material-symbols.dropdown-item-trailing-icon.pull-right(aria-hidden="true") check
|
||||
span.material-symbols.dropdown-item-trailing-icon(aria-hidden="true") check
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
footer.site-footer
|
||||
- var showLanguagePicker = Object.keys(settings.i18n.subdomainLang).length > 1
|
||||
- var hasCustomLeftNav = nav.left_footer && nav.left_footer.length > 0
|
||||
.site-footer-content.hidden-print
|
||||
.row
|
||||
ul.site-footer-items.col-lg-9
|
||||
if !settings.nav.hide_powered_by
|
||||
li
|
||||
//- year of Server Pro release, static
|
||||
| © 2024
|
||||
|
|
||||
a(href='https://www.overleaf.com/for/enterprises') Powered by Overleaf
|
||||
|
||||
if showLanguagePicker || hasCustomLeftNav
|
||||
li
|
||||
strong.text-muted |
|
||||
|
||||
if showLanguagePicker
|
||||
include language-picker-bootstrap-5
|
||||
|
||||
if showLanguagePicker && hasCustomLeftNav
|
||||
li
|
||||
strong.text-muted |
|
||||
|
||||
each item in nav.left_footer
|
||||
li
|
||||
if item.url
|
||||
a(href=item.url, class=item.class) !{translate(item.text)}
|
||||
else
|
||||
| !{item.text}
|
||||
|
||||
ul.site-footer-items.col-lg-3.text-end
|
||||
each item in nav.right_footer
|
||||
li
|
||||
if item.url
|
||||
a(href=item.url, class=item.class, aria-label=item.label) !{item.text}
|
||||
else
|
||||
| !{item.text}
|
||||
@@ -790,6 +790,7 @@
|
||||
"knowledge_base": "",
|
||||
"labels_help_you_to_easily_reference_your_figures": "",
|
||||
"labels_help_you_to_reference_your_tables": "",
|
||||
"language": "",
|
||||
"language_feedback": "",
|
||||
"large_or_high-resolution_images_taking_too_long": "",
|
||||
"last_active": "",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import ReactDOM from 'react-dom'
|
||||
import getMeta from '@/utils/meta'
|
||||
import DefaultNavbar from '@/features/ui/components/bootstrap-5/navbar/default-navbar'
|
||||
import FatFooter from '@/features/ui/components/bootstrap-5/footer/fat-footer'
|
||||
import Footer from '@/features/ui/components/bootstrap-5/footer/footer'
|
||||
|
||||
const navbarElement = document.getElementById('navbar-container')
|
||||
if (navbarElement) {
|
||||
@@ -9,8 +9,8 @@ if (navbarElement) {
|
||||
ReactDOM.render(<DefaultNavbar {...navbarProps} />, navbarElement)
|
||||
}
|
||||
|
||||
const footerElement = document.getElementById('fat-footer-container')
|
||||
const footerElement = document.getElementById('footer-container')
|
||||
if (footerElement) {
|
||||
const footerProps = getMeta('ol-footer')
|
||||
ReactDOM.render(<FatFooter {...footerProps} />, footerElement)
|
||||
ReactDOM.render(<Footer {...footerProps} />, footerElement)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import SidebarDsNav from '@/features/project-list/components/sidebar/sidebar-ds-
|
||||
|
||||
export function ProjectListDsNav() {
|
||||
const navbarProps = getMeta('ol-navbar')
|
||||
const footerProps = getMeta('ol-footer')
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
error,
|
||||
@@ -120,7 +119,7 @@ export function ProjectListDsNav() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FatFooter {...footerProps} />
|
||||
<FatFooter />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ import withErrorBoundary from '../../../infrastructure/error-boundary'
|
||||
import { GenericErrorBoundaryFallback } from '@/shared/components/generic-error-boundary-fallback'
|
||||
import getMeta from '@/utils/meta'
|
||||
import DefaultNavbar from '@/features/ui/components/bootstrap-5/navbar/default-navbar'
|
||||
import FatFooter from '@/features/ui/components/bootstrap-5/footer/fat-footer'
|
||||
import Footer from '@/features/ui/components/bootstrap-5/footer/footer'
|
||||
import WelcomePageContent from '@/features/project-list/components/welcome-page-content'
|
||||
import ProjectListDefault from '@/features/project-list/components/project-list-default'
|
||||
import { ProjectListDsNav } from '@/features/project-list/components/project-list-ds-nav'
|
||||
@@ -57,7 +57,7 @@ function DefaultNavbarAndFooter({ children }: { children: ReactNode }) {
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
<FatFooter {...footerProps} />
|
||||
<Footer {...footerProps} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ function FatFooterBase() {
|
||||
</FooterBaseLink>
|
||||
</div>
|
||||
<div className="fat-footer-base-item fat-footer-base-language">
|
||||
<LanguagePicker />
|
||||
<LanguagePicker showHeader={false} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="fat-footer-base-section fat-footer-base-social">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import FatFooterBase from './fat-footer-base'
|
||||
import { FatFooterMetadata } from '../../types/fat-footer-metadata'
|
||||
|
||||
type FooterLinkProps = {
|
||||
href: string
|
||||
@@ -13,7 +12,7 @@ type FooterSectionProps = {
|
||||
links: FooterLinkProps[]
|
||||
}
|
||||
|
||||
function FatFooter(props: FatFooterMetadata) {
|
||||
function FatFooter() {
|
||||
const { t } = useTranslation()
|
||||
const hideFatFooter = false
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { FooterMetadata } from '@/features/ui/components/types/footer-metadata'
|
||||
import ThinFooter from '@/features/ui/components/bootstrap-5/footer/thin-footer'
|
||||
import FatFooter from '@/features/ui/components/bootstrap-5/footer/fat-footer'
|
||||
|
||||
function Footer(props: FooterMetadata) {
|
||||
return props.showThinFooter ? <ThinFooter {...props} /> : <FatFooter />
|
||||
}
|
||||
|
||||
export default Footer
|
||||
@@ -0,0 +1,90 @@
|
||||
import type {
|
||||
FooterItem,
|
||||
FooterMetadata,
|
||||
} from '@/features/ui/components/types/footer-metadata'
|
||||
import OLRow from '@/features/ui/components/ol/ol-row'
|
||||
import LanguagePicker from '@/features/ui/components/bootstrap-5/language-picker'
|
||||
import React from 'react'
|
||||
|
||||
function FooterItemLi({
|
||||
text,
|
||||
translatedText,
|
||||
url: href,
|
||||
class: className,
|
||||
label,
|
||||
}: FooterItem) {
|
||||
const textToDisplay = translatedText || text
|
||||
|
||||
if (!href) {
|
||||
return <li>{textToDisplay}</li>
|
||||
}
|
||||
|
||||
const linkProps = {
|
||||
href,
|
||||
className,
|
||||
'aria-label': label,
|
||||
}
|
||||
|
||||
return (
|
||||
<li>
|
||||
<a {...linkProps} dangerouslySetInnerHTML={{ __html: textToDisplay }} />
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
function Separator() {
|
||||
return (
|
||||
<li role="separator" className="text-muted">
|
||||
<strong>|</strong>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
function ThinFooter({
|
||||
showPoweredBy,
|
||||
subdomainLang,
|
||||
leftItems,
|
||||
rightItems,
|
||||
}: FooterMetadata) {
|
||||
const showLanguagePicker = Boolean(
|
||||
subdomainLang && Object.keys(subdomainLang).length > 1
|
||||
)
|
||||
|
||||
const hasCustomLeftNav = Boolean(leftItems && leftItems.length > 0)
|
||||
|
||||
return (
|
||||
<footer className="site-footer">
|
||||
<div className="site-footer-content d-print-none">
|
||||
<OLRow>
|
||||
<ul className="site-footer-items col-lg-9">
|
||||
{showPoweredBy ? (
|
||||
<>
|
||||
<li>
|
||||
{/* year of Server Pro release, static */}© 2024{' '}
|
||||
<a href="https://www.overleaf.com/for/enterprises">
|
||||
Powered by Overleaf
|
||||
</a>
|
||||
</li>
|
||||
{showLanguagePicker || hasCustomLeftNav ? <Separator /> : null}
|
||||
</>
|
||||
) : null}
|
||||
{showLanguagePicker ? (
|
||||
<li>
|
||||
<LanguagePicker showHeader />
|
||||
</li>
|
||||
) : null}
|
||||
{hasCustomLeftNav ? <Separator /> : null}
|
||||
{leftItems?.map(item => <FooterItemLi key={item.text} {...item} />)}
|
||||
</ul>
|
||||
<ul className="site-footer-items col-lg-3 text-end">
|
||||
{rightItems?.map(item => (
|
||||
<FooterItemLi key={item.text} {...item} />
|
||||
))}
|
||||
</ul>
|
||||
</OLRow>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThinFooter
|
||||
@@ -4,12 +4,13 @@ import {
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownToggle,
|
||||
DropdownHeader,
|
||||
} from './dropdown-menu'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getMeta from '@/utils/meta'
|
||||
import Icon from '@/shared/components/icon'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
|
||||
function LanguagePicker() {
|
||||
function LanguagePicker({ showHeader } = { showHeader: false }) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const currentLangCode = getMeta('ol-i18n').currentLangCode
|
||||
@@ -26,18 +27,18 @@ function LanguagePicker() {
|
||||
className="btn-inline-link"
|
||||
variant="link"
|
||||
>
|
||||
<Icon
|
||||
type="language"
|
||||
className="fa fa-fw"
|
||||
accessibilityLabel={t('select_a_language')}
|
||||
/>
|
||||
{translatedLanguages?.[currentLangCode]}
|
||||
<MaterialIcon type="translate" />
|
||||
|
||||
<span className="language-picker-text">
|
||||
{translatedLanguages?.[currentLangCode]}
|
||||
</span>
|
||||
</DropdownToggle>
|
||||
|
||||
<DropdownMenu
|
||||
className="dropdown-menu-sm-width"
|
||||
aria-labelledby="language-picker-toggle"
|
||||
>
|
||||
{showHeader ? <DropdownHeader>{t('language')}</DropdownHeader> : null}
|
||||
{subdomainLang &&
|
||||
Object.entries(subdomainLang).map(([subdomain, subdomainDetails]) => {
|
||||
if (
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { SubdomainLang } from '@/features/ui/components/types/fat-footer'
|
||||
|
||||
export type FatFooterMetadata = {
|
||||
subdomainLang?: SubdomainLang
|
||||
translatedLanguages: { [key: string]: string }
|
||||
currentLangCode: string
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { SubdomainLang } from '@/features/ui/components/types/fat-footer'
|
||||
|
||||
export type FooterItem = {
|
||||
text: string
|
||||
translatedText?: string
|
||||
url?: string
|
||||
class?: string
|
||||
label?: string
|
||||
}
|
||||
|
||||
export type FooterMetadata = {
|
||||
showThinFooter: boolean
|
||||
translatedLanguages: { [key: string]: string }
|
||||
showPoweredBy?: boolean
|
||||
subdomainLang?: SubdomainLang
|
||||
leftItems?: FooterItem[]
|
||||
rightItems?: FooterItem[]
|
||||
}
|
||||
@@ -49,7 +49,7 @@ import { ThirdPartyIds } from '../../../types/third-party-ids'
|
||||
import { Publisher } from '../../../types/subscription/dashboard/publisher'
|
||||
import { SubscriptionChangePreview } from '../../../types/subscription/subscription-change-preview'
|
||||
import { DefaultNavbarMetadata } from '@/features/ui/components/types/default-navbar-metadata'
|
||||
import { FatFooterMetadata } from '@/features/ui/components/types/fat-footer-metadata'
|
||||
import { FooterMetadata } from '@/features/ui/components/types/footer-metadata'
|
||||
export interface Meta {
|
||||
'ol-ExposedSettings': ExposedSettings
|
||||
'ol-allInReconfirmNotificationPeriods': UserEmailData[]
|
||||
@@ -89,7 +89,7 @@ export interface Meta {
|
||||
'ol-error': { name: string } | undefined
|
||||
'ol-expired': boolean
|
||||
'ol-features': Features
|
||||
'ol-footer': FatFooterMetadata
|
||||
'ol-footer': FooterMetadata
|
||||
'ol-fromPlansPage': boolean
|
||||
'ol-galleryTagName': string
|
||||
'ol-gitBridgeEnabled': boolean
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
// Footer
|
||||
$footer-height: 50px;
|
||||
|
||||
// Header
|
||||
$header-height: 68px;
|
||||
$toolbar-height: 40px;
|
||||
$toolbar-small-height: 32px;
|
||||
|
||||
// Footer
|
||||
$thin-footer-height: 50px;
|
||||
$fat-footer-content-height: calc(100vh - $header-height);
|
||||
$thin-footer-content-height: calc(
|
||||
100vh - ($header-height + $thin-footer-height)
|
||||
);
|
||||
|
||||
// List of allowed themes
|
||||
$themes: ('default', 'light');
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 100vh;
|
||||
padding-top: $header-height + $spacing-08;
|
||||
padding-bottom: $spacing-08;
|
||||
|
||||
.thin-footer & {
|
||||
min-height: calc(100vh - #{$thin-footer-height});
|
||||
}
|
||||
}
|
||||
|
||||
.content-alt {
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
--link-color-dark: var(--link-ui-dark);
|
||||
--link-hover-color-dark: var(--link-ui-hover-dark);
|
||||
--link-visited-color-dark: var(--link-ui-visited-dark);
|
||||
--link-text-decoration: underline;
|
||||
--link-hover-text-decoration: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-color);
|
||||
text-decoration: var(--link-text-decoration);
|
||||
|
||||
&:visited {
|
||||
color: var(--link-visited-color);
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
|
||||
// Make a button look and behave like a link
|
||||
.btn-link {
|
||||
color: var(--link-ui);
|
||||
color: var(--link-color);
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
@@ -156,7 +156,7 @@
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--link-ui-hover);
|
||||
color: var(--link-hover-color);
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
$dropdown-item-min-height: 36px;
|
||||
|
||||
.dropdown {
|
||||
display: inline-flex;
|
||||
|
||||
@@ -20,6 +22,9 @@
|
||||
.dropdown-header {
|
||||
@include body-xs;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: $dropdown-item-min-height; // a minimum height of 36px to be accessible for touch screens
|
||||
padding: var(--spacing-05) var(--spacing-06) var(--spacing-02)
|
||||
var(--spacing-04);
|
||||
}
|
||||
@@ -55,7 +60,7 @@
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
place-content: center start;
|
||||
min-height: 36px; // a minimum height of 36px to be accessible for touch screens
|
||||
min-height: $dropdown-item-min-height; // a minimum height of 36px to be accessible for touch screens
|
||||
position: relative;
|
||||
|
||||
&:active {
|
||||
|
||||
@@ -56,56 +56,33 @@ $footer-width-delta: 320px;
|
||||
}
|
||||
|
||||
footer.site-footer {
|
||||
--link-color: var(--link-web);
|
||||
--link-hover-color: var(--link-web-hover);
|
||||
--link-visited-color: var(--link-web-visited);
|
||||
--link-text-decoration: none;
|
||||
--link-hover-text-decoration: underline;
|
||||
|
||||
background-color: var(--bg-light-primary);
|
||||
border-top: 1px solid var(--border-primary-dark);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
|
||||
@include body-sm;
|
||||
|
||||
height: $footer-height;
|
||||
min-height: $thin-footer-height;
|
||||
line-height: $thin-footer-height - 1; // Hack — in Chrome, using the full $footer-height would generate vertical scrolling
|
||||
|
||||
ul {
|
||||
ul.site-footer-items {
|
||||
list-style: none;
|
||||
margin: var(--spacing-00);
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
> li {
|
||||
display: inline-block;
|
||||
margin: var(--spacing-07) var(--spacing-04);
|
||||
margin: 0 var(--spacing-04);
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: var(--font-size-05);
|
||||
}
|
||||
}
|
||||
|
||||
li.lng-option {
|
||||
text-align: left;
|
||||
display: list-item;
|
||||
|
||||
img {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: var(--content-primary-dark);
|
||||
|
||||
&:visited {
|
||||
color: var(--content-primary-dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--content-secondary-dark);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--content-secondary-dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.site-footer-content {
|
||||
@@ -117,7 +94,44 @@ footer.site-footer {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#language-picker-toggle {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.language-picker-text {
|
||||
text-decoration: var(--link-hover-text-decoration);
|
||||
}
|
||||
}
|
||||
|
||||
.material-symbols {
|
||||
vertical-align: -0.1875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.language-picker .dropdown-menu {
|
||||
.dropdown-item {
|
||||
&.active {
|
||||
color: var(--green-70);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fat-footer {
|
||||
--link-color: var(--content-secondary-dark);
|
||||
--link-hover-color: var(--content-secondary-dark);
|
||||
--link-visited-color: var(--content-secondary-dark);
|
||||
--link-text-decoration: none;
|
||||
--link-hover-text-decoration: underline;
|
||||
|
||||
container-name: fatfooter;
|
||||
container-type: inline-size;
|
||||
background: var(--bg-dark-primary);
|
||||
@@ -133,20 +147,6 @@ footer.site-footer {
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--content-secondary-dark);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--content-secondary-dark);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&:visited {
|
||||
color: var(--content-secondary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
.footer-brand-container {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -196,16 +196,6 @@ footer.site-footer {
|
||||
|
||||
#language-picker-toggle {
|
||||
color: var(--content-secondary-dark);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.fat-footer-base-meta a:not(.dropdown-toggle) {
|
||||
@@ -216,16 +206,6 @@ footer.site-footer {
|
||||
.dropdown-header {
|
||||
display: none; /* hiding rather than removing as still needed in the thin footer */
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
&.active {
|
||||
color: var(--green-70);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,17 +386,13 @@ footer.site-footer {
|
||||
}
|
||||
|
||||
&.fat-footer {
|
||||
--link-color: var(--content-primary);
|
||||
--link-hover-color: var(--content-primary);
|
||||
--link-visited-color: var(--content-primary);
|
||||
|
||||
background: var(--content-primary-dark);
|
||||
color: var(--content-primary);
|
||||
|
||||
a {
|
||||
color: var(--content-primary);
|
||||
|
||||
&:visited {
|
||||
color: var(--content-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.footer-section-heading {
|
||||
color: var(--content-primary);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
.project-list-react {
|
||||
--project-list-content-height: #{$fat-footer-content-height};
|
||||
|
||||
#project-list-root > &.content {
|
||||
padding-top: $header-height;
|
||||
padding-bottom: 0;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
min-height: var(--project-list-content-height);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.thin-footer & {
|
||||
--project-list-content-height: #{$thin-footer-content-height};
|
||||
}
|
||||
}
|
||||
|
||||
.project-list-wrapper {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
min-height: var(--project-list-content-height);
|
||||
}
|
||||
|
||||
.project-list-sidebar-wrapper-react {
|
||||
position: relative;
|
||||
background-color: var(--bg-dark-secondary);
|
||||
flex: 0 0 15%;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
min-height: var(--project-list-content-height);
|
||||
max-width: 320px;
|
||||
min-width: 200px;
|
||||
|
||||
@@ -121,7 +127,7 @@
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
min-height: var(--project-list-content-height);
|
||||
|
||||
.loading-screen-brand-container {
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -579,18 +579,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
|
||||
.loading-screen-brand-container {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.current-plan {
|
||||
|
||||
@@ -10,6 +10,7 @@ describe('LanguagePicker', function () {
|
||||
currentLangCode: 'en',
|
||||
})
|
||||
window.metaAttributesCache.set('ol-footer', {
|
||||
showThinFooter: false,
|
||||
translatedLanguages: {
|
||||
en: 'English',
|
||||
fr: 'Français',
|
||||
@@ -26,12 +27,12 @@ describe('LanguagePicker', function () {
|
||||
})
|
||||
|
||||
it('renders the language picker with the current language', function () {
|
||||
cy.mount(<LanguagePicker />)
|
||||
cy.mount(<LanguagePicker showHeader />)
|
||||
cy.get('#language-picker-toggle').should('contain', 'English')
|
||||
})
|
||||
|
||||
it('opens the dropdown and lists available languages', function () {
|
||||
cy.mount(<LanguagePicker />)
|
||||
cy.mount(<LanguagePicker showHeader />)
|
||||
cy.get('#language-picker-toggle').click()
|
||||
|
||||
cy.get('.dropdown-menu').within(() => {
|
||||
@@ -42,7 +43,7 @@ describe('LanguagePicker', function () {
|
||||
})
|
||||
|
||||
it('changes the language and updates the URL when a language is selected', function () {
|
||||
cy.mount(<LanguagePicker />)
|
||||
cy.mount(<LanguagePicker showHeader />)
|
||||
cy.get('#language-picker-toggle').should('exist').click()
|
||||
cy.contains('Français').click()
|
||||
cy.url().should('include', 'fr.overleaf.com')
|
||||
|
||||
@@ -55,6 +55,7 @@ describe('<ProjectListRoot />', function () {
|
||||
window.metaAttributesCache.set('ol-user', {})
|
||||
window.metaAttributesCache.set('ol-user_id', userId)
|
||||
window.metaAttributesCache.set('ol-footer', {
|
||||
showThinFooter: false,
|
||||
translatedLanguages: { en: 'English' },
|
||||
subdomainLang: { en: { lngCode: 'en', url: 'overleaf.com' } },
|
||||
})
|
||||
|
||||
+1
@@ -65,6 +65,7 @@ describe('<ProjectTools />', function () {
|
||||
})
|
||||
|
||||
window.metaAttributesCache.set('ol-footer', {
|
||||
showThinFooter: false,
|
||||
translatedLanguages: { en: 'English' },
|
||||
subdomainLang: { en: { lngCode: 'en', url: 'overleaf.com' } },
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user