Current Time
-{centralEuropeTime[0]}
-{centralEuropeTime[1]}
-{easternTime[0]}
-{easternTime[1]}
+Current Time
+Community around the world
+{option.title}
+{option.subtitle}
+{osLabels[os.id as OperatingSystemId]}
+ {highlighted && ( + + + Recommended for your system + + )} +- {title} -
--
+
- +
-
+
{command}
))}
{title}
+-
{commands.map((command, index) => (
-
- {description} -
+{description}
Special thanks to our contributors
-- The Podman community has contributors from many different organizations, including: -
-Special thanks to our contributors
++ The Podman community has contributors from many different organizations, including: +
+
+
+
Welcome to the new Podman Website!
-
+
- Take a look around, don't forget to check out the new docs layout. Please report
- any bugs to the issue tracker.
+ Take a look around, don't forget to check out the new docs layout. Please report any
+ bugs to the issue tracker.
diff --git a/src/components/layout/CommunityMeetingsCardGrid/index.tsx b/src/components/layout/CommunityMeetingsCardGrid/index.tsx
index 31615cf0c2..4c4ebbed79 100644
--- a/src/components/layout/CommunityMeetingsCardGrid/index.tsx
+++ b/src/components/layout/CommunityMeetingsCardGrid/index.tsx
@@ -1,10 +1,11 @@
-import React, { ReactNode, useEffect, useRef, useState } from 'react';
+import React, { ReactNode, useRef, useState } from 'react';
+import { Icon } from '@iconify/react';
+import { usePluginData } from '@docusaurus/useGlobalData';
import CustomCard from '@site/src/components/ui/CustomCard';
import SubcardGrid from '@site/src/components/layout/SubcardGrid';
-import SectionHeader from '@site/src/components/layout/SectionHeader';
import Dropdown from '@site/src/components/utilities/DropDown';
import CloseIcon from '@site/src/components/shapes/CloseIcon';
-import * as markDownFiles from '@site/static/data/meetings/notes/index'; // ToDo: Lazy load these files
+import VideoEmbed from '@site/src/components/ui/VideoEmbed';
import './styles.css';
@@ -13,44 +14,73 @@ type CommunityMeetingsCardProps = {
subtitle: string;
date: string;
timeZone: string;
- buttons: [
- {
- text: string;
- path: string;
- },
- ];
+ buttons: { text: string; path: string }[];
+};
+
+type MeetingNote = {
+ slug: string;
+ displayDate: string;
+ title: string;
+ recordingLink?: string;
+ recordingEmbedUrl?: string;
+};
+
+type MeetingsData = { community: MeetingNote[]; cabal: MeetingNote[] };
+
+type ModalTriggerContent = {
+ text: string;
+ markDown?: ReactNode;
+ embedUrl?: string;
+ modalHeaderData?: string;
+ icon?: string;
};
type DropdownOptionProps = {
date: string;
- meeting_recording: {
- text: string;
- link: string;
- };
- meeting_minutes: {
- text: string;
- markDown: ReactNode;
- modalHeaderData?: string;
- };
+ meeting_recording: ModalTriggerContent & { link?: string };
+ meeting_minutes: ModalTriggerContent & { path: string };
};
type SubcardButtonProps = {
text: string;
path?: string;
markDown?: ReactNode;
- modalHeaderData?: String;
+ embedUrl?: string;
+ modalHeaderData?: string;
+ icon?: string;
};
type SubcardGridProps = {
buttons: SubcardButtonProps[];
icon: string;
date: string;
+ embedUrl?: string;
+ embedTitle?: string;
};
-function toggleModalOpen(ref, handler) {
- useEffect(() => {
- const listener = event => {
- if (ref?.current?.contains(event.target)) {
+function toModalOption(note: MeetingNote): DropdownOptionProps {
+ return {
+ date: note.displayDate,
+ meeting_minutes: {
+ path: `/community/meetings/${note.slug}`,
+ modalHeaderData: note.title,
+ text: 'Meeting Minutes',
+ icon: 'mdi:text-box-outline',
+ },
+ meeting_recording: {
+ link: note.recordingLink,
+ embedUrl: note.recordingEmbedUrl,
+ modalHeaderData: note.title,
+ text: 'Watch Recording',
+ icon: 'mdi:play-circle-outline',
+ },
+ };
+}
+
+function useOutsideClick(ref: React.RefObject, handler: (event: Event) => void) {
+ React.useEffect(() => {
+ const listener = (event: Event) => {
+ if (ref?.current?.contains(event.target as Node)) {
return;
}
handler(event);
@@ -64,73 +94,45 @@ function toggleModalOpen(ref, handler) {
}, [ref, handler]);
}
-function CommunityMeetingsCardGrid({ cards }) {
- let cabalDropdownOptions: DropdownOptionProps[] = [];
- let MeetingDropdownOptions: DropdownOptionProps[] = [];
-
+function CommunityMeetingsCardGrid({ cards }: { cards: CommunityMeetingsCardProps[] }) {
+ const meetings = usePluginData('meeting-notes-plugin') as MeetingsData;
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalHeader, setModalHeader] = useState(undefined);
- const [meetinNotesMD, setMeetinNotesMD] = useState(undefined);
- const meetingMinutesRef = [useRef(), useRef()];
- const modalRef = useRef();
+ const [modalContent, setModalContent] = useState(undefined);
+ const meetingMinutesRef = [useRef(null), useRef(null)];
+ const modalRef = useRef(null);
+
+ useOutsideClick(modalRef, () => setIsModalOpen(false));
- toggleModalOpen(modalRef, () => setIsModalOpen(false));
+ const communityOptions = meetings.community.map(toModalOption);
+ const cabalOptions = meetings.cabal.map(toModalOption);
const prepareModalHeader = (text: string, date: string) => {
- const modalHeader: ReactNode = (
-
- {text}
- {date}
- setIsModalOpen(false)}>
-
+ setModalHeader(
+
+
+ {text}
+ {date}
-
+
+ ,
);
- setModalHeader(modalHeader);
- };
-
- const populateMeetings = (): void => {
- Object.values(markDownFiles)?.forEach(mdFile => {
- let mdReader = mdFile?.default(useRef());
- mdReader?.props?.children?.forEach(child => {
- let field1: string = child?.props?.children?.[0];
- let field2: object = child?.props?.children?.[1];
- if (typeof field1 == 'string' && (field1.includes('BlueJeans') || field1.includes('Video'))) {
- if (mdFile?.contentTitle?.includes('Cabal')) {
- cabalDropdownOptions.unshift({
- date: (mdFile?.toc?.[0]?.value as string).split(/[0-9]{2}:[0-9]{2}/)[0],
- meeting_minutes: {
- markDown: mdReader,
- modalHeaderData: mdFile['contentTitle'],
- text: 'Meeting Minutes',
- },
- meeting_recording: {
- link: field2?.props?.href,
- text: 'Watch Recording',
- },
- });
- } else {
- MeetingDropdownOptions.unshift({
- date: (mdFile?.toc?.[0]?.value as string).split(/[0-9]{2}:[0-9]{2}/)[0],
- meeting_minutes: {
- markDown: mdReader,
- modalHeaderData: mdFile['contentTitle'],
- text: 'Meeting Minutes',
- },
- meeting_recording: {
- link: field2?.props?.href,
- text: 'Watch Recording',
- },
- });
- }
- }
- });
- });
};
- const toggleIsModalOpen = (...modalData) => {
- modalData && setMeetinNotesMD(modalData[0].markDown);
- prepareModalHeader(modalData[0].modalHeaderData, modalData[1]);
+ const toggleIsModalOpen = (content: ModalTriggerContent, date: string) => {
+ const title = content?.modalHeaderData ?? '';
+ if (content?.embedUrl) {
+ setModalContent( );
+ } else {
+ setModalContent(content?.markDown);
+ }
+ prepareModalHeader(title, date);
setIsModalOpen(true);
};
@@ -138,67 +140,71 @@ function CommunityMeetingsCardGrid({ cards }) {
const { meeting_minutes, meeting_recording, date } = props;
return (
-
- {date}
-
- {meeting_recording?.text}
-
- {
- toggleIsModalOpen(meeting_minutes, date);
- }}
- className="cursor-pointer">
- {meeting_minutes?.text}
-
+
+ {date}
+
+ {meeting_recording?.embedUrl ? (
+ {
+ toggleIsModalOpen(meeting_recording, date);
+ }}
+ className="cursor-pointer font-semibold text-purple-700 no-underline hover:text-purple-900 hover:underline dark:text-purple-500 dark:hover:text-purple-300">
+ {meeting_recording?.text}
+
+ ) : (
+
+ {meeting_recording?.text}
+
+ )}
+
+ {meeting_minutes?.text}
+
+
);
}
function getDropdownOption(options: DropdownOptionProps[]) {
- return options.map(option => );
+ return options.map((option, index) => );
}
- populateMeetings();
-
- let communityMeetingsData: SubcardGridProps[] = [];
- let CabalMeetingsData: SubcardGridProps[] = [];
-
- // get top 2 CommunityMeetings & CabalMeetings for subcards
- for (let i = 0; i < 2; i++) {
- let meeting = MeetingDropdownOptions.shift();
- communityMeetingsData.push({
- date: meeting?.date,
+ const buildSubcardData = (options: DropdownOptionProps[]): SubcardGridProps[] =>
+ options.slice(0, 2).map(meeting => ({
+ date: meeting.date,
icon: 'film-icon',
+ embedUrl: meeting.meeting_recording?.embedUrl,
+ embedTitle: meeting.meeting_recording?.modalHeaderData,
buttons: [
- {
- path: meeting?.meeting_recording?.link,
- text: meeting?.meeting_recording?.text,
- },
- { ...meeting?.meeting_minutes },
- ],
- });
- meeting = cabalDropdownOptions.shift();
- CabalMeetingsData.push({
- date: meeting?.date,
- icon: 'film-icon',
- buttons: [
- {
- path: meeting?.meeting_recording?.link,
- text: meeting?.meeting_recording?.text,
- },
- { ...meeting?.meeting_minutes },
+ // If we can embed the recording directly, skip the "Watch Recording"
+ // button entirely instead of making it open the same video in a modal.
+ ...(meeting.meeting_recording?.embedUrl
+ ? []
+ : [
+ {
+ path: meeting.meeting_recording?.link,
+ text: meeting.meeting_recording?.text,
+ },
+ ]),
+ { ...meeting.meeting_minutes },
],
- });
- }
+ }));
+
+ const communityMeetingsData = buildSubcardData(communityOptions);
+ const cabalMeetingsData = buildSubcardData(cabalOptions);
return (
-
- {cards.map((card: CommunityMeetingsCardProps, index: number) => {
- let meetingsData = index == 1 ? CabalMeetingsData : communityMeetingsData;
+
+ {cards.map((card, index) => {
+ const meetingsData = index == 1 ? cabalMeetingsData : communityMeetingsData;
+ const dropdownOptions = index == 1 ? cabalOptions : communityOptions;
return (
+ className="card-container mb-4 flex w-full flex-col flex-wrap items-center justify-start gap-4 transition duration-150 ease-linear lg:mb-6 lg:flex-1">
-
+
+
+ Most Recent Meetings
+
-
);
})}
+
);
}
diff --git a/src/components/layout/CommunityMeetingsCardGrid/styles.css b/src/components/layout/CommunityMeetingsCardGrid/styles.css
index 6d99a88d40..5fa8f30b7a 100644
--- a/src/components/layout/CommunityMeetingsCardGrid/styles.css
+++ b/src/components/layout/CommunityMeetingsCardGrid/styles.css
@@ -1,40 +1,14 @@
-/* colors (current tailwind standard colors but not included with currently using tailwind installation) */
-.bg-stone-200 {
- background-color: rgb(231 229 228);
-}
-
-/* width custom classes */
-.w-90-screen {
- width: 90vw;
-}
-
-/* height custom classes */
-.h-80-screen {
- height: 85vh;
-}
-
.close-icon {
cursor: pointer;
}
-.md-wrapper {
- padding: 2rem;
- height: 75vh;
-}
-
-.md-wrapper h1,
-h2,
-h3 {
- padding: 0.5rem;
-}
-
-dialog {
- padding: 0;
+.modal-body h1,
+.modal-body h2,
+.modal-body h3 {
+ padding: 0.5rem 0;
}
-.modal-header {
- background-color: white;
- padding: 1rem;
- display: inline-flex;
- justify-content: space-between;
+dialog::backdrop {
+ background-color: rgb(0 0 0 / 0.5);
+ backdrop-filter: blur(4px);
}
diff --git a/src/components/layout/HeroHeader/index.tsx b/src/components/layout/HeroHeader/index.tsx
index fb50fa8a8a..679952e7c9 100644
--- a/src/components/layout/HeroHeader/index.tsx
+++ b/src/components/layout/HeroHeader/index.tsx
@@ -3,9 +3,9 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
import { Icon } from '@iconify/react';
import Button from '@site/src/components/utilities/Button';
import DropdownButton from '@site/src/components/utilities/DropdownButton';
-import Link from '@site/src/components/utilities/Link';
import WaveBorder from '@site/src/components/shapes/WaveBorder';
import operatingSystemData from './installOptions';
+import { detectOperatingSystem } from '@site/src/lib/detectOperatingSystem';
type InstallOptionProps = Card & {
icon: string;
option?: React.ReactNode;
@@ -14,123 +14,108 @@ type InstallOptionProps = Card & {
other?: { path: string; text: string; subtext: string };
};
-const detectOperatingSystem = () => {
- const userAgent = window.navigator.userAgent.toLowerCase().split(' ');
- if (userAgent.find(item => item.includes('windows'))) {
- return 'windows';
- } else if (userAgent.find(item => item.includes('macintosh'))) {
- return 'mac';
- }
- return 'linux';
-};
-
function returnOperatingSystemData() {
- const os = operatingSystemData.find(os => os.id === detectOperatingSystem() && os);
- return os;
+ const os = operatingSystemData.find(os => os.id === detectOperatingSystem());
+ return { os };
}
+const InstallOptionRow = ({
+ title,
+ subtitle,
+ icon,
+ path,
+}: {
+ title: string;
+ subtitle: string;
+ icon: string;
+ path: string;
+}): JSX.Element => (
+
+
+
+
+
+ {title}
+ {subtitle}
+
+
+);
+
const InstallOption = (props): JSX.Element => {
if (!props) {
props = operatingSystemData[0];
}
return (
-
-
-
-
-
- {props.preferred.title}
- {props.preferred.subtitle}
-
-
-
-
+
+
+
+
+ {props.third && }
-
- {props.third && (
-
-
-
-
- {props.third.title}
- {props.third.subtitle}
-
-
-
-
+
+
+ {props.other.text}
+ {props.other.subtext && (
+ {props.other.subtext}
+ )}
- )}
-
+
+
);
};
-function HeroHeader({ title, subtitle, podmanrelease, desktoprelease, image, platforms }) {
+const VersionBadge = ({ icon, text, path }: { icon: string; text: string; path: string }): JSX.Element => (
+
+
+ {text}
+
+);
+
+function HeroHeader({ title, subtitle, podmanrelease, desktoprelease, image, platforms, platformsLabel }) {
return (
-
+
{title}
{subtitle}
- {() => }
+ {() => {
+ const { os } = returnOperatingSystemData();
+ return ;
+ }}
-
-
- Latest stable Podman
-
- -
-
- Latest stable Podman Desktop
-
- -
-
-
+
+
+
+
+
- {platforms[0]}
+ {platformsLabel}
- {platforms.slice(1).map((icon, index) => {
+ {platforms.map(platform => {
return (
- -
-
+ -
+
+
+
);
})}
diff --git a/src/components/layout/HeroHeader/installOptions.ts b/src/components/layout/HeroHeader/installOptions.ts
index 7668a39f5f..8d47aab344 100644
--- a/src/components/layout/HeroHeader/installOptions.ts
+++ b/src/components/layout/HeroHeader/installOptions.ts
@@ -2,7 +2,7 @@ import { LATEST_VERSION, LATEST_DESKTOP_VERSION } from '@site/static/data/global
const operatingSystemData = [
{
id: 'windows',
- preferred:{
+ preferred: {
title: 'Podman Desktop for Windows',
subtitle: `Windows Installer v-${LATEST_DESKTOP_VERSION}`,
icon: 'fa-brands:windows',
@@ -24,7 +24,7 @@ const operatingSystemData = [
path: `https://github.com/podman-container-tools/podman/releases/download/v${LATEST_VERSION}/podman-installer-windows-arm64.msi`,
},
other: {
- path: 'docs/installation',
+ path: '/downloads',
text: 'Other Install Options',
},
},
@@ -44,7 +44,7 @@ const operatingSystemData = [
path: `https://github.com/podman-container-tools/podman/releases/download/v${LATEST_VERSION}/podman-installer-macos-arm64.pkg`,
},
other: {
- path: 'docs/installation',
+ path: '/downloads',
text: 'Other Install Options',
},
},
@@ -54,7 +54,7 @@ const operatingSystemData = [
title: 'Podman CLI for Linux',
subtitle: `Podman Engine v${LATEST_VERSION}`,
icon: 'material-symbols:terminal-rounded',
- path: `docs/installation#installing-on-linux`,
+ path: `/docs/installation#installing-on-linux`,
},
alt: {
title: 'Podman Desktop for Linux',
@@ -63,7 +63,7 @@ const operatingSystemData = [
path: `https://github.com/podman-desktop/podman-desktop/releases/download/v${LATEST_DESKTOP_VERSION}/podman-desktop-${LATEST_DESKTOP_VERSION}.flatpak`,
},
other: {
- path: 'docs/installation',
+ path: '/downloads',
text: 'Other Install Options',
},
},
diff --git a/src/components/layout/PageHeader/index.tsx b/src/components/layout/PageHeader/index.tsx
index 0bb9afa786..a22fc922d9 100644
--- a/src/components/layout/PageHeader/index.tsx
+++ b/src/components/layout/PageHeader/index.tsx
@@ -1,6 +1,5 @@
import React, { PropsWithChildren } from 'react';
import { Icon } from '@iconify/react';
-import WaveBorder from '@site/src/components/shapes/WaveBorder';
import Markdown from '@site/src/components/utilities/Markdown';
import BasicResourcesBox from '@site/src/components/content/BasicResourcesBox';
type ImageSectionProps = LayoutProps & {
@@ -14,36 +13,51 @@ type PageHeaderProps = LayoutProps &
darkColor?: string;
lightColor?: string;
basicResources?: boolean;
- instructions?: { [key:string]: any };
+ instructions?: { [key: string]: any };
};
type PageHeaderSupplementalInfoProps = PageHeaderProps & {
image?: Image;
basicResources?: boolean;
-}
+};
type InstructionsProps = PageHeaderProps & {
- instructions?: { [key:string]: any };
-}
+ instructions?: { [key: string]: any };
+};
const TextBox = ({ grid, display, layout, title, description }: PageHeaderProps): JSX.Element => {
return (
- {title}
+ {title}
);
};
+const DecorativeBlob = () => (
+
+
+
+
+
+
+
+);
+
const Image = ({
- grid,
- display,
- layout,// if array then {[key:string]: any}[];
- image = { path: 'images/optimized/podman-2-196w-172h.webp', alt: 'Podman Logo' },
+ layout, // if array then {[key:string]: any}[];
+ image = { path: '/images/optimized/podman-2-196w-172h.webp', alt: 'Podman Logo' },
}: ImageSectionProps) => {
return (
-
-
+
+
+
);
};
@@ -51,51 +65,56 @@ const Image = ({
function PageHeaderSupplementalInfo({ image, basicResources }: PageHeaderSupplementalInfoProps) {
if (basicResources) {
return (
-
+
+
+
);
- }
- return (
-
- );
+ }
+ return ;
}
function Instructions({ instructions }: InstructionsProps) {
if (instructions) {
return (
- {instructions.title}
+ {instructions.title}
{instructions.subtitle}
-
- )
+ );
}
return null;
}
-function PageHeader({ title, description, image, lightColor = 'white', darkColor = 'gray-900', basicResources, instructions }: PageHeaderProps) {
+function PageHeader({
+ title,
+ description,
+ image,
+ lightColor = 'white',
+ darkColor = 'gray-900',
+ basicResources,
+ instructions,
+}: PageHeaderProps) {
return (
-
-
-
-
-
+
+
+
-
+
-
);
diff --git a/src/components/layout/SectionHeader/index.tsx b/src/components/layout/SectionHeader/index.tsx
index 353d9404ec..0595d4fe72 100644
--- a/src/components/layout/SectionHeader/index.tsx
+++ b/src/components/layout/SectionHeader/index.tsx
@@ -22,11 +22,11 @@ function SectionHeader({
bgColor,
}: SectionHeaderProps): JSX.Element {
const applyTextColor = textGradient
- ? `bg-gradient-radial bg-clip-text text-transparent dark:bg-gradient-radial dark:text-transparent ${textGradientStops}`
+ ? `bg-gradient-to-r bg-clip-text text-transparent dark:bg-gradient-to-r dark:text-transparent ${textGradientStops}`
: `${textColor}`;
return (
-
-
+
+
{title}
diff --git a/src/components/layout/SubcardGrid/index.tsx b/src/components/layout/SubcardGrid/index.tsx
index a431560cac..ad4d62189a 100644
--- a/src/components/layout/SubcardGrid/index.tsx
+++ b/src/components/layout/SubcardGrid/index.tsx
@@ -4,7 +4,7 @@ import { DayOfTheWeek } from '@site/src/components/utilities/DateUtils';
function SubcardGrid({ cards, toggleIsModalOpen }) {
return (
-
+
{cards?.map((card, index) => {
let date = new Date(card.date).getDay();
return (
@@ -16,6 +16,8 @@ function SubcardGrid({ cards, toggleIsModalOpen }) {
text={card.subtitle}
data={card.buttons}
icon={card.icon}
+ embedUrl={card.embedUrl}
+ embedTitle={card.embedTitle}
method={meeting_minutes => {
toggleIsModalOpen(meeting_minutes, card.date);
}}
diff --git a/src/components/pages/MeetingNotePage/index.tsx b/src/components/pages/MeetingNotePage/index.tsx
new file mode 100644
index 0000000000..b6e9071db6
--- /dev/null
+++ b/src/components/pages/MeetingNotePage/index.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import Layout from '@theme/Layout';
+import Markdown from '@site/src/components/utilities/Markdown';
+import VideoEmbed from '@site/src/components/ui/VideoEmbed';
+
+type MeetingNote = {
+ slug: string;
+ displayDate: string;
+ title: string;
+ recordingLink?: string;
+ recordingEmbedUrl?: string;
+ content: string;
+};
+
+// The page already renders the title in its own header, so drop the matching
+// leading `# Title` line from the markdown to avoid showing it twice.
+function stripLeadingTitle(content: string, title: string): string {
+ return content.replace(new RegExp(`^#\\s+${title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*\\n`), '');
+}
+
+function MeetingNotePage({ note }: { note: MeetingNote }): JSX.Element {
+ return (
+
+
+
+ ← Back to Community
+
+
+ {note.title}
+ {note.displayDate}
+
+ {note.recordingEmbedUrl ? (
+
+
+
+ ) : note.recordingLink ? (
+
+ ) : null}
+
+
+
+ );
+}
+
+export default MeetingNotePage;
diff --git a/src/components/ui/ArticleCard/index.tsx b/src/components/ui/ArticleCard/index.tsx
index d1ff58c057..c91bd22684 100644
--- a/src/components/ui/ArticleCard/index.tsx
+++ b/src/components/ui/ArticleCard/index.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { Icon } from '@iconify/react';
import parse from 'html-react-parser';
type ArticleCardProps = {
title: string;
@@ -13,89 +14,103 @@ type ArticleCardProps = {
};
const FALLBACK_IMAGES = [
- 'images/raw/characters/seal-diving.png',
- 'images/raw/characters/seals-swimming.png',
- 'images/raw/characters/confused-seal.png',
- 'images/raw/podman-selkie-385w-358h.png',
+ '/images/raw/characters/seal-diving.png',
+ '/images/raw/characters/seals-swimming.png',
+ '/images/raw/characters/confused-seal.png',
+ '/images/raw/podman-selkie-385w-358h.png',
];
const PublishDate = ({ date, styles }: { date: string; styles?: string }) => {
return (
- {date}
+ className={`${styles} flex h-fit max-w-fit items-center gap-1 rounded-full border border-white/60 bg-white/80 px-2.5 py-1 text-gray-700 shadow-sm backdrop-blur dark:border-white/10 dark:bg-gray-900/80 dark:text-gray-300`}>
+
+ {date}
);
};
-const Title = (title: string) => {
- return {title}
;
-};
function ArticleCard(props: ArticleCardProps) {
// Select fallback image based on index, cycling through available images
const fallbackImage = FALLBACK_IMAGES[(props.index || 0) % FALLBACK_IMAGES.length];
-
+
// Sanitizes HTML and converts it to plain text
const sanitizeHtml = (html: string) => {
if (!html) return html;
- const div = document.createElement("div");
+ const div = document.createElement('div');
div.innerHTML = html;
- return div.textContent || div.innerText || "";
+ return div.textContent || div.innerText || '';
};
const abbrSubtitle = sanitizeHtml(props.subtitle).trim().split(' ').slice(0, 32).join(' ').concat('...');
+
+ const TitleLink = ({ className }: { className?: string }) => (
+
+
+ {sanitizeHtml(props.title)}
+
+
+ );
+
+ const Byline = () => (
+
+
+
+
+
+ {props.display_name}
+
+
+ );
+
if (props.altLayout) {
return (
-
-
-
-
-
-
- {sanitizeHtml(props.title)}
-
-
-
-
-
-
-
+
+
+
+
+
+
);
}
// Normal Layout
- else
- return (
-
-
-
-
- {sanitizeHtml(props.title)}
-
-
+ return (
+
+
+
+
+
+
+
+ );
}
export default ArticleCard;
diff --git a/src/components/ui/Card/index.tsx b/src/components/ui/Card/index.tsx
index fbeffed96c..9feeb8de1b 100644
--- a/src/components/ui/Card/index.tsx
+++ b/src/components/ui/Card/index.tsx
@@ -21,7 +21,7 @@ function CardBody(props) {
}
function CardButtons({ data = [{ text: 'button text' }] }) {
return (
-
+
{data.map((button, index) => (
{index == 0 ? : }
@@ -33,7 +33,7 @@ function CardButtons({ data = [{ text: 'button text' }] }) {
function Card(props) {
return (
-
+
diff --git a/src/components/ui/CustomCard/index.tsx b/src/components/ui/CustomCard/index.tsx
index a36b01f04e..a7ab5bbbc1 100644
--- a/src/components/ui/CustomCard/index.tsx
+++ b/src/components/ui/CustomCard/index.tsx
@@ -1,12 +1,16 @@
import React, { ReactNode } from 'react';
+import { Icon } from '@iconify/react';
import Button from '@site/src/components/utilities/Button/';
import Markdown from '@site/src/components/utilities/Markdown';
+import VideoEmbed from '@site/src/components/ui/VideoEmbed';
import FilmIcon from '../../shapes/FilmIcon';
type SubcardButtonProps = {
text: string;
path?: string;
markDown?: ReactNode;
+ embedUrl?: string;
+ modalHeaderData?: string;
};
type CardInfoButtonProps = {
@@ -15,24 +19,10 @@ type CardInfoButtonProps = {
method: Function;
};
-function CardHeader(props) {
- const { title, subtitle, details } = props;
+function CardBody({ text, className = '' }: { text: string; className?: string }) {
return (
-
- {title}
-
-
-
- );
-}
-
-function CardBody(props) {
- const { text } = props;
- return (
-
-
-
-
+
+
);
}
@@ -48,7 +38,7 @@ function CardInfoButtons(cardInfoButtonProps: CardInfoButtonProps) {
},
} = cardInfoButtonProps;
return (
-
+
{primary
? data.map((button, index) => (
@@ -57,7 +47,7 @@ function CardInfoButtons(cardInfoButtonProps: CardInfoButtonProps) {
))
: data.map((button, index) => (
- {index == 0 ? (
+ {button.path ? (
) : (
Welcome to the new Podman Website!
- Take a look around, don't forget to check out the new docs layout. Please report - any bugs to the issue tracker. + Take a look around, don't forget to check out the new docs layout. Please report any + bugs to the issue tracker.
{text}
-{date}
-{text}
+{date}
{date}
- - {meeting_recording?.text} - - { - toggleIsModalOpen(meeting_minutes, date); - }} - className="cursor-pointer"> - {meeting_minutes?.text} - +{date}
+{title}
+{subtitle}
+{props.preferred.title}
-{props.preferred.subtitle}
-{props.third.title}
-{props.third.subtitle}
-{props.other.text}
+ {props.other.subtext && ( +{props.other.subtext}
+ )}{title}
{subtitle}
- - Latest stable Podman - - - - - Latest stable Podman Desktop - - - - -
+{platforms[0]}
+{platformsLabel}
-
- {platforms.slice(1).map((icon, index) => {
+ {platforms.map(platform => {
return (
-
-
-
+ -
+
+
+
);
})}
diff --git a/src/components/layout/HeroHeader/installOptions.ts b/src/components/layout/HeroHeader/installOptions.ts
index 7668a39f5f..8d47aab344 100644
--- a/src/components/layout/HeroHeader/installOptions.ts
+++ b/src/components/layout/HeroHeader/installOptions.ts
@@ -2,7 +2,7 @@ import { LATEST_VERSION, LATEST_DESKTOP_VERSION } from '@site/static/data/global
const operatingSystemData = [
{
id: 'windows',
- preferred:{
+ preferred: {
title: 'Podman Desktop for Windows',
subtitle: `Windows Installer v-${LATEST_DESKTOP_VERSION}`,
icon: 'fa-brands:windows',
@@ -24,7 +24,7 @@ const operatingSystemData = [
path: `https://github.com/podman-container-tools/podman/releases/download/v${LATEST_VERSION}/podman-installer-windows-arm64.msi`,
},
other: {
- path: 'docs/installation',
+ path: '/downloads',
text: 'Other Install Options',
},
},
@@ -44,7 +44,7 @@ const operatingSystemData = [
path: `https://github.com/podman-container-tools/podman/releases/download/v${LATEST_VERSION}/podman-installer-macos-arm64.pkg`,
},
other: {
- path: 'docs/installation',
+ path: '/downloads',
text: 'Other Install Options',
},
},
@@ -54,7 +54,7 @@ const operatingSystemData = [
title: 'Podman CLI for Linux',
subtitle: `Podman Engine v${LATEST_VERSION}`,
icon: 'material-symbols:terminal-rounded',
- path: `docs/installation#installing-on-linux`,
+ path: `/docs/installation#installing-on-linux`,
},
alt: {
title: 'Podman Desktop for Linux',
@@ -63,7 +63,7 @@ const operatingSystemData = [
path: `https://github.com/podman-desktop/podman-desktop/releases/download/v${LATEST_DESKTOP_VERSION}/podman-desktop-${LATEST_DESKTOP_VERSION}.flatpak`,
},
other: {
- path: 'docs/installation',
+ path: '/downloads',
text: 'Other Install Options',
},
},
diff --git a/src/components/layout/PageHeader/index.tsx b/src/components/layout/PageHeader/index.tsx
index 0bb9afa786..a22fc922d9 100644
--- a/src/components/layout/PageHeader/index.tsx
+++ b/src/components/layout/PageHeader/index.tsx
@@ -1,6 +1,5 @@
import React, { PropsWithChildren } from 'react';
import { Icon } from '@iconify/react';
-import WaveBorder from '@site/src/components/shapes/WaveBorder';
import Markdown from '@site/src/components/utilities/Markdown';
import BasicResourcesBox from '@site/src/components/content/BasicResourcesBox';
type ImageSectionProps = LayoutProps & {
@@ -14,36 +13,51 @@ type PageHeaderProps = LayoutProps &
darkColor?: string;
lightColor?: string;
basicResources?: boolean;
- instructions?: { [key:string]: any };
+ instructions?: { [key: string]: any };
};
type PageHeaderSupplementalInfoProps = PageHeaderProps & {
image?: Image;
basicResources?: boolean;
-}
+};
type InstructionsProps = PageHeaderProps & {
- instructions?: { [key:string]: any };
-}
+ instructions?: { [key: string]: any };
+};
const TextBox = ({ grid, display, layout, title, description }: PageHeaderProps): JSX.Element => {
return (
{title}
+{title}
{instructions.title}
+{instructions.title}
{instructions.subtitle}
-{title}
{note.title}
+{note.displayDate}
+{date}
+ className={`${styles} flex h-fit max-w-fit items-center gap-1 rounded-full border border-white/60 bg-white/80 px-2.5 py-1 text-gray-700 shadow-sm backdrop-blur dark:border-white/10 dark:bg-gray-900/80 dark:text-gray-300`}> +{date}
{title}
; -}; function ArticleCard(props: ArticleCardProps) { // Select fallback image based on index, cycling through available images const fallbackImage = FALLBACK_IMAGES[(props.index || 0) % FALLBACK_IMAGES.length]; - + // Sanitizes HTML and converts it to plain text const sanitizeHtml = (html: string) => { if (!html) return html; - const div = document.createElement("div"); + const div = document.createElement('div'); div.innerHTML = html; - return div.textContent || div.innerText || ""; + return div.textContent || div.innerText || ''; }; const abbrSubtitle = sanitizeHtml(props.subtitle).trim().split(' ').slice(0, 32).join(' ').concat('...'); + + const TitleLink = ({ className }: { className?: string }) => ( ++ + {sanitizeHtml(props.title)} + +
+ ); + + const Byline = () => ( +- - {sanitizeHtml(props.title)} - -
-- - {sanitizeHtml(props.title)} - -
+ return ( +{title}
-
-