fix: include logo in screenshot, fix screenshots on small/zoomed windows (#579)
* fix: include logo in screenshot * fix: screenshots on small/zoomed windows, screenshots with no async/other --------- Co-authored-by: Razboy20 <razboy20@gmail.com>
This commit is contained in:
@@ -33,6 +33,8 @@ import CalendarFooter from './CalendarFooter';
|
|||||||
*/
|
*/
|
||||||
export default function Calendar(): ReactNode {
|
export default function Calendar(): ReactNode {
|
||||||
const { courseCells, activeSchedule } = useFlattenedCourseSchedule();
|
const { courseCells, activeSchedule } = useFlattenedCourseSchedule();
|
||||||
|
const asyncCourseCells = courseCells.filter(block => block.async);
|
||||||
|
const displayBottomBar = asyncCourseCells && asyncCourseCells.length > 0;
|
||||||
|
|
||||||
const [course, setCourse] = useState<Course | null>(useCourseFromUrl());
|
const [course, setCourse] = useState<Course | null>(useCourseFromUrl());
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ export default function Calendar(): ReactNode {
|
|||||||
return (
|
return (
|
||||||
<CalendarContext.Provider value>
|
<CalendarContext.Provider value>
|
||||||
<div className='h-full w-full flex flex-col'>
|
<div className='h-full w-full flex flex-col'>
|
||||||
<div className='h-screen flex overflow-auto'>
|
<div className='h-screen flex overflow-auto screenshot:calendar-target'>
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'py-spacing-6 relative h-full min-h-screen w-full flex flex-none flex-col justify-between overflow-clip whitespace-nowrap border-r border-ut-offwhite/50 shadow-[2px_0_10px,rgba(214_210_196_/_.1)] motion-safe:duration-300 motion-safe:ease-out-expo motion-safe:transition-[max-width] screenshot:hidden',
|
'py-spacing-6 relative h-full min-h-screen w-full flex flex-none flex-col justify-between overflow-clip whitespace-nowrap border-r border-ut-offwhite/50 shadow-[2px_0_10px,rgba(214_210_196_/_.1)] motion-safe:duration-300 motion-safe:ease-out-expo motion-safe:transition-[max-width] screenshot:hidden',
|
||||||
@@ -169,7 +171,11 @@ export default function Calendar(): ReactNode {
|
|||||||
setShowSidebar(!showSidebar);
|
setShowSidebar(!showSidebar);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className='min-h-2xl min-w-5xl flex-grow gap-0 pl-spacing-3 screenshot:min-h-xl'>
|
<div
|
||||||
|
className={clsx('min-h-2xl min-w-5xl flex-grow gap-0 pl-spacing-3 screenshot:min-h-xl', {
|
||||||
|
'screenshot:flex-grow-0': displayBottomBar, // html-to-image seems to have a bug with flex-grow
|
||||||
|
})}
|
||||||
|
>
|
||||||
<CalendarGrid courseCells={courseCells} setCourse={setCourse} />
|
<CalendarGrid courseCells={courseCells} setCourse={setCourse} />
|
||||||
</div>
|
</div>
|
||||||
<CalendarBottomBar courseCells={courseCells} setCourse={setCourse} />
|
<CalendarBottomBar courseCells={courseCells} setCourse={setCourse} />
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Button } from '@views/components/common/Button';
|
|||||||
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
|
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
|
||||||
import Divider from '@views/components/common/Divider';
|
import Divider from '@views/components/common/Divider';
|
||||||
import { ExtensionRootWrapper, styleResetClass } from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
import { ExtensionRootWrapper, styleResetClass } from '@views/components/common/ExtensionRoot/ExtensionRoot';
|
||||||
|
import { LargeLogo } from '@views/components/common/LogoIcon';
|
||||||
import ScheduleTotalHoursAndCourses from '@views/components/common/ScheduleTotalHoursAndCourses';
|
import ScheduleTotalHoursAndCourses from '@views/components/common/ScheduleTotalHoursAndCourses';
|
||||||
import useSchedules from '@views/hooks/useSchedules';
|
import useSchedules from '@views/hooks/useSchedules';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
@@ -39,6 +40,9 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<LargeLogo className='hidden! screenshot:flex!' />
|
||||||
|
<Divider className='self-center hidden! screenshot:block!' size='2.5rem' orientation='vertical' />
|
||||||
|
|
||||||
<div className='min-w-[11.5rem] screenshot:transform-origin-left screenshot:scale-120'>
|
<div className='min-w-[11.5rem] screenshot:transform-origin-left screenshot:scale-120'>
|
||||||
<ScheduleTotalHoursAndCourses
|
<ScheduleTotalHoursAndCourses
|
||||||
scheduleName={activeSchedule.name}
|
scheduleName={activeSchedule.name}
|
||||||
|
|||||||
@@ -266,31 +266,38 @@ export const saveAsCal = async () => {
|
|||||||
* @param calendarRef - The reference to the calendar component.
|
* @param calendarRef - The reference to the calendar component.
|
||||||
*/
|
*/
|
||||||
export const saveCalAsPng = () => {
|
export const saveCalAsPng = () => {
|
||||||
|
const WIDTH_PX = 1165;
|
||||||
|
const HEIGHT_PX = 754;
|
||||||
|
const SCALE = 2;
|
||||||
|
|
||||||
const rootNode = document.createElement('div');
|
const rootNode = document.createElement('div');
|
||||||
rootNode.style.backgroundColor = 'white';
|
rootNode.style.backgroundColor = 'white';
|
||||||
rootNode.style.position = 'fixed';
|
rootNode.style.position = 'fixed';
|
||||||
rootNode.style.zIndex = '1000';
|
rootNode.style.zIndex = '1000';
|
||||||
rootNode.style.top = '-10000px';
|
rootNode.style.top = '-10000px';
|
||||||
rootNode.style.left = '-10000px';
|
rootNode.style.left = '-10000px';
|
||||||
rootNode.style.width = '1165px';
|
rootNode.style.width = `${WIDTH_PX}px`;
|
||||||
rootNode.style.height = '754px';
|
rootNode.style.height = `${HEIGHT_PX}px`;
|
||||||
document.body.appendChild(rootNode);
|
document.body.appendChild(rootNode);
|
||||||
|
|
||||||
const clonedNode = document.querySelector('#root')!.cloneNode(true) as HTMLDivElement;
|
const clonedNode = document.querySelector('#root')!.cloneNode(true) as HTMLDivElement;
|
||||||
clonedNode.style.backgroundColor = 'white';
|
clonedNode.style.backgroundColor = 'white';
|
||||||
(clonedNode.firstChild as HTMLDivElement).classList.add('screenshot-in-progress');
|
(clonedNode.firstChild as HTMLDivElement).classList.add('screenshot-in-progress');
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
const calendarTarget = clonedNode.querySelector('.screenshot\\:calendar-target') as HTMLDivElement;
|
||||||
requestAnimationFrame(async () => {
|
calendarTarget.style.width = `${WIDTH_PX}px`;
|
||||||
rootNode.appendChild(clonedNode);
|
calendarTarget.style.height = `${HEIGHT_PX}px`;
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
rootNode.appendChild(clonedNode);
|
||||||
|
requestAnimationFrame(async () => {
|
||||||
try {
|
try {
|
||||||
const screenshotBlob = await toBlob(clonedNode, {
|
const screenshotBlob = await toBlob(clonedNode, {
|
||||||
cacheBust: true,
|
cacheBust: true,
|
||||||
canvasWidth: 1165 * 2,
|
canvasWidth: WIDTH_PX * SCALE,
|
||||||
canvasHeight: 754 * 2,
|
canvasHeight: HEIGHT_PX * SCALE,
|
||||||
skipAutoScale: true,
|
skipAutoScale: true,
|
||||||
pixelRatio: 2,
|
pixelRatio: SCALE,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!screenshotBlob) {
|
if (!screenshotBlob) {
|
||||||
|
|||||||
Reference in New Issue
Block a user