diff --git a/docs/conf.py b/docs/conf.py index b97b86106..741c82bd6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,6 +6,8 @@ from datetime import datetime +suppress_warnings = ["misc.highlighting_failure"] + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. diff --git a/docs/customizing-volto-light-theme/advanced-components-bm3.md b/docs/customizing-volto-light-theme/advanced-components-bm3.md new file mode 100644 index 000000000..c463e6936 --- /dev/null +++ b/docs/customizing-volto-light-theme/advanced-components-bm3.md @@ -0,0 +1,829 @@ +--- +myst: + html_meta: + "description": "Advanced Components, Site Customization & Block Model v3" + "property=og:description": "Advanced Components, Site Customization & Block Model v3" + "property=og:title": "Advanced Components, Site Customization & Block Model v3" + "keywords": "Plone, Volto, Training, Volto Light Theme, Integrate, block" +--- + +# Advanced Components, Site Customization & Block Model v3 + +## Understanding the Card Primitive + +The Card primitive is VLT's reusable component for displaying content in card layouts. It has three configurable slots: image, summary, and actions. + +### Card Structure + +```jsx + + + +

Title

+

Summary text goes here.

+
+ + + +
+``` + +### Card Variations + +- **Vertical layout** (default): Image on top +- **Horizontal layout**: Image on left or right +- **Contained**: With background color from theme +- **Listing**: Image displayed on left with specific size (controlled by `--card-listing-image-size`, default 220px) + +### Card.Image Slot + +Display an image using a `src` prop or use a Plone image object: + +```tsx + +``` + +Custom image component: + +```tsx + +``` + +### Card.Summary Slot + +Recommended structure using VLT's Summary component: + +```tsx +import DefaultSummary from '@kitconcept/volto-light-theme/components/Summary/DefaultSummary'; + +const Summary = config.getComponent({ + name: 'Summary', + dependencies: [item['@type']], +}).component || DefaultSummary; + + + + +``` + +## Creating Custom Summary Components + +The Summary component displays content metadata in listings, teasers, and cards. VLT includes built-in implementations: + +- `DefaultSummary`: Kicker, title, and description +- `NewsItemSummary`: Publication date, kicker, title, description +- `EventSummary`: Start/end date, kicker, title, description +- `FileSummary`: File size and type + +### Step 1: Create Product Content Type + +First, create a custom "Product" content type through the Plone UI: + +1. Go to http://localhost:3000/controlpanel/dexterity-types +2. Click "Add New Content Type" +3. Fill in: + - **Type Name**: Product + - **Short Name**: product (auto-filled) + - **Description**: A product with pricing information +4. Click "Add" +5. In the "Behaviors" tab, enable: + - "Kicker" (we'll use this field to store the price) + - "Preview image" + - Any other desired behaviors (Dublin Core, etc.) +6. Click "Save" + +### Step 2: Create a Custom Summary Component + +Create `src/components/Summary/ProductSummary.tsx`: + +```tsx +import { FormattedNumber } from 'react-intl'; + +const ProductSummary = ({ item }) => { + const { + title, + description, + HeadingTag = 'h3', + head_title, + currency = 'EUR', + } = item; + const price = parseFloat(head_title); + + return ( + <> + + {title ? title : item.id} + + {description &&

{description}

} + {head_title && !isNaN(price) && ( +
+ + + +
+ )} + + ); +}; + +ProductSummary.hideLink = false; +export default ProductSummary; +``` + +**Note**: We use the `head_title` field (kicker) to store price information. The price is formatted using `FormattedNumber` for proper currency display with EUR as default. In a real project, you would create custom fields for price and currency. + +### Step 3: Add Styles for Product Summary + +Create `src/theme/_productSummary.scss`: + +```scss +.products .card .card-summary { + padding-bottom: 0 !important; + .product-price { + font-size: 1.25rem; + color: var(--accent-color); + margin-top: 0.5rem; + + .price { + background: var(--theme-high-contrast-color); + padding: 0.25rem 0.75rem; + border-radius: 4px; + } + } + + .product-title { + margin-top: 0; + } +} +``` + +Import in `src/theme/_main.scss`: + +```scss +@import './blocks/hero'; +@import './blocks/relatedItems'; +@import './productSummary'; +@import './site'; +``` + +### Step 4: Register the Summary Component + +In `src/config/settings.ts`: + +```typescript +import ProductSummary from '../components/Summary/ProductSummary'; + +export default function install(config: ConfigType) { + // ... previous config ... + + config.registerComponent({ + name: 'Summary', + component: ProductSummary, + dependencies: ['product'], + }); + + return config; +} +``` + +### Step 5: Test the Product Summary + +1. Create a Product item in your site +2. Fill in the title, description, and kicker field (e.g., "$99.99") +3. Add the Product to a Listing or Teaser block +4. The custom ProductSummary will display the price, title, and description + +## Creating Custom Listing Variations with Card Actions + +Listing variations customize content display in Listing blocks. Let's create a ProductTemplate demonstrating the Card.Actions slot for interactive buttons. + +### Card.Actions Slot + +The Card.Actions slot provides interactive elements beyond the main card link: +- "Add to Cart" or "Get Now" buttons for products +- "Download" buttons for files +- "Register" buttons for events + +### Step 1: Create ProductActions Component + +Create `src/components/Actions/ProductActions.tsx`: + +```tsx +const ProductActions = ({ item }) => { + return ( + <> + + + ); +}; + +export default ProductActions; +``` + +### Step 2: Register ProductActions + +Update `src/config/settings.ts`: + +```typescript +import ProductActions from '../components/Actions/ProductActions'; + +export default function install(config: ConfigType) { + // ... previous configuration ... + + // Register ProductActions component + config.registerComponent({ + name: 'Actions', + component: ProductActions, + dependencies: ['product'], + }); + + return config; +} +``` + +### Step 3: Create ProductTemplate Listing Variation + +Create `src/components/blocks/Listing/ProductTemplate.tsx`: + +```tsx +import React from 'react'; +import PropTypes from 'prop-types'; +import ConditionalLink from '@plone/volto/components/manage/ConditionalLink/ConditionalLink'; +import Card from '@kitconcept/volto-light-theme/primitives/Card/Card'; +import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers/Url/Url'; +import config from '@plone/volto/registry'; +import DefaultSummary from '@kitconcept/volto-light-theme/components/Summary/DefaultSummary'; +import cx from 'classnames'; + +const ProductTemplate = ({ items, linkTitle, linkHref, isEditMode }) => { + let link = null; + let href = linkHref?.[0]?.['@id'] || ''; + const PreviewImageComponent = config.getComponent('PreviewImage').component; + + if (isInternalURL(href)) { + link = ( + + {linkTitle || href} + + ); + } else if (href) { + link = {linkTitle || href}; + } + + return ( + <> +
+ {items.map((item) => { + const Summary = + config.getComponent({ + name: 'Summary', + dependencies: [item['@type']], + }).component || DefaultSummary; + + const Actions = config.getComponent({ + name: 'Actions', + dependencies: [item['@type']], + }).component; + + const showLink = !Summary.hideLink && !isEditMode; + + return ( +
+ + {item.image_field !== '' && ( + + )} + + + + + {Actions && } + + +
+ ); + })} +
+ + {link &&
{link}
} + + ); +}; + +ProductTemplate.propTypes = { + items: PropTypes.arrayOf(PropTypes.any).isRequired, + linkTitle: PropTypes.string, + linkHref: PropTypes.any, + isEditMode: PropTypes.bool, +}; + +export default ProductTemplate; +``` + +**Key Features:** +- Uses `config.getComponent()` to fetch registered Summary/Actions components by content type +- `showLink` ensures cards are only clickable when appropriate +- `isEditMode` disables navigation during editing +- Dynamically renders Actions only for content types that have them registered + +### Step 4: Register ProductTemplate + +Update `src/config/blocks.ts`: + +```typescript +import ProductTemplate from '../components/blocks/Listing/ProductTemplate'; + +export default function install(config: ConfigType) { + // ... previous configuration ... + + // Register ProductTemplate listing variation + config.blocks.blocksConfig.listing.variations = [ + ...(config.blocks.blocksConfig.listing.variations || []), + { + id: 'products', + title: 'Products', + template: ProductTemplate, + }, + ]; + + return config; +} +``` + +### Step 5: Add Styles + +Create `src/theme/blocks/_listing.scss`: + +```scss +.block.listing { + &.products { + max-width: var(--default-container-width) !important; + &.next--has--same--backgroundColor.next--is--same--block-type, + &.next--is--__button { + .listing-item:last-child { + padding-bottom: 0 !important; + border-bottom: none !important; + } + } + + .items { + display: flex; + flex-wrap: wrap; + @media only screen and (max-width: $largest-mobile-screen) { + flex-direction: column; + + .listing-item { + padding-bottom: 20px !important; + } + } + } + .headline { + @include block-title(); + margin-right: 0 !important; + margin-left: 0 !important; + } + .listing-item { + align-items: normal; + border-bottom: none; + margin: 0 !important; + + @media only screen and (min-width: $tablet-breakpoint) { + width: 50%; + padding-top: 10px; + padding-bottom: 10px !important; + + &:nth-child(2n) { + padding-left: 10px !important; + } + + &:nth-child(2n + 1) { + padding-right: 10px !important; + } + + &:last-child, + &:nth-last-child(2):not(:nth-child(2n)) { + padding-bottom: 0 !important; + } + + &:first-child, + &:nth-child(2) { + padding-top: 0 !important; + } + } + + &:last-child:nth-child(2n + 1) { + @media only screen and (min-width: $largest-mobile-screen) { + margin-left: 0 !important; + } + } + + .card { + flex-grow: 1; + .card-inner { + background: var(--theme-high-contrast-color); + .image-wrapper { + img { + width: 100%; + margin: 0; + aspect-ratio: var(--image-aspect-ratio, $aspect-ratio) !important; + } + } + .card-summary { + padding: 0 $spacing-large $spacing-large $spacing-large; + margin-top: $spacing-medium; + + .headline { + padding: 0 !important; + margin-bottom: $spacing-small; + letter-spacing: 1px; + text-transform: uppercase; + @include headtitle1(); + @include word-break(); + } + + h2 { + margin: 0 0 $spacing-small 0; + @include text-heading-h3(); + } + p { + margin-bottom: 0; + @include body-text(); + } + p:empty { + display: none; + } + } + + .product-price { + display: flex; + justify-content: end; + padding: $spacing-small; + + .price { + font-size: 2.5rem; + width: 30%; + } + } + } + + .actions-wrapper { + display: flex; + justify-content: end; + padding: 0 $spacing-large $spacing-medium $spacing-large; + .rent-now-button { + width: 30%; + padding: 0.75rem 1rem; + margin: 1rem; + background-color: var(--accent-color); + color: white; + border: none; + cursor: pointer; + transition: opacity 0.2s; + + &:hover { + opacity: 0.9; + } + } + } + } + } + } +} +``` + +Import in `src/theme/_main.scss`: + +```scss +@import './blocks/hero'; +@import './blocks/relatedItems'; +@import './blocks/listing'; +@import './productSummary'; +@import './site'; +``` + +### Step 6: Test the Product Listing + +1. Create Product items with title, description, kicker (price), and images +2. Add a Listing block to a page +3. Select "Products" variation in block settings +4. Configure to show Product content type +5. Products display with image, summary, and "Get now" button + +## Working with Slots + +VLT provides slots for extending the layout without component shadowing. Let's create a practical example: a newsletter signup component in the preFooter slot. + +### Available Slots + +- `aboveHeader`: Content above header +- `belowHeader`: Content below header +- `headerTools`: Header tools at top-right (includes Anontools by default) +- `preFooter`: Before footer +- `postFooter`: After footer +- `footer`: Main footer area +- `footerLinks`: Footer links section +- `followUs`: Social media section + +### Step 1: Create Newsletter Signup Component + +Create `src/components/NewsletterSignup/NewsletterSignup.tsx`: + +```tsx +import React, { useState } from 'react'; + +const NewsletterSignup = () => { + const [email, setEmail] = useState(''); + + const handleSubmit = (e) => { + e.preventDefault(); + // In a real implementation, this would submit to a newsletter service + console.log('Newsletter signup:', email); + alert(`Thanks for signing up with ${email}!`); + setEmail(''); + }; + + return ( +
+
+

Stay Updated

+

+ Subscribe to our newsletter for the latest updates and news. +

+
+ setEmail(e.target.value)} + placeholder="Enter your email" + required + className="newsletter-input" + /> + +
+
+
+ ); +}; + +export default NewsletterSignup; +``` + +### Step 2: Add Styles + +Create `src/theme/_newsletterSignup.scss`: + +```scss +.newsletter-signup { + background-color: var(--secondary-color); + color: var(--secondary-foreground-color); + padding: 4rem 2rem; + + .newsletter-container { + max-width: var(--default-container-width); + margin: 0 auto; + text-align: center; + } + + .newsletter-title { + font-size: 2rem; + margin-bottom: 1rem; + } + + .newsletter-description { + font-size: 1.125rem; + margin-bottom: 2rem; + opacity: 0.9; + } + + .newsletter-form { + display: flex; + gap: 1rem; + max-width: 500px; + margin: 0 auto; + flex-wrap: wrap; + justify-content: center; + + .newsletter-input { + flex: 1; + min-width: 250px; + padding: 0.75rem 1rem; + border: 1px solid var(--secondary-foreground-color); + font-size: 1rem; + background-color: var(--primary-color); + color: var(--primary-foreground-color); + + &:focus { + outline: 2px solid var(--accent-color); + outline-offset: 2px; + } + } + + .newsletter-button { + padding: 0.75rem 2rem; + background-color: var(--accent-color); + color: var(--accent-foreground-color); + border: none; + font-size: 1rem; + cursor: pointer; + transition: opacity 0.2s; + + &:hover { + opacity: 0.9; + } + + &:focus { + outline: 2px solid var(--accent-foreground-color); + outline-offset: 2px; + } + } + } +} +``` + +Import in `src/theme/_main.scss`: + +```scss +@import './blocks/hero'; +@import './blocks/relatedItems'; +@import './blocks/listing'; +@import './productSummary'; +@import './site'; +@import './newsletterSignup'; +``` + +### Step 3: Register the Component to the Slot + +In `src/config/settings.ts`: + +```typescript +import NewsletterSignup from '../components/NewsletterSignup/NewsletterSignup'; + +export default function install(config: ConfigType) { + // ... previous config ... + + config.registerSlotComponent({ + name: 'NewsletterSignup', + slot: 'preFooter', + component: NewsletterSignup, + }); + + return config; +} +``` + +The newsletter signup component will now appear before the footer on all pages, demonstrating how slots enable you to extend the layout without shadowing core components. + +## Site Customization Behaviors + +VLT provides backend behaviors for site customization that you activated earlier. These behaviors enable fields for customizing the site without code changes. + +### Header Customization Options + +Through the Plone UI, you can customize: +- **Site logo**: Main logo in the top left +- **Complementary logo**: Second logo on the right side +- **Fat menu**: Enabled by default, can be disabled +- **Intranet header**: Alternative header for intranet sites +- **Actions**: Links at the top right + +### Theme Customization Options + +- Navigation text color +- Fat menu and breadcrumbs text color +- Fat menu background color +- Footer font color +- Footer background color + +### Footer Customization Options + +- **Footer links**: Additional links with title, URL, and new tab option +- **Footer logos**: List of logos with links and customizable size (small/large) and container width (default/layout) +- **Footer colophon text**: Customizable last line of footer + +## Block Model v3 (opt-in) + +```{note} +Block Model v3 is a beta feature. It's recommended to only use it when all blocks in your registry are v3-compatible (indicated by banner in block's GitHub repository). +``` + +Block Model v3 introduces a unified container architecture that ensures consistent styling and spacing between View and Edit modes. This eliminates the previous issues where Edit mode appeared different from View mode. + +### Key Benefits + +- Consistent rendering across View and Edit modes +- Simplified CSS with standardized container structure +- Improved spacing control through block categories +- Reduced maintenance overhead + +### The Two-Container System + +Every block in Block Model v3 follows this structure: + +``` +┌────────────────────────────────────────────────────────────┐ +│ Main/Outer Container (.block.${type}.category-${category}) │ +│ • Full width (edge to edge) │ +│ • Background color & theme variables │ +│ • Vertical spacing via padding on BG color changes │ +│ │ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ Secondary/Inner Container (.block-inner-container) │ │ +│ │ • Content width & horizontal centering │ │ +│ │ • Default vertical spacing between blocks │ │ +│ │ • Content alignment via CSS Grid │ │ +│ │ │ │ +│ │ [Block Content Here] │ │ +│ │ │ │ +│ └───────────────────────────────────────────────────────┘ │ +└────────────────────────────────────────────────────────────┘ +``` + +**Main/Outer Container:** +- Full width (extends edge to edge) +- Handles background colors and theme variables +- Uses padding (not margin) for vertical spacing +- CSS Classes: `.block.${type}.category-${category}` + +**Secondary/Inner Container:** +- Controls content width constraints +- Provides consistent inter-block spacing +- Supports content alignment through CSS Grid +- CSS Class: `.block-inner-container` + +### Enable Block Model v3 + +In your project's `src/config/settings.ts`: + +```typescript +export default function install(config: ConfigType) { + // Enable Block Model v3 + config.settings.blockModel = 3; + config.blocks.blocksConfig.slate.blockModel = config.settings.blockModel; + config.blocks.blocksConfig.title.blockModel = config.settings.blockModel; + config.blocks.blocksConfig.__button.blockModel = config.settings.blockModel; + // Define block categories for spacing + config.blocks.blocksConfig.slate.category = 'inline'; + config.blocks.blocksConfig.title.category = 'title'; + config.blocks.blocksConfig.__button.category = 'action'; + + return config; +} +``` + +### Block Categories + +Block categories determine spacing relationships between adjacent blocks. Categories are available at `config.blocks.blocksConfig.[$type].category`. + +Vertical spacing between blocks is provided by the **upper block**: +- Block content should be flush with top of container +- Bottom padding creates space for following block +- Different category combinations may have specific spacing adjustments + +### View Mode Structure + +```tsx +
+
+ {View component} +
+
+``` + +### Edit Mode Structure + +```tsx +
+
+ {Edit component} +
+
+ {/* Delete block button, move block buttons, etc. */} +
+
+``` + +Notice how the actual block content remains identical in both modes, while the framework containers handle all the differences in layout and editing functionality. \ No newline at end of file diff --git a/docs/customizing-volto-light-theme/block-development-widgets.md b/docs/customizing-volto-light-theme/block-development-widgets.md new file mode 100644 index 000000000..cc5016326 --- /dev/null +++ b/docs/customizing-volto-light-theme/block-development-widgets.md @@ -0,0 +1,631 @@ +--- +myst: + html_meta: + "description": "Block Development, Widgets & Integration" + "property=og:description": "Block Development, Widgets & Integration" + "property=og:title": "Block Development, Widgets & Integration" + "keywords": "Plone, Volto, Training, Volto Light Theme" +--- + +# Block Development, Widgets & Integration + +## Understanding VLT Widgets + +VLT provides powerful widgets for block configuration that work with the StyleWrapper system. + +### BlockWidth Widget + +Controls the content width of blocks: + +```javascript +{ + widget: 'blockWidth', + title: 'Block Width', + default: 'default', +} +``` + +### BlockAlignment Widget + +Controls content alignment within blocks: + +```javascript +{ + widget: 'blockAlignment', + title: 'Alignment', + default: 'center', +} +``` + +### ThemeColorSwatch Widget + +Allows selection from configured themes stored in `config.blocks.themes`: + +```javascript +{ + widget: 'themeColorSwatch', + title: 'Color Theme', + colors: config.blocks.themes, +} +``` + +### ObjectList Widget + +Allows introducing a list of ordered objects with drag and drop: + +```javascript +{ + widget: 'object_list', + title: 'Items', + schemaName: 'mySchemaName', +} +``` + +## Creating a Custom Hero Block + +Let's build a hero block step by step, starting with a basic implementation and then enhancing it with VLT widgets. + +### Step 1: Create Basic Block Schema + +Create `src/components/blocks/myHero/schema.ts`: + +```javascript +import { defineMessages } from 'react-intl'; + +const messages = defineMessages({ + hero: { + id: 'Hero', + defaultMessage: 'Hero', + }, + title: { + id: 'Title', + defaultMessage: 'Title', + }, + subtitle: { + id: 'Subtitle', + defaultMessage: 'Subtitle', + }, + backgroundImage: { + id: 'Background Image', + defaultMessage: 'Background Image', + }, +}); + +const heroBlockSchema = (props) => { + const { intl } = props; + + return { + title: intl.formatMessage(messages.hero), + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['title', 'subtitle'], + }, + { + id: 'design', + title: 'Design', + fields: ['backgroundImage'], + }, + ], + properties: { + title: { + title: intl.formatMessage(messages.title), + type: 'string', + }, + subtitle: { + title: intl.formatMessage(messages.subtitle), + type: 'string', + }, + backgroundImage: { + title: intl.formatMessage(messages.backgroundImage), + widget: 'object_browser', + mode: 'image', + allowExternals: false, + }, + }, + required: [], + }; +}; + +export { heroBlockSchema }; +``` + +### Step 2: Create View Component + +Create `src/components/blocks/myHero/View.tsx`: + +```tsx +import React from 'react'; +import cx from 'classnames'; +import config from '@plone/volto/registry'; +import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers/Url/Url'; +import type { BlockViewProps } from '@plone/types'; + +const HeroView = (props: BlockViewProps) => { + const { className, style } = props; + const { title, subtitle, backgroundImage, url } = props?.data || {}; + + const hasImage = backgroundImage?.[0]?.['@id']; + + let renderedImage = null; + if (hasImage) { + const Image = config.getComponent('Image').component; + const imageItem = backgroundImage[0]; + + if (Image) { + renderedImage = ( + + ); + } else { + renderedImage = ( + + ); + } + } + + return ( +
+ {hasImage &&
{renderedImage}
} + +
+
+ {title &&

{title}

} + {subtitle &&

{subtitle}

} +
+
+
+ ); +}; + +export default HeroView; +``` + +### Step 3: Create Edit Component + +Create `src/components/blocks/myHero/Edit.tsx`: + +```tsx +import React from 'react'; +import { useIntl } from 'react-intl'; +import SidebarPortal from '@plone/volto/components/manage/Sidebar/SidebarPortal'; +import { BlockDataForm } from '@plone/volto/components/manage/Form'; +import { heroBlockSchema } from './schema'; +import HeroView from './View'; +import type { BlockEditProps } from '@plone/types'; + +const HeroEdit = (props: BlockEditProps) => { + const { selected, onChangeBlock, block, data } = props; + const intl = useIntl(); + + return ( + <> + + + { + onChangeBlock(block, { + ...data, + [id]: value, + }); + }} + /> + + + ); +}; + +export default HeroEdit; +``` + +### Step 4: Register the Basic Block + +Update `src/config/blocks.ts`: + +```typescript +import type { ConfigType } from '@plone/registry'; +import HeroView from '../components/blocks/myHero/View'; +import HeroEdit from '../components/blocks/myHero/Edit'; +import { heroBlockSchema } from '../components/blocks/myHero/schema'; +import heroSVG from '@plone/volto/icons/hero.svg'; + +export default function install(config: ConfigType) { + // ... block themes configuration ... + + // Register Hero Block + config.blocks.blocksConfig.hero = { + id: 'hero', + title: 'Hero', + icon: heroSVG, + group: 'common', + view: HeroView, + edit: HeroEdit, + restricted: false, + mostUsed: true, + blockSchema: heroBlockSchema, + sidebarTab: 1, + category: 'hero', + }; + + return config; +} +``` + +### Step 5: Add Basic Block Styles + +Create `src/theme/blocks/_hero.scss`: + +```scss +.block.hero { + position: relative; + display: flex; + width: 100%; + max-width: var(--block-width) !important; + align-items: center; + justify-content: center; + background-color: var(--theme-color); + color: var(--theme-foreground-color); + margin-inline: auto; + + .hero-content { + position: relative; + z-index: 1; + width: 100%; + } + + .hero-text { + display: flex; + width: 100%; + height: 100%; + flex-direction: column; + align-items: var(--align--block-alignment); + gap: 1rem; + text-align: var(--align--block-alignment); + + .hero-title { + margin-bottom: $spacing-small; + font-size: 5rem; + line-height: 1.1; + } + + .hero-subtitle { + margin-bottom: $spacing-small; + font-size: 2rem; + line-height: 1.3; + opacity: 0.9; + } + } + + &.has-image { + color: #fff; + + .hero-image-wrapper { + position: absolute; + z-index: 0; + inset: 0; + + img { + width: 100%; + height: 100%; + object-fit: cover; + opacity: 0.7; + } + + &::after { + position: absolute; + background: rgba(0, 0, 0, 0.4); + content: ''; + inset: 0; + } + } + + .hero-content { + position: relative; + z-index: 1; + } + } +} +``` + +Import in `src/theme/_main.scss`: + +```scss +@import './blocks/hero'; +@import './site'; +``` + +### Step 6: Enhance with VLT Widgets + +Now let's add VLT's powerful widgets to control block width and alignment. Update the schema file to add the schema enhancer. + +Update `src/components/blocks/myHero/schema.ts`: + +```javascript +import { defineMessages } from 'react-intl'; + +const messages = defineMessages({ + hero: { + id: 'Hero', + defaultMessage: 'Hero', + }, + title: { + id: 'Title', + defaultMessage: 'Title', + }, + subtitle: { + id: 'Subtitle', + defaultMessage: 'Subtitle', + }, + backgroundImage: { + id: 'Background Image', + defaultMessage: 'Background Image', + }, + blockWidth: { + id: 'Block Width', + defaultMessage: 'Block Width', + }, + textAlignment: { + id: 'Text Alignment', + defaultMessage: 'Text Alignment', + }, +}); + +const heroBlockSchema = (props) => { + const { intl } = props; + + return { + title: intl.formatMessage(messages.hero), + fieldsets: [ + { + id: 'default', + title: 'Default', + fields: ['title', 'subtitle'], + }, + { + id: 'design', + title: 'Design', + fields: ['backgroundImage'], + }, + ], + properties: { + title: { + title: intl.formatMessage(messages.title), + type: 'string', + }, + subtitle: { + title: intl.formatMessage(messages.subtitle), + type: 'string', + }, + backgroundImage: { + title: intl.formatMessage(messages.backgroundImage), + widget: 'object_browser', + mode: 'image', + allowExternals: false, + }, + }, + required: [], + }; +}; + +// Schema enhancer to add VLT widget styling fields +const heroSchemaEnhancer = ({ formData, schema, intl }) => { + // Add custom fields to the styling schema at the beginning + schema.properties.styles.schema.fieldsets[0].fields = [ + 'blockWidth:noprefix', + 'align', + ...schema.properties.styles.schema.fieldsets[0].fields, + ]; + + schema.properties.styles.schema.properties['blockWidth:noprefix'] = { + widget: 'blockWidth', + title: intl.formatMessage(messages.blockWidth), + default: 'default', + }; + + schema.properties.styles.schema.properties.align = { + widget: 'blockAlignment', + title: intl.formatMessage(messages.textAlignment), + default: 'center', + }; + + return schema; +}; + +export { heroBlockSchema, heroSchemaEnhancer }; +``` + +### Step 7: Update Block Registration with Schema Enhancer + +Update `src/config/blocks.ts` to include the schema enhancer: + +```typescript +import type { ConfigType } from '@plone/registry'; +import HeroView from '../components/blocks/myHero/View'; +import HeroEdit from '../components/blocks/myHero/Edit'; +import { + heroBlockSchema, + heroSchemaEnhancer, +} from '../components/blocks/myHero/schema'; +import { composeSchema } from '@plone/volto/helpers/Extensions'; +import { defaultStylingSchema } from '@kitconcept/volto-light-theme/components/Blocks/schema'; +import heroSVG from '@plone/volto/icons/hero.svg'; + +export default function install(config: ConfigType) { + // ... block themes configuration ... + + // Register Hero Block + config.blocks.blocksConfig.hero = { + id: 'hero', + title: 'Hero', + icon: heroSVG, + group: 'common', + view: HeroView, + edit: HeroEdit, + restricted: false, + mostUsed: true, + blockSchema: heroBlockSchema, + schemaEnhancer: composeSchema(defaultStylingSchema, heroSchemaEnhancer), + sidebarTab: 1, + category: 'hero', + }; + + return config; +} +``` + +### Step 8: Update Styles to Use Widget Values + +Update `src/theme/blocks/_hero.scss` to use the CSS custom properties set by the widgets: + +```scss +.block.hero { + position: relative; + display: flex; + align-items: center; + justify-content: center; + background-size: cover; + background-position: center; + background-color: var(--theme-color); + color: var(--theme-foreground-color); + max-width: var(--block-width) !important; + margin-left: auto; + margin-right: auto; + + .hero-content { + .hero-image-wrapper { + img { + aspect-ratio: var(--image-aspect-ratio, 16/9); + opacity: 0.8; + } + } + + .hero-text { + position: absolute; + display: flex; + flex-direction: column; + align-items: var(--align--block-alignment); + width: 100%; + height: 100%; + padding: 4rem; + z-index: 2; + + .hero-title { + font-size: 5rem; + margin-bottom: $spacing-small; + line-height: 1; + } + + .hero-subtitle { + font-size: 3rem; + opacity: 0.95; + line-height: 1; + } + } + } +} +``` + +## Integrating Third-Party Blocks + +Let's learn how to integrate the `@plone-collective/volto-relateditems-block` into VLT. + +### Install the Block + +To install the related items block, make sure you are in the `frontend/packages/volto-my-project` folder, and use the following command: + +```bash +pnpm install @plone-collective/volto-relateditems-block@latest +``` + +Add it to your `package.json` addons (before VLT): + +```json +"addons": [ + "@eeacms/volto-accordion-block", + "@kitconcept/volto-button-block", + "@kitconcept/volto-heading-block", + "@kitconcept/volto-highlight-block", + "@kitconcept/volto-introduction-block", + "@kitconcept/volto-separator-block", + "@kitconcept/volto-slider-block", + "@plone-collective/volto-relateditems-block", + "@kitconcept/volto-light-theme" +], +``` + +### Enhance the Block Schema + +To add the theme feature to the Related Items block, update `src/config/blocks.ts` to register the `defaultStylingSchema` enhancer: + +```typescript +export default function install(config: ConfigType) { + // ... previous configuration ... + + config.blocks.blocksConfig.relatedItems = { + ...config.blocks.blocksConfig.relatedItems, + schemaEnhancer: defaultStylingSchema, + }; + + return config; +} +``` + +### Add Custom Styles + +Create `src/theme/blocks/_relatedItems.scss`: + +```scss +.block.relatedItems { + .inner-container { + background: var(--theme-high-contrast-color); + padding: 3rem; + width: var(--narrow-container-width); + + h2.headline { + color: var(--theme-foreground-color); + } + + ul { + color: var(--theme-foreground-color); + li a { + color: var(--link-foreground-color); + } + } + } +} + +``` + +Import it in `_main.scss`: + +```scss +@import './blocks/hero'; +@import './blocks/relatedItems'; +@import './site'; +``` \ No newline at end of file diff --git a/docs/customizing-volto-light-theme/concepts.md b/docs/customizing-volto-light-theme/concepts.md index 91eba4414..993331413 100644 --- a/docs/customizing-volto-light-theme/concepts.md +++ b/docs/customizing-volto-light-theme/concepts.md @@ -1,35 +1,38 @@ --- myst: html_meta: - "description": "Concepts" - "property=og:description": "Concepts" - "property=og:title": "Concepts" + "description": "Foundation, Concepts & Project Setup" + "property=og:description": "Foundation, Concepts & Project Setup" + "property=og:title": "Foundation, Concepts & Project Setup" "keywords": "Plone, Volto, Training, Volto Light Theme" --- +# Foundation, Concepts & Project Setup -# Volto Light Theme Concepts +## Volto Light Theme Core Concepts Volto Light Theme (VLT) is a customizable theme built for the Volto frontend of the Plone CMS. It provides a foundation that aims to solve many common design challenges, while remaining flexible enough for customization. It's particularly valuable because it is based on real-world experience, while simultaneously embodying the Volto vision for the future. This module will help you understand the core concepts in VLT and create a mental map of its parts. -## Base Styling +### Base Styling -VLT is designed with simplicity and a minimal aesthetic in mind. Consistency, accessibility, and intuitiveness are what drive the development and improvements for VLT. +VLT is designed with simplicity and a minimal aesthetic in mind. The three core principles are: +- **Consistency**: Predictable design patterns across all components +- **Accessibility**: WCAG compliant with contrast checkers and semantic HTML +- **Intuitiveness**: Clear visual hierarchy and user-friendly interfaces -## Customizable Variables +### Customizable Variables -VLT offers a set of CSS custom properties (variables) that allow developers to customize various design elements, such as: - -- Colors -- Spatial relationships -- Layouts +VLT offers a set of CSS custom properties (variables) that allow developers to customize various design elements: +- **Colors**: Using paired foreground/background color system +- **Spatial relationships**: Container widths and spacing scales +- **Layouts**: Three-width container system These variables can be easily overridden in your project to match the desired visual identity. -## Colors +### Color System -The color system is designed so that colors work in couples: a "background color" and a "foreground color". The "foreground color" is often called "text color" in other systems, but since we want to use this value for more than text—like icons or borders, this works better as a generic term. Colors that do not specify "foreground" in the name are meant to be background colors. +The color system is designed so that colors work in couples: a "background color" and a "foreground color". The "foreground color" is often called "text color" in other systems, but since we want to use this value for more than text—like icons or borders—this works better as a generic term. Colors that do not specify "foreground" in the name are meant to be background colors. -The main color properties for a project using VLT are the following: +The main color properties for a project using VLT are: ```scss --primary-color: #fff; @@ -42,9 +45,9 @@ The main color properties for a project using VLT are the following: --accent-foreground-color: #000; ``` -### Semantic color properties +### Semantic Color Properties -As an additional layer on top of the main color properties, we have set in place some semantic custom properties for the basic layout sections. As a default they use the values from the main color variables, but they can be detached if desired by setting new color values. However, we feel that leaving these color relationships as they are helps create a cohesive final design. The semantic layer of properties includes the following: +As an additional layer on top of the main color properties, we have set in place some semantic custom properties for the basic layout sections. As a default they use the values from the main color variables, but they can be detached if desired by setting new color values. However, leaving these color relationships as they are helps create a cohesive final design: ```scss // Header @@ -71,32 +74,64 @@ As an additional layer on top of the main color properties, we have set in place --link-foreground-color: var(--link-color); ``` -## Block width - -VLT now uses a standard block width definition as well. Currently, this is done via a `widget` component, `BlockWidthWidget`, that will be ported to Volto core in the near future. This component stores the value of the custom property `--block-width` so that it can be used by the StyleWrapper when injecting styles into the markup. +### Block Themes + +VLT includes a block theme system that enables individual blocks to use distinct color palettes. These themes are configured in `config.blocks.themes` and applied through the StyleWrapper system at runtime. + +**The four core block theme variables:** + +- `--theme-color`: Primary background color — the most visible color in the block +- `--theme-high-contrast-color`: Secondary background color for nested elements (e.g., cards within a block) to create visual separation from the main background +- `--theme-foreground-color`: Default text and icon color +- `--theme-low-contrast-foreground-color`: Subdued text color for secondary content like placeholders or helper text + +While the system can be extended with non-color CSS properties, the default four variables establish the color foundation for each theme. + +**Example configuration:** + +```typescript +config.blocks.themes = [ + { + style: { + '--theme-color': '#fff', + '--theme-high-contrast-color': '#ecebeb', + '--theme-foreground-color': '#000', + '--theme-low-contrast-foreground-color': '#555555', + }, + name: 'default', + label: 'Default', + }, + { + style: { + '--theme-color': '#ecebeb', + '--theme-high-contrast-color': '#fff', + '--theme-foreground-color': '#000', + '--theme-low-contrast-foreground-color': '#555555', + }, + name: 'grey', + label: 'Grey', + }, +]; +``` -The three-width layout system considers the following variables: +Users select block themes through the `themeColorSwatch` widget in the block sidebar. This widget renders colored buttons using each theme's `--theme-color` value, allowing visual theme selection. -```scss ---layout-container-width: #{$layout-container-width}; // for major elements like headers, & large Blocks like the `volto-slider-block`. ---default-container-width: #{$default-container-width}; // a balanced content presentation for most Blocks. ---narrow-container-width: #{$narrow-container-width}; // optimal readability. -``` +### Container Width System -The default values map the container width SCSS variables, which have existed in the VLT ecosystem since versions < 6.0.0-alpha.0: +VLT uses three types of container widths: ```scss -// Container widths -$layout-container-width: 1440px !default; -$default-container-width: 940px !default; -$narrow-container-width: 620px !default; +// Three-width layout system +--layout-container-width: 1440px; // for major elements like headers & large Blocks +--default-container-width: 940px; // balanced content presentation for most Blocks +--narrow-container-width: 620px; // optimal readability for text ``` -## Block alignment +The VLT `BlockWidthWidget` stores the value of the custom property `--block-width` so that it can be used by the StyleWrapper when injecting styles into the markup. -As part of the effort to generalize behaviors, another VLT `widget` is the `BlockAlignmentWidget`, which also takes advantage of the StyleWrapper by setting the `--block-alignment` property. +### Block Alignment -The three default options are: +The `BlockAlignmentWidget` takes advantage of the StyleWrapper by setting the `--block-alignment` property. The three default options are: ```scss --align-left: start; @@ -104,6 +139,145 @@ The three default options are: --align-right: end; ``` -## Conclusion +## Create a New Project with Cookieplone + +We recommend creating your Plone project with **Cookieplone**. Our comprehensive documentation provides step-by-step guidance to help you get started. For detailed installation instructions, visit our [Cookieplone guide](https://6.docs.plone.org/install/create-project-cookieplone.html). + +## Installing Volto Light Theme + +### Step 1: Install VLT and Recommended Block Add-ons + +Navigate to the `frontend/packages/my-vlt-project` folder and install VLT: + +```bash +pnpm install @kitconcept/volto-light-theme@latest +``` + +Volto Light Theme comes with several pre-configured add-ons that provide basic blocks for your website. If you'd like to include them, you can add them in the `addons` section in your {file}`package.json`, but this is not required. + +Here is the list of recommended addons to install, including VLT, which should be the last element: + +```json +"addons": [ + "@eeacms/volto-accordion-block", + "@kitconcept/volto-button-block", + "@kitconcept/volto-heading-block", + "@kitconcept/volto-highlight-block", + "@kitconcept/volto-introduction-block", + "@kitconcept/volto-separator-block", + "@kitconcept/volto-slider-block", + "@kitconcept/volto-light-theme" +], +``` + +While in your project package folder, add VLT and the block addons to the `addons` list in your `package.json`: + +```json +{ + "name": "my-vlt-project", + "addons": [ + "@eeacms/volto-accordion-block", + "@kitconcept/volto-button-block", + "@kitconcept/volto-heading-block", + "@kitconcept/volto-highlight-block", + "@kitconcept/volto-introduction-block", + "@kitconcept/volto-separator-block", + "@kitconcept/volto-slider-block", + "@kitconcept/volto-light-theme" + ] +} +``` + +**Important:** VLT must be the last addon in the list to ensure proper style cascade. Your project addon will still be the last applied if defined in `volto.config.js`. + +### Step 2: Configure VLT as the Theme Provider + +Open the `volto.config.js` file in your `frontend` folder and modify it as shown below: + +```javascript +const addons = ['my-vlt-project']; +const theme = '@kitconcept/volto-light-theme'; + +module.exports = { + addons, + theme, +}; +``` + +You'll need to restart your Plone frontend to see the changes. + +That's it! Your project should now be using Volto Light Theme with its additional blocks and components. + +### Step 3: Install Backend Package + +In your backend folder, install the Python package for site customization behaviors. + +Edit `backend/pyproject.toml` and add to the dependencies array: + +``` +dependencies = [ + "Products.CMFPlone==6.1.3", + "plone.api", + "plone.restapi", + "plone.volto", + "kitconcept.voltolighttheme==7.3.1", +] +``` + +### Step 4: Install the Backend Add-on + +Start your development environment: + +```bash +# Terminal 1 - Backend +make backend-start + +# Terminal 2 - Frontend +make frontend-start +``` + +Once the frontend is running: + +1. Go to http://localhost:3000/controlpanel/addons +2. Find "Volto Light Theme" in the list +3. Click "Install" + +### Step 5: Activate Behaviors for Plone Site + +To enable site customization through the UI: + +1. Go to http://localhost:3000/controlpanel/dexterity-types/Plone%20Site +2. In the "Behaviors" tab, activate the desired behaviors +3. Click "Save" + +Now your project should have the VLT Site configurations available. + +## File Structure Setup + +Let's set up the recommended file structure. In your project add-on's `src` folder, create the following structure: + +```console +src/ +├── components/ +│ └── blocks/ +├── config/ +│ ├── settings.ts +│ └── blocks.ts +├── index.ts +└── theme/ + ├── blocks/ + ├── _main.scss + └── _site.scss +``` + +Create the files: + +```bash +cd src +mkdir -p components/blocks config theme/blocks +touch config/settings.ts config/blocks.ts +touch index.ts +touch theme/_main.scss theme/_site.scss +``` -VLT provides a robust foundation for Plone CMS frontend development through this framework of customizable variables and standardized block controls. Through these core concepts, VLT strikes a balance between maintaining consistency and flexibility, allowing developers to create cohesive designs while still having the freedom to customize elements to match their specific project needs. +Remember that if you add new files to your project, it will be necessary to restart your Plone frontend. \ No newline at end of file diff --git a/docs/customizing-volto-light-theme/creating-new-project.md b/docs/customizing-volto-light-theme/creating-new-project.md deleted file mode 100644 index 9cc7fef69..000000000 --- a/docs/customizing-volto-light-theme/creating-new-project.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -myst: - html_meta: - "description": "Create a new project with Plone and Volto" - "property=og:description": "Create a new project with Plone and Volto" - "property=og:title": "Create a new project with Plone and Volto" - "keywords": "Plone, Volto, Training, Theme, Footer" ---- - -# Create a new project with Plone and Volto -We recommend creating your Plone project with **Cookieplone**. Our comprehensive documentation provides step-by-step guidance to help you get started. For detailed installation instructions, visit our [Cookieplone guide](https://6.docs.plone.org/install/create-project-cookieplone.html). \ No newline at end of file diff --git a/docs/customizing-volto-light-theme/design-system-implementation.md b/docs/customizing-volto-light-theme/design-system-implementation.md new file mode 100644 index 000000000..ff014bf02 --- /dev/null +++ b/docs/customizing-volto-light-theme/design-system-implementation.md @@ -0,0 +1,263 @@ +--- +myst: + html_meta: + "description": "Design system implementation & theming" + "property=og:description": "Design system implementation & theming" + "property=og:title": "Design system implementation & theming" + "keywords": "Plone, Volto, Training, Theme, Footer" +--- + +# Design System Implementation & Theming + +## Extracting Design Tokens + +When working with a given design, systematically extract design decisions. Identify: + +### Color Extraction Checklist + +1. **Primary Colors** + - Background color + - Text color on primary + +2. **Secondary Colors** + - Background color + - Text color on secondary + +3. **Accent Colors** + - Highlight color + - Text color on accent + +4. **Semantic Colors** + - Link colors + +### Typography Extraction + +Look for: +- Font families +- Line heights +- Font weights + + +## Implementing Your Design System + +VLT has migrated to use standardized color definitions. These use CSS properties that are injected at runtime in the right places, so your CSS can adapt to use them generically. The resulting CSS is simpler, and there's no need to define class names for each color definition. + +### Step 1: Add Font Files + +If you're using custom fonts, add the font files to your theme directory. Create a `fonts` folder in your theme directory and place your font files there: + +``` +src/theme/fonts/Chakra_Petch/ + ├── ChakraPetch-Regular.ttf + ├── ChakraPetch-Bold.ttf + └── ... (other font weights/styles) +``` + +This ensures the font files are bundled with your theme and can be referenced in your SCSS files. + +### Step 2: Create _site.scss + +In `src/theme/_site.scss`, define your color variables, custom properties and block-specific styles: + +```scss +@font-face { + font-family: 'Chakra Petch'; + src: url('./fonts/Chakra_Petch/ChakraPetch-Regular.ttf') format('truetype'); +} + +:root { + // Extract these from your design + --accent-color: #3b5759; + --accent-foreground-color: #fff; + --secondary-color: #afcac8; + + // Typography + --text-base: 1.15rem; + --custom-main-font: 'Chakra Petch', sans-serif; + --line-height-factor: 1.5; + + // Gradients for header/footer + --header-background: linear-gradient( + -3deg, + var(--background, #fff) 0%, + color-mix(in oklab, var(--secondary-color) 1%, var(--background, #fff)) 20%, + color-mix(in oklab, var(--secondary-color) 3%, var(--background, #fff)) 35%, + color-mix(in oklab, var(--secondary-color) 10%, var(--background, #fff)) 50%, + color-mix(in oklab, var(--secondary-color) 30%, var(--background, #fff)) 65%, + color-mix(in oklab, var(--secondary-color) 65%, var(--background, #fff)) 80%, + color-mix(in oklab, var(--secondary-color) 90%, var(--background, #fff)) 92%, + var(--secondary-color) 100% + ); + + --footer-background: radial-gradient( + ellipse 100% 100% at 50% 100%, + var(--secondary-color) 0%, + var(--secondary-color) 20%, + color-mix(in oklab, var(--secondary-color) 85%, var(--background, #fff)) 30%, + color-mix(in oklab, var(--secondary-color) 65%, var(--background, #fff)) 40%, + color-mix(in oklab, var(--secondary-color) 45%, var(--background, #fff)) 50%, + color-mix(in oklab, var(--secondary-color) 30%, var(--background, #fff)) 60%, + color-mix(in oklab, var(--secondary-color) 18%, var(--background, #fff)) 70%, + color-mix(in oklab, var(--secondary-color) 10%, var(--background, #fff)) 80%, + color-mix(in oklab, var(--secondary-color) 4%, var(--background, #fff)) 90%, + var(--background, #fff) 100% + ); + + --fatmenu-foreground: #fff; + + // Container widths (customized) + --default-container-width: 1440px; + --layout-container-width: 90%; + + // Link color + --link-foreground-color: #157a7a; + + // Breadcrumbs + --breadcrumbs-background: var(--background, #fff); + --breadcrumbs-foreground: var(--secondary-foreground-color, #3b5759); + + .breadcrumbs { + border-bottom: 1px solid #afcac8; + } + + // Block-specific styles + #page-document, + #page-edit, + #page-add { + .blocks-group-wrapper:first-child { + padding-top: 0; + + } + .block { + + &.__button { + .button { + button { + padding: 1rem; + } + } + } + + &.__button { + .ui.button:hover { + --theme-color: #fff; + } + } + + &.slider { + .teaser-item-title { + background: rgba(255, 255, 255, 0.1); + color: var(--theme-foreground-color) !important; + backdrop-filter: blur(20px) saturate(110%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + box-shadow: + 0 8px 32px 0 rgba(31, 135, 125, 0.1), + inset 0 0 0 1px rgba(255, 255, 255, 0.1); + } + } + + &.gridBlock { + .four { + .slate:not(.inner) { + padding: 2.5rem; + padding-top: 4rem !important; + backdrop-filter: blur(20px) saturate(110%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + box-shadow: + 0 8px 32px 0 rgba(31, 135, 125, 0.1), + inset 0 0 0 1px rgba(255, 255, 255, 0.1); + } + } + } + + &.teaser { + .card { + .card-inner { + .card-summary { + padding: $spacing-large; + } + } + } + } + } + + + } +} + +#sidebar { + .color-swatch-widget { + .buttons button.teal { + background: linear-gradient(135deg, var(--secondary-color) 0%, #fff 100%); + } + } +} +``` + +### Step 3: Configure Block Themes + +In `src/config/blocks.ts`, define block themes: + +```typescript +import type { ConfigType } from '@plone/registry'; + +export default function install(config: ConfigType) { + // Block palettes + config.blocks.themes = [ + { + style: { + '--theme-color': 'white', + '--theme-high-contrast-color': '#bbd1d0', + '--theme-foreground-color': 'black', + '--theme-low-contrast-foreground-color': '#555555', + }, + name: 'default', + label: 'Default', + }, + { + style: { + '--theme-color': `linear-gradient(180deg, oklab(1 0 0 / 0.9) 0%, transparent 15%, transparent 85%, oklab(1 0 0 / 0.9) 100%), + radial-gradient(ellipse 850px 700px at 12% 15%, oklab(1 0 0 / 0.4) 0%, transparent 70%), + radial-gradient(ellipse 900px 650px at 85% 85%, oklab(1 0 0 / 0.4) 0%, transparent 70%), + radial-gradient(ellipse 850px 750px at 70% 35%, oklab(0.805 -0.030 -0.003 / 0.5) 0%, oklab(0.835 -0.025 -0.002 / 0.2) 50%, transparent 85%), + radial-gradient(ellipse 920px 800px at 25% 65%, oklab(0.780 -0.032 -0.004 / 0.45) 0%, oklab(0.825 -0.027 -0.003 / 0.2) 50%, transparent 87%), + radial-gradient(ellipse 1100px 900px at 50% 50%, oklab(0.805 -0.030 -0.003 / 0.25) 0%, oklab(0.850 -0.025 -0.002 / 0.1) 60%, transparent 90%), + linear-gradient(182deg, oklab(1 0 0) 0%, oklab(0.988 -0.006 0) 10%, oklab(0.958 -0.016 -0.001) 22%, oklab(0.910 -0.025 -0.003) 35%, oklab(0.860 -0.030 -0.003) 45%, oklab(0.820 -0.032 -0.004) 52%, oklab(0.860 -0.030 -0.003) 59%, oklab(0.910 -0.025 -0.003) 69%, oklab(0.958 -0.016 -0.001) 82%, oklab(0.988 -0.006 0) 92%, oklab(1 0 0) 100%)`, + '--theme-high-contrast-color': 'oklab(1 0 0 / 0.1)', + '--theme-foreground-color': 'black', + '--theme-low-contrast-foreground-color': '#555555', + }, + name: 'teal', + label: 'Teal', + }, + ]; + + return config; +} +``` + +### Step 4: Main Index Configuration + +In `src/index.ts`: + +```typescript +import type { ConfigType } from '@plone/registry'; +import installSettings from './config/settings'; +import installBlocks from './config/blocks'; + +function applyConfig(config: ConfigType) { + installSettings(config); + installBlocks(config); + return config; +} + +export default applyConfig; +``` + +### Step 5: Import SCSS Files + +In `src/theme/_main.scss`: + +```scss +@import './site'; +``` \ No newline at end of file diff --git a/docs/customizing-volto-light-theme/index.md b/docs/customizing-volto-light-theme/index.md index 74e398160..04260b9a7 100644 --- a/docs/customizing-volto-light-theme/index.md +++ b/docs/customizing-volto-light-theme/index.md @@ -28,9 +28,8 @@ This training is best suited for developers who have prior experience with Volto :numbered: concepts -creating-new-project -installing-vlt -integrate-new-block -theming +design-system-implementation +block-development-widgets +advanced-components-bm3 question-answer ``` \ No newline at end of file diff --git a/docs/customizing-volto-light-theme/installing-vlt.md b/docs/customizing-volto-light-theme/installing-vlt.md deleted file mode 100644 index 32cc59343..000000000 --- a/docs/customizing-volto-light-theme/installing-vlt.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -myst: - html_meta: - "description": "Installing Volto Light Theme" - "property=og:description": "Installing Volto Light Theme" - "property=og:title": "Installing Volto Light Theme" - "keywords": "Plone, Volto, Training, Volto Light Theme" ---- - -# Installing Volto Light Theme - -Follow the steps below to install and configure VLT in your project. VLT provides a clean and modern design with ready-to-use blocks and components. - -## Step 1: Install Volto Light Theme - -To install VLT, navigate to the {file}`frontend/packages/volto-my-project` folder and run the following command: - -```{note} -For now we'll be using an `alpha` release, so we need to specify the correct version. -``` - -```shell -pnpm install @kitconcept/volto-light-theme@6.0.0-alpha.2 -``` - -While in your project package folder, add VLT to the `addons` list in your {file}`package.json`, as follows: - -```json -"addons": ["@kitconcept/volto-light-theme"], -``` - -## Step 2: install block add-ons - -Volto Light Theme comes with several pre-configured add-ons that provide basic blocks for your website. If you'd like to include them, you can add them in the `addons` section in your {file}`package.json`, but this is not required. - -Here is the list of recommended addons to install, including VLT, which should be the last element: - -```json -"addons": [ - "@eeacms/volto-accordion-block", - "@kitconcept/volto-button-block", - "@kitconcept/volto-heading-block", - "@kitconcept/volto-highlight-block", - "@kitconcept/volto-introduction-block", - "@kitconcept/volto-separator-block", - "@kitconcept/volto-slider-block", - "@kitconcept/volto-light-theme" -], -``` - -## Step 3: configure Volto Light Theme as the theme provider - -To leverage a cohesive set of styles, components, and design patterns that align with Volto's best practices, you need to set VLT as your theme provider. - -Open the {file}`volto.config.js` file in your {file}`frontend` folder, and modify it as shown below. - -```{code-block} js -:emphasize-lines: 2 - -const addons = ['volto-project-title']; -const theme = '@kitconcept/volto-light-theme'; - -module.exports = { - addons, - theme -}; -``` - -You'll need to restart your Plone frontend to see the changes. - -That's it! Your project should now be using Volto Light Theme with its additional blocks and components. diff --git a/docs/customizing-volto-light-theme/integrate-new-block.md b/docs/customizing-volto-light-theme/integrate-new-block.md deleted file mode 100644 index 7086e08b4..000000000 --- a/docs/customizing-volto-light-theme/integrate-new-block.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -myst: - html_meta: - "description": "Adding New Block" - "property=og:description": "Adding New Block" - "property=og:title": "Adding New Block" - "keywords": "Plone, Volto, Training, Volto Light Theme, Integrate, block" ---- - -# Integrate a new block - -In this training module, we'll learn how to integrate the `@plone-collective/volto-relateditems-block` into VLT. This block allows you to create links to related content in your Plone site. - -## Install `@plone-collective/volto-relateditems-block` - -To install the related items block, make sure you are in the {file}`frontend/packages/volto-my-project` folder, and use the following command: - -```{note} -For now we'll be using an `alpha` release, so we need to specify the correct version. -``` - -```shell -pnpm install @plone-collective/volto-relateditems-block@1.0.0-alpha.1 -``` - -After installation, ensure that the add-on is included in the `addons` key of your project's {file}`package.json`: - -```json -"addons": [ - "@eeacms/volto-accordion-block", - "@kitconcept/volto-button-block", - "@kitconcept/volto-heading-block", - "@kitconcept/volto-highlight-block", - "@kitconcept/volto-introduction-block", - "@kitconcept/volto-separator-block", - "@kitconcept/volto-slider-block", - "@plone-collective/volto-relateditems-block", - "@kitconcept/volto-light-theme" -], -``` - -You'll need to restart your Plone frontend to see the changes. - -That's it! Your project should now be using `@plone-collective/volto-relateditems-block`, which shows related items for the content as a list of links. diff --git a/docs/customizing-volto-light-theme/theming.md b/docs/customizing-volto-light-theme/theming.md deleted file mode 100644 index 5e3d94699..000000000 --- a/docs/customizing-volto-light-theme/theming.md +++ /dev/null @@ -1,342 +0,0 @@ ---- -myst: - html_meta: - "description": "Extend the Volto Light Theme" - "property=og:description": "Extend the Volto Light Theme" - "property=og:title": "Extend the Volto Light Theme" - "keywords": "Plone, Volto, Training, Extend, Volto Light Theme" ---- - -# Extend VLT - -In this section we'll extend the VLT to create a "dark" aesthetic for our project. The same patterns can be applied for other visual identity cases. - -## File structure - -Let us start by setting up the recommended file structure. In your project add-on's {file}`src` folder, create a subfolder named {file}`theme`. -Inside {file}`theme` create two empty files named {file}`_main.scss` and {file}`_variables.scss`. Refer to the following file system diagram: - -```console -src/ -├── components -├── index.js -└── theme - ├── _main.scss - └── _variables.scss -``` - -Remember that if you add new files to your project, it will be necessary to restart your Plone frontend. - -### `_variables.scss` - -{file}`_variables.scss` is where you can override the base theme SCSS variables. - -```scss -:root { - --primary-color: black; - --primary-foreground-color: lemonchiffon; - - --secondary-color: darkslategrey; - --secondary-foreground-color: lemonchiffon; - - --accent-color: darkslategrey; - --accent-foreground-color: lemonchiffon; - - --link-color: lightblue; -} -``` - -### `_main.scss` - -{file}`_main.scss` is where you should put any custom styles. You can also include other SCSS or CSS files, as follows: - -```scss -@import 'variables'; -``` - -## Block themes - -Now we need to change the available themes for the blocks by adding the following definition inside the `applyConfig` function in our project's {file}`index.js`: - -```js -config.blocks.themes = [ - { - style: { - '--theme-color': 'black', - '--theme-high-contrast-color': 'darkslategrey', - '--theme-foreground-color': 'lemonchiffon', - '--theme-low-contrast-foreground-color': 'lightgrey', - }, - name: 'default', - label: 'Default', - }, - { - style: { - '--theme-color': 'darkslategrey', - '--theme-high-contrast-color': 'black', - '--theme-foreground-color': 'lemonchiffon', - '--theme-low-contrast-foreground-color': 'lightgrey', - }, - name: 'green', - label: 'Green', - }, -]; -``` - -## Extend add-on styles - -The theme provides the ability to extend or modify existing components. Let's create one more file named {file}`relatedItems.scss` to add specific styles for the add-on, as follows: - -```console -src/ -├── components -├── index.js -└── theme - ├── blocks - └── _relatedItems.scss - ├── _main.scss - └── _variables.scss -``` - -In the new {file}`_relatedItems.scss`, let's fix the text color, and add background color to the `.inner-container` element with the variables `--primary-foreground-color` and `--theme-high-contrast-color`. Lastly, let's use `--link-foreground-color` for the related items links: - -```scss -.block.relatedItems { - .inner-container { - background: var(--theme-high-contrast-color); - padding: 3rem; - - h2.headline { - color: var(--primary-foreground-color); - } - - ul.items-list { - color: var(--primary-foreground-color); - li a { - color: var(--link-foreground-color); - } - } - } -} -``` - -And now we need to add {file}`_relatedItems.scss` in {file}`_main_.scss`: - -```scss -@import 'blocks/relatedItems'; -@import 'variables'; -``` - -## Enhancing a block schema - -To be able to use the Block Width widget with our Related Items block, we need to add it to the block schema. -To do this we'll use a `schemaEnhancer`. A schema enhancer is a function that receives an object with `formData` (the block `data`), the `schema` (the original schema that we want to tweak), and the injected `intl` (to aid with internationalization). - -Usually we would want to keep the schema enhancers in individual files per block, after which they can be imported to the {file}`index.js`. For this example we'll leave everything in the same file: - -```js -import { defineMessages } from 'react-intl'; -import { composeSchema } from '@plone/volto/helpers/Extensions'; -import { defaultStylingSchema } from '@kitconcept/volto-light-theme/components/Blocks/schema'; -import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer'; - -const messages = defineMessages({ - BlockWidth: { - id: 'Block Width', - defaultMessage: 'Block Width', - }, -}); - -const applyConfig = (config) => { - config.settings = { - ...config.settings, - isMultilingual: false, - supportedLanguages: ['en'], - defaultLanguage: 'en', - }; - - config.blocks.themes = [ - { - style: { - '--theme-color': 'black', - '--theme-high-contrast-color': 'darkslategrey', - '--theme-foreground-color': 'lemonchiffon', - '--theme-low-contrast-foreground-color': 'lightgrey', - }, - name: 'default', - label: 'Default', - }, - { - style: { - '--theme-color': 'darkslategrey', - '--theme-high-contrast-color': 'black', - '--theme-foreground-color': 'lemonchiffon', - '--theme-low-contrast-foreground-color': 'lightgrey', - }, - name: 'green', - label: 'Green', - }, - ]; - - const relatedItemsEnhancer = ({ formData, schema, intl }) => { - addStyling({ schema, intl }); - - schema.properties.styles.schema.fieldsets[0].fields = [ - 'blockWidth:noprefix', - ...schema.properties.styles.schema.fieldsets[0].fields, - ]; - schema.properties.styles.schema.properties['blockWidth:noprefix'] = { - widget: 'blockWidth', - title: intl.formatMessage(messages.BlockWidth), - default: 'default', - filterActions: ['narrow', 'default'], - }; - return schema; - }; - - config.blocks.blocksConfig.relatedItems = { - ...config.blocks.blocksConfig.relatedItems, - schemaEnhancer: composeSchema(defaultStylingSchema, relatedItemsEnhancer), - }; - - return config; -}; - -export default applyConfig; -``` - -Finally, let's wire the width classes for our block in the file {file}`_relatedItems.scss`: - -```scss -.block.relatedItems { - margin-right: auto; - margin-left: auto; - - .inner-container { - background: var(--theme-high-contrast-color); - padding: 3rem; - - h2.headline { - color: var(--primary-foreground-color); - } - - ul { - color: var(--primary-foreground-color); - li a { - color: var(--link-foreground-color); - } - } - } - - &.has--block-width--narrow { - max-width: var(--narrow-container-width) !important; - } - - &.has--block-width--default { - max-width: var(--default-container-width) !important; - } -} - -.block-editor-relatedItems { - &.has--block-width--narrow .block .block .block { - max-width: var(--narrow-container-width) !important; - } - - &.has--block-width--default .block .block .block { - max-width: var(--default-container-width) !important; - } -} -``` - - -## Set themes for one block - -To demonstrate this feature, we'll add a custom list of themes just for the Related Items block, which will include one more theme called `Blue`. Add the property `themes` to the `relatedItems` block in the `blocksConfig` object: - -```js -import { defineMessages } from 'react-intl'; -import { composeSchema } from '@plone/volto/helpers/Extensions'; -import { defaultStylingSchema } from '@kitconcept/volto-light-theme/components/Blocks/schema'; -import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer'; - -const messages = defineMessages({ - BlockWidth: { - id: 'Block Width', - defaultMessage: 'Block Width', - }, -}); - -const applyConfig = (config) => { - config.settings = { - ...config.settings, - isMultilingual: false, - supportedLanguages: ['en'], - defaultLanguage: 'en', - }; - - config.blocks.themes = [ - { - style: { - '--theme-color': 'black', - '--theme-high-contrast-color': 'darkslategrey', - '--theme-foreground-color': 'lemonchiffon', - '--theme-low-contrast-foreground-color': 'lightgrey', - }, - name: 'default', - label: 'Default', - }, - { - style: { - '--theme-color': 'darkslategrey', - '--theme-high-contrast-color': 'black', - '--theme-foreground-color': 'lemonchiffon', - '--theme-low-contrast-foreground-color': 'lightgrey', - }, - name: 'green', - label: 'Green', - }, - ]; - - const relatedItemsEnhancer = ({ formData, schema, intl }) => { - addStyling({ schema, intl }); - - schema.properties.styles.schema.fieldsets[0].fields = [ - 'blockWidth:noprefix', - ...schema.properties.styles.schema.fieldsets[0].fields, - ]; - schema.properties.styles.schema.properties['blockWidth:noprefix'] = { - widget: 'blockWidth', - title: intl.formatMessage(messages.BlockWidth), - default: 'default', - filterActions: ['narrow', 'default'], - }; - return schema; - }; - - config.blocks.blocksConfig.relatedItems = { - ...config.blocks.blocksConfig.relatedItems, - schemaEnhancer: composeSchema(defaultStylingSchema, relatedItemsEnhancer), - themes: [ - ...config.blocks.themes, - { - style: { - '--theme-color': 'midnightblue', - '--theme-high-contrast-color': 'black', - '--theme-foreground-color': 'lemonchiffon', - '--theme-low-contrast-foreground-color': 'lightgrey', - }, - name: 'blue', - label: 'Blue', - }, - ], - }; - - return config; -}; - -export default applyConfig; -``` - -## Conclusion - -Understanding how to extend VLT will help you take advantage of the system and quickly create consistent and flexible designs. diff --git a/docs/mastering-plone/events.md b/docs/mastering-plone/events.md index bcc7e0ddc..fd6b1b707 100644 --- a/docs/mastering-plone/events.md +++ b/docs/mastering-plone/events.md @@ -267,7 +267,7 @@ This trick does not yet work in Volto because some css-classes are still missing Modify {file}`frontend/theme/extras/custom.overrides` and add: -```less +```css /* Hide date fields from contributors */ body.userrole-contributor { #default-start.field,