Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cc0eab9
fix authentication
arybakov05 Oct 25, 2025
b6e7e18
restructured header tools slots
arybakov05 Oct 25, 2025
e161a9a
added HeaderTools sub-slots
arybakov05 Oct 25, 2025
56be089
Merge branch 'seven' into 6673-seven-header-slots
arybakov05 Oct 26, 2025
0fa2701
Merge branch 'seven' into 6673-seven-header-slots
avoinea Oct 28, 2025
51e1d42
added missing news
arybakov05 Oct 28, 2025
17d2fe3
Merge remote-tracking branch 'origin/6673-seven-header-slots' into 66…
arybakov05 Oct 28, 2025
450f4a7
Merge branch 'seven' into 6673-seven-header-slots
arybakov05 Mar 16, 2026
20d42b1
Merge branch 'seven' into 6673-seven-header-slots
arybakov05 Mar 18, 2026
eebdf1b
merge seven into 6673-seven-header-slots
arybakov05 Mar 18, 2026
7802977
added missing news
arybakov05 Mar 18, 2026
52e0c1f
Merge branch 'seven' into 6673-seven-header-slots
arybakov05 May 18, 2026
987c129
clean up after merge conflicts, replace search svg with icon
arybakov05 May 18, 2026
31eaa9d
fix prettier
arybakov05 May 18, 2026
44f8b98
use user from context instead of token
arybakov05 May 18, 2026
3f1c00b
Merge branch 'seven' into 6673-seven-header-slots
arybakov05 May 20, 2026
f4f55bf
remove unnecessary `flattenToAppURL` call
arybakov05 May 20, 2026
2481490
use native form behavior for search widget
arybakov05 May 20, 2026
882e040
rename slots
arybakov05 May 20, 2026
78d467c
Merge branch 'seven' into 6673-seven-header-slots
arybakov05 May 22, 2026
8b114f9
Merge seven into 66673-seven-header-slots
arybakov05 May 22, 2026
c265832
move styles from header.css to the correct modules
arybakov05 May 22, 2026
2c5cafb
remove space from language switcher slot name
arybakov05 May 22, 2026
7263e85
Merge branch 'refs/heads/seven' into 6673-seven-header-slots
arybakov05 May 22, 2026
5b9ab13
rename siteActions locale to actions, update pnpm-lock file
arybakov05 May 22, 2026
e45f43a
Merge branch 'seven' into 6673-seven-header-slots
arybakov05 May 22, 2026
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
1 change: 1 addition & 0 deletions apps/seven/news/6673.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Include `isAuthenticated` boolean in root loader data. @arybakov05
33 changes: 27 additions & 6 deletions packages/layout/config/slots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import Footer from '../slots/Footer';
import Logo from '../slots/Logo/Logo';
import LanguageSwitcher from '../slots/LanguageSwitcher/LanguageSwitcher';
import Navigation from '../slots/Navigation/Navigation';
import HeaderTools from '../slots/Tools';
import ContentArea from '../slots/ContentArea';
import MainFooter from '../slots/MainFooter/MainFooter';
import Breadcrumbs from '../slots/Breadcrumbs';
import { NotContentTypeCondition } from '../helpers';
import AnonymousTools from '../slots/HeaderTools/AnonymousTools';
import HeaderTools from '../slots/HeaderTools/HeaderTools';
import SearchWidget from '../slots/HeaderTools/SearchWidget';
import Actions from '../slots/HeaderTools/Actions';

export default function install(config: ConfigType) {
// Main App Slot
Expand All @@ -36,16 +39,34 @@ export default function install(config: ConfigType) {
component: Navigation,
});

// Tools
// Header Tools
config.registerSlotComponent({
name: 'Tools',
slot: 'headertools',
name: 'HeaderTools',
slot: 'headerTools',
component: HeaderTools,
});

config.registerSlotComponent({
name: 'Language Switcher',
slot: 'language-switcher',
name: 'Actions',
slot: 'actions',
component: Actions,
});
Comment thread
pnicolli marked this conversation as resolved.

config.registerSlotComponent({
name: 'AnonymousTools',
slot: 'anonymousTools',
component: AnonymousTools,
});

config.registerSlotComponent({
name: 'SearchWidget',
slot: 'searchWidget',
component: SearchWidget,
});

config.registerSlotComponent({
name: 'LanguageSwitcher',
slot: 'languageSwitcher',
component: LanguageSwitcher,
});

