Volto Album View

I need something like light gallery in one of my sites, so i looked arround if there is something provided by plone / volto already. I saw that there is something called image-galery using the AlbumView from volto, this would provide exactly what i need but I can't find any documentation about it or how i could use this. Can anyone explain to me how i can access this.

I need a gallery too, do you success add one?

@mactrash Yes, I added one by myself since I couldn't find a good solution. I just created a new Block and used Light Gallery to display the images correctly. If you want to, I can provide the code.

I am new to volto, if you can share the code I am happy to have that

The AlbumView is a display option for the Folder content type, but usually Folders are disabled when using Volto because any page can be a folder.

Instead, for a built-in gallery option, add a Listing block and then choose the Image Gallery variation in the block settings.

1 Like

Sorry for the late response. Here is the code I use (don't blame me if it's not perfect, this was one of my first tries with Plone/Volto).

As you see in the schema file, I define a URL where all images from this URL will be taken from. I recommend creating a page for each gallery and setting this URL as the start URL. This way, you will be able to create multiple Galleries. E.g. If you have a gallery on your Landing page, create a page called "landingImages". Then use the gallery block on your landing page, and your URL would be /landingimages.

LightGallerySchema.js


export const LightGallerySchema = (props) => {
  return {
    title: 'Image Gallery',
    fieldsets: [
      {
        id: 'default',
        title: 'Default',
        fields: ['galleryurl', 'colNumb', "sortOn", "sortOrder"],
      },
    ],

    properties: {
      galleryurl: {
        title: 'Url',
        description: 'Start Url for the image gallery',
        widget: 'internal_url',
        required: true,
      },
      colNumb: {
        title: 'Column count',
        description: 'Number of columns to be displayed',
        widget: 'number',
        required: true,
      },
      sortOn: {
        title: 'Sort term',
        description: 'Sort term to sort the images e.g. sortable_title',
        widget: 'text',
      },
      sortOrder: {
        title: 'Sort order descending',
        description: 'Sort descending, otherwise its ascending',
        type: 'boolean',
      }
    },
    required: [],
  };
};

export default LightGallerySchema;

LightGalleryEdit.jsx

import React from "react";
import LightGalleryData from "./LightGalleryData";
import SidebarPortal from '@plone/volto/components/manage/Sidebar/SidebarPortal';

const LightGalleryEdit = React.memo((props) => {
    const { selected, onChangeBlock, block, data } = props;

    return (
        <>
            <h3>Image gallery</h3>
            <img
                src='/default-image.svg'
                width="400"
                height="300"
            />
            <SidebarPortal selected={selected}>
                <LightGalleryData
                    {...props}
                    data={data}
                    block={block}
                    onChangeBlock={onChangeBlock}
                />
            </SidebarPortal>
        </>
    )
})

export default LightGalleryEdit;

LightGalleryData.jsx

import React from 'react';
import { LightGallerySchema } from './LightGallerySchema';
import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm';

const LightGalleryData = (props) => {
  const { block, data, onChangeBlock } = props;
  const schema = LightGallerySchema({ ...props });
  console.log(props.metadata);
  return (
    <BlockDataForm
      schema={schema}
      title={schema.title}
      onChangeField={(id, value) => {
        onChangeBlock(block, {
          ...data,
          [id]: value,
        });
      }}
      formData={data}
      block={block}
    />
  );
};
export default LightGalleryData;

LightGalleryView.jsx
(Don't forget to insert the License Key into the "licensekey" attribute)

import React, { useEffect } from 'react';
import ImageList from '@mui/material/ImageList';
import ImageListItem from '@mui/material/ImageListItem';
import { useDispatch, useSelector } from 'react-redux';
import { searchContent } from '@plone/volto/actions';
import { flattenToAppURL } from '@plone/volto/helpers';
import PropTypes from 'prop-types';
import LightGallery from 'lightgallery/react';
import { Image } from 'semantic-ui-react';
import lgZoom from 'lightgallery/plugins/zoom';
import 'lightgallery/css/lightgallery.css';
import 'lightgallery/css/lg-zoom.css';

const LightGalleryView = (props) => {
  const { data, id, content } = props;
  const dispatch = useDispatch();

  const subrequestID = content?.UID ? `${content?.UID}-${id}` : id;
  const images = useSelector((state) => state?.search?.subrequests?.[subrequestID]?.items,);

  const contentData = data.galleryurl;
  const colNumb = data.colNumb;

  //to sort by title insert sortable_title
  var sortOn = "None"
  var sortOrder = "ascending";
  if (data.sortOn != 0) {
    sortOn = data.sortOn
  }
  if (data.sortOrder) {
    sortOrder = "descending";
  }

  useEffect(() => {
    dispatch(
      searchContent(
        contentData,
        {
          portal_type: ['Image'],
          b_size: 1000,
          sort_on: sortOn,
          sort_order: sortOrder,
        },
        subrequestID,
      ),
    );
  }, []);

  return (
    <>
      <div className="App">
        {data.title?.length > 0 && (
          <h1>{data.title}</h1>
        )}
        {images?.length > 0 && (
          <ImageList className='lightgalleryUl' variant="masonry" cols={colNumb} gap={12}>
            <LightGallery plugins={[lgZoom]} mode="lg-fade" licenseKey='Insert License Key here' elementClassNames="lightgallery">
              {images?.map((item, index) => (
                <ImageListItem key={index} className="gallery-item"
                  href={flattenToAppURL(`${item['@id']}/@@images/${item?.image_field}`,)}
                  data-sub-html={item?.description}
                  data-src={flattenToAppURL(`${item['@id']}/@@images/${item?.image_field}`,)}>
                  <Image src={`${item['@id']}/@@images/${item?.image_field}/teaser`} className="img-responsive" alt={item?.description} loading="lazy" />
                </ImageListItem>
              ))}
            </LightGallery>
          </ImageList>
        )}
      </div>
    </>
  );
};

LightGalleryView.propTypes = {
  items: PropTypes.arrayOf(PropTypes.any),
};

export default LightGalleryView;

The default-image.svg used in the LightGalleryEdit.jsx file

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
  <g fill="none" fill-rule="evenodd">
    <rect width="399" height="299" x=".5" y=".5" fill="#D8E1E3" stroke="#878F93" rx="3"/>
    <g transform="translate(130 90)">
      <rect width="140" height="120" fill="#FFF" fill-opacity=".5" rx="3"/>
      <g transform="translate(22 13)">
        <rect width="96" height="96" fill="#93ACC8" rx="3"/>
        <polygon fill="#FFF" points="14.299 72 79.949 72 60.957 44.745 49 59.702 34.836 34.246"/>
        <circle cx="74" cy="29" r="8" fill="#FFF"/>
      </g>
    </g>
  </g>
</svg>

1 Like