Expand Down
18 changes: 16 additions & 2 deletions packages/layout/locales/de/common.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
{
"layout": {
"languageSwitcher": {
"switchTo": "Zu {{ lang }} wechseln"
"slots": {
"tools": {
"languageSwitcher": {
"switchTo": "Zu {{ lang }} wechseln"
},
"actions": {
"logout": "Abmelden"
},
"anonymousTools": {
"login": "Anmelden",
"register": "Registrieren"
},
"searchwidget": {
"searchSite": "Seite durchsuchen"
}
}
},
"contenttypes": {
"common": {
Expand Down
18 changes: 16 additions & 2 deletions packages/layout/locales/en/common.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
{
"layout": {
"languageSwitcher": {
"switchTo": "Switch to {{ lang }}"
"slots": {
"tools": {
"languageSwitcher": {
"switchTo": "Switch to {{ lang }}"
},
"actions": {
"logout": "Log Out"
},
"anonymousTools": {
"login": "Log In",
"register": "Register"
},
"searchWidget": {
"searchSite": "Search site"
}
}
},
"contenttypes": {
"common": {
Expand Down
18 changes: 16 additions & 2 deletions packages/layout/locales/it/common.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
{
"layout": {
"languageSwitcher": {
"switchTo": "Passa a {{ lang }}"
"slots": {
"tools": {
"languageSwitcher": {
"switchTo": "Passa a {{ lang }}"
},
"actions": {
"logout": "Disconnetti"
},
"anonymousTools": {
"login": "Accedi",
"register": "Registrati"
},
"searchWidget": {
"searchSite": "Cerca nel sito"
}
}
},
"contenttypes": {
"common": {
Expand Down
1 change: 1 addition & 0 deletions packages/layout/news/6673.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added search widget and header sub-slots. @arybakov05
4 changes: 2 additions & 2 deletions packages/layout/slots/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Breadcrumbs = (props: SlotComponentProps) => {
icon: <HomeIcon size="sm" />,
};

const breacrumbs = [rootItem, ...(items || [])];
const breadcrumbs = [rootItem, ...(items || [])];

return (
<SectionWrapper
Expand All @@ -26,7 +26,7 @@ const Breadcrumbs = (props: SlotComponentProps) => {
width="layout"
className="breadcrumbs"
>
<PCBreadcrumbs items={breacrumbs}>
<PCBreadcrumbs items={breadcrumbs}>
{(item) => (
<PCBreadcrumb id={item['@id']} href={item['@id']}>
{item.title}
Expand Down
55 changes: 44 additions & 11 deletions packages/layout/slots/Header/Header.module.css
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
@layer custom {
/* .header-wrapper {
display: flex;
flex-direction: row;
align-items: baseline;
justify-content: space-between;
padding-top: 25px;
padding-bottom: 35px;
} */
.header-wrapper {
:global(.section-inner-container) {
align-items: center;
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);

/* Place the three direct children: logo, navigation, header tools */
> :nth-child(1) {
/* logo slot */
grid-column: 1;
justify-self: start;
}
> :nth-child(2) {
/* navigation slot */
grid-column: 2;
justify-self: center; /* ensure centering within the middle column */
}
> :nth-child(3) {
/* header tools slot */
grid-column: 3;
justify-self: end;
}
}

:global(.header-logo-nav-tools-wrapper) {
--grid-auto-flow: column;
}

:global(.breadcrumbs) {
ol {
display: grid;
gap: 0.5rem;
grid-auto-flow: column;
list-style-type: none;

li {
display: flex;
align-items: end;
}
}
}
}

.header-tools {
display: flex;
flex: 1 1 0;
flex-direction: row-reverse;
display: inline-flex;
align-items: center;
Comment thread
pnicolli marked this conversation as resolved.
gap: 0.5rem;
}
}
7 changes: 1 addition & 6 deletions packages/layout/slots/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,7 @@ const Header = (props: HeaderProps) => {
<SlotRenderer name="navigation" content={content} location={location} />
<div className={clsx(styles['header-tools'], 'header-tools')}>
<SlotRenderer
name="headertools"
content={content}
location={location}
/>
<SlotRenderer
name="language-switcher"
name="headerTools"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok on doing this, and move it inside the tools.

content={content}
location={location}
/>
Expand Down
10 changes: 10 additions & 0 deletions packages/layout/slots/HeaderTools/Actions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Link } from '@plone/components';
import { useTranslation } from 'react-i18next';

const Actions = () => {
const { t } = useTranslation();

return <Link href="/logout">{t('layout.slots.tools.actions.logout')}</Link>;
};

export default Actions;
29 changes: 29 additions & 0 deletions packages/layout/slots/HeaderTools/AnonymousTools.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import clsx from 'clsx';
import type { SlotComponentProps } from '../SlotRenderer';
import { useTranslation } from 'react-i18next';
import { Link } from '@plone/components';
import config from '@plone/registry';
import styles from './Tools.module.css';

const AnonymousTools = (props: SlotComponentProps) => {
const { content } = props;
const { t } = useTranslation();

const returnUrl = content['@id'];
const hasReturnUrl = returnUrl !== '' && returnUrl !== '/';

return (
<div className={clsx(styles['anonymoustools'], 'anonymoustools')}>
<Link href={`/login${hasReturnUrl ? `?return_url=${returnUrl}` : ''}`}>
{t('layout.slots.tools.anonymousTools.login')}
</Link>
{config.settings.showSelfRegistration && (
<Link href="/register">
{t('layout.slots.tools.anonymousTools.register')}
</Link>
)}
</div>
);
};

export default AnonymousTools;
36 changes: 36 additions & 0 deletions packages/layout/slots/HeaderTools/HeaderTools.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import SlotRenderer, { type SlotComponentProps } from '../SlotRenderer';
import { useRouteLoaderData } from 'react-router';
import type { RootLoader } from 'seven/app/root';

const HeaderTools = (props: SlotComponentProps) => {
const rootData = useRouteLoaderData<RootLoader>('root');

if (!rootData) {
return null;
}

const { isAuthenticated } = rootData;
const { content, location } = props;

return (
<>
{isAuthenticated ? (
<SlotRenderer name="actions" content={content} location={location} />
) : (
<SlotRenderer
name="anonymousTools"
content={content}
location={location}
/>
)}
<SlotRenderer
name="languageSwitcher"
content={content}
location={location}
/>
<SlotRenderer name="searchWidget" content={content} location={location} />
</>
);
};

export default HeaderTools;
39 changes: 39 additions & 0 deletions packages/layout/slots/HeaderTools/SearchWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Form, Input, Label, TextField } from 'react-aria-components';
import type { SlotComponentProps } from '../SlotRenderer';
import { useTranslation } from 'react-i18next';
import { Button } from '@plone/components';
import Search from '@plone/components/icons/search.svg?react';
import styles from './Tools.module.css';
import clsx from 'clsx';

const SearchWidget = (props: SlotComponentProps) => {
const { location } = props;

const { t } = useTranslation();
const pathname = location.pathname;
const hasPath = pathname?.length > 0 && pathname !== '/';

return (
<Form
className={clsx(styles['searchwidget'], 'searchwidget')}
action="/search"
method="get"
>
Comment thread
pnicolli marked this conversation as resolved.
<TextField name="search" type="text">
<Label className="sr-only">
{t('layout.slots.tools.searchWidget.searchSite')}
</Label>
<Input
name="SearchableText"
placeholder={t('layout.slots.tools.searchWidget.searchSite')}
/>
{hasPath && <input type="hidden" name="path" value={pathname} />}
</TextField>
<Button type="submit">
<Search />
</Button>
</Form>
);
};

export default SearchWidget;
53 changes: 53 additions & 0 deletions packages/layout/slots/HeaderTools/Tools.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@layer custom {
.anonymoustools {
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
}

.searchwidget {
display: flex;
flex-direction: row-reverse;
border: 2px solid transparent;
border-radius: 8px;
gap: 2px;

&:focus-within,
&:hover {
border: 2px solid var(--border);
}

input {
max-width: 200px;
height: 100%;
padding: 2px 8px;
border-radius: 0 8px 8px 0;
border-left: 2px solid transparent;

&:focus-visible {
outline: 2px solid var(--quanta-cobalt);
}
}

button {
box-sizing: content-box;
padding: 8px;
border-radius: 8px 0 0 8px;
background-color: transparent;

&:hover {
cursor: pointer;
}

&:focus {
outline: 2px solid var(--quanta-cobalt);
outline-offset: 0;
}

svg {
opacity: 0.7;
}
}
}
}
Loading
Loading