Skip to content

Commit

Permalink
Merge pull request #575 from Lemoncode/dev
Browse files Browse the repository at this point in the history
deploy auto fit text plus b/w bug fix and show file name on footer
  • Loading branch information
brauliodiez authored Nov 24, 2024
2 parents 0a427ed + b9556d4 commit cbc6c48
Show file tree
Hide file tree
Showing 17 changed files with 180 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Layer } from 'konva/lib/Layer';
import { balanceSpacePerItem } from './balance-space';
import { calcTextWidth } from './calc-text-width';
import { calcTextDimensions } from '@/common/utils/calc-text-dimensions';

export const adjustTabWidths = (args: {
tabs: string[];
Expand Down Expand Up @@ -35,9 +35,14 @@ export const adjustTabWidths = (args: {
}
const arrangeTabsInfo = tabs.reduce(
(acc: OriginalTabInfo[], tab, index): OriginalTabInfo[] => {
const tabFullTextWidth =
calcTextWidth(tab, font.fontSize, font.fontFamily, konvaLayer) +
totalInnerXPadding;
const { width: textWidth } = calcTextDimensions(
tab,
font.fontSize,
font.fontFamily,
konvaLayer
);

const tabFullTextWidth = textWidth + totalInnerXPadding;
const desiredWidth = Math.max(totalMinTabSpace, tabFullTextWidth);
return [
...acc,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { calcTextDimensions } from '@/common/utils/calc-text-dimensions';
import { useCanvasContext } from '@/core/providers';
import { useEffect, useRef } from 'react';

export const useResizeOnFontSizeChange = (
id: string,
coords: { x: number; y: number },
text: string,
fontSize: number,
fontVariant: string,
multiline: boolean = false
) => {
const previousFontSize = useRef(fontSize);
const { updateShapeSizeAndPosition, stageRef } = useCanvasContext();
const konvaLayer = stageRef.current?.getLayers()[0];

useEffect(() => {
if (previousFontSize.current !== fontSize) {
previousFontSize.current = fontSize;

const paragraphLines = _extractParagraphLines(text);
const longestLine = _findLongestString(paragraphLines);

const { width, height } = calcTextDimensions(
multiline ? longestLine : text,
fontSize,
fontVariant,
konvaLayer
);

updateShapeSizeAndPosition(
id,
coords,
{
width: width * 1.15,
height: multiline
? _calcParagraphTotalHeight(height, 0.8, paragraphLines.length)
: height,
},
true
);
}
}, [fontSize]);
};

/* Hook Helper functions */
function _extractParagraphLines(multilineText: string) {
return multilineText.split(/\r?\n/).filter(line => line.trim() !== '');
}

function _findLongestString(stringsArray: string[]): string {
return stringsArray.reduce((longest, current) =>
current.length > longest.length ? current : longest
);
}

function _calcParagraphTotalHeight(
heightPerLine: number,
lineHeight: number = 1.3,
linesQty: number
) {
return heightPerLine * lineHeight * linesQty;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-rest
import { useShapeProps } from '../../shapes/use-shape-props.hook';
import { BASIC_SHAPE } from '../front-components/shape.const';
import { useGroupShapeProps } from '../mock-components.utils';
import { useResizeOnFontSizeChange } from './front-text-hooks/resize-fontsize-change.hook';

const heading1SizeRestrictions: ShapeSizeRestrictions = {
minWidth: 40,
Expand Down Expand Up @@ -56,6 +57,8 @@ export const Heading1Shape = forwardRef<any, ShapeProps>((props, ref) => {
ref
);

useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant);

return (
<Group {...commonGroupProps} {...shapeProps}>
<Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-rest
import { useShapeProps } from '../../shapes/use-shape-props.hook';
import { BASIC_SHAPE } from '../front-components/shape.const';
import { useGroupShapeProps } from '../mock-components.utils';
import { useResizeOnFontSizeChange } from './front-text-hooks/resize-fontsize-change.hook';

const heading2SizeRestrictions: ShapeSizeRestrictions = {
minWidth: 40,
Expand Down Expand Up @@ -56,6 +57,8 @@ export const Heading2Shape = forwardRef<any, ShapeProps>((props, ref) => {
ref
);

useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant);

return (
<Group {...commonGroupProps} {...shapeProps}>
<Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-rest
import { BASIC_SHAPE } from '../front-components/shape.const';
import { useShapeProps } from '../../shapes/use-shape-props.hook';
import { useGroupShapeProps } from '../mock-components.utils';
import { useResizeOnFontSizeChange } from './front-text-hooks/resize-fontsize-change.hook';

const heading3SizeRestrictions: ShapeSizeRestrictions = {
minWidth: 40,
Expand Down Expand Up @@ -57,6 +58,8 @@ export const Heading3Shape = forwardRef<any, ShapeProps>((props, ref) => {
ref
);

useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant);

return (
<Group {...commonGroupProps} {...shapeProps}>
<Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-rest
import { BASIC_SHAPE } from '../front-components/shape.const';
import { useShapeProps } from '../../shapes/use-shape-props.hook';
import { useGroupShapeProps } from '../mock-components.utils';
import { useResizeOnFontSizeChange } from './front-text-hooks/resize-fontsize-change.hook';

const linkSizeRestrictions: ShapeSizeRestrictions = {
minWidth: 40,
Expand Down Expand Up @@ -41,10 +42,8 @@ export const LinkShape = forwardRef<any, ShapeProps>((props, ref) => {

const { width: restrictedWidth, height: restrictedHeight } = restrictedSize;

const { textColor, textDecoration, fontSize, textAlignment } = useShapeProps(
otherProps,
BASIC_SHAPE
);
const { textColor, textDecoration, fontSize, textAlignment, fontVariant } =
useShapeProps(otherProps, BASIC_SHAPE);

const commonGroupProps = useGroupShapeProps(
props,
Expand All @@ -53,6 +52,8 @@ export const LinkShape = forwardRef<any, ShapeProps>((props, ref) => {
ref
);

useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant);

return (
<Group {...commonGroupProps} {...shapeProps}>
<Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-rest
import { useShapeProps } from '../../shapes/use-shape-props.hook';
import { BASIC_SHAPE } from '../front-components/shape.const';
import { useGroupShapeProps } from '../mock-components.utils';
import { useResizeOnFontSizeChange } from './front-text-hooks/resize-fontsize-change.hook';

const normaltextSizeRestrictions: ShapeSizeRestrictions = {
minWidth: 40,
Expand Down Expand Up @@ -56,6 +57,8 @@ export const NormaltextShape = forwardRef<any, ShapeProps>((props, ref) => {
ref
);

useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant);

return (
<Group {...commonGroupProps} {...shapeProps}>
<Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-rest
import { BASIC_SHAPE } from '../front-components/shape.const';
import { useShapeProps } from '../../shapes/use-shape-props.hook';
import { useGroupShapeProps } from '../mock-components.utils';
import { useResizeOnFontSizeChange } from './front-text-hooks/resize-fontsize-change.hook';

const paragraphSizeRestrictions: ShapeSizeRestrictions = {
minWidth: 200,
Expand Down Expand Up @@ -40,7 +41,7 @@ export const ParagraphShape = forwardRef<any, ShapeProps>((props, ref) => {
);
const { width: restrictedWidth, height: restrictedHeight } = restrictedSize;

const { textColor, fontSize, textAlignment } = useShapeProps(
const { textColor, fontSize, textAlignment, fontVariant } = useShapeProps(
otherProps,
BASIC_SHAPE
);
Expand All @@ -52,6 +53,8 @@ export const ParagraphShape = forwardRef<any, ShapeProps>((props, ref) => {
ref
);

useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant, true);

return (
<Group {...commonGroupProps} {...shapeProps}>
<Text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-rest
import { useShapeProps } from '../../shapes/use-shape-props.hook';
import { BASIC_SHAPE } from '../front-components/shape.const';
import { useGroupShapeProps } from '../mock-components.utils';
import { useResizeOnFontSizeChange } from './front-text-hooks/resize-fontsize-change.hook';

const smalltextSizeRestrictions: ShapeSizeRestrictions = {
minWidth: 40,
Expand Down Expand Up @@ -56,6 +57,8 @@ export const SmalltextShape = forwardRef<any, ShapeProps>((props, ref) => {
ref
);

useResizeOnFontSizeChange(id, { x, y }, text, fontSize, fontVariant);

return (
<Group {...commonGroupProps} {...shapeProps}>
<Text
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Layer } from 'konva/lib/Layer';

/**
* Virtually calculates the width that a text will occupy, by using a canvas.
* Virtually calculates the height and width that a text will occupy, by using a canvas.
* If a Konva Layer is provided, it will reuse the already existing canvas.
* Otherwise, it will create a canvas within the document, on the fly, to perform the measurement.
* Finaly, as a safety net, a very generic calculation is provided in case the other options are not available.
*/
export const calcTextWidth = (
export const calcTextDimensions = (
inputText: string,
fontSize: number,
fontfamily: string,
Expand All @@ -31,7 +31,10 @@ const _getTextWidthByKonvaMethod = (
) => {
const context = konvaLayer.getContext();
context.font = `${fontSize}px ${fontfamily}`;
return context.measureText(text).width;
const { width, fontBoundingBoxAscent, fontBoundingBoxDescent } =
context.measureText(text);
const totalHeight = fontBoundingBoxAscent + fontBoundingBoxDescent;
return { width, height: totalHeight };
};

const _getTextCreatingNewCanvas = (
Expand All @@ -43,8 +46,13 @@ const _getTextCreatingNewCanvas = (
const context = canvas.getContext('2d');
if (context) {
context.font = `${fontSize}px ${fontfamily}`;
return context.measureText(text).width;
const { width, fontBoundingBoxAscent, fontBoundingBoxDescent } =
context.measureText(text);
const height = fontBoundingBoxAscent + fontBoundingBoxDescent;
return { width, height };
}
const charAverageWidth = fontSize * 0.7;
return text.length * charAverageWidth + charAverageWidth * 0.8;
const width = text.length * charAverageWidth + charAverageWidth * 0.8;
const height = fontSize * 1.5;
return { width, height };
};
1 change: 1 addition & 0 deletions src/core/local-disk/use-local-disk.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const useLocalDisk = () => {
reader.onload = () => {
const content = reader.result as string;
const parseData: QuickMockFileContract = JSON.parse(content);
setFileName(file.name);
if (parseData.version === '0.1') {
// Handle version 0.1 parsing
const appDocument =
Expand Down
1 change: 1 addition & 0 deletions src/core/providers/canvas/canvas.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export interface CanvasContextModel {
addNewPage: () => void;
duplicatePage: (pageIndex: number) => void;
getActivePage: () => Page;
getActivePageName: () => string;
setActivePage: (pageId: string) => void;
deletePage: (pageIndex: number) => void;
editPageTitle: (pageIndex: number, newName: string) => void;
Expand Down
6 changes: 6 additions & 0 deletions src/core/providers/canvas/canvas.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ export const CanvasProvider: React.FC<Props> = props => {
return document.pages[document.activePageIndex];
};

const getActivePageName = () => {
return document.pages[document.activePageIndex].name;
};

const setActivePage = (pageId: string) => {
selectionInfo.clearSelection();
selectionInfo.shapeRefs.current = {};
Expand Down Expand Up @@ -179,6 +183,7 @@ export const CanvasProvider: React.FC<Props> = props => {

const createNewFullDocument = () => {
setDocument(createDefaultDocumentModel());
setFileName('');
};

const deleteSelectedShapes = () => {
Expand Down Expand Up @@ -318,6 +323,7 @@ export const CanvasProvider: React.FC<Props> = props => {
addNewPage,
duplicatePage,
getActivePage,
getActivePageName,
setActivePage,
deletePage,
editPageTitle,
Expand Down
21 changes: 18 additions & 3 deletions src/pods/footer/footer.pod.module.css
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
.container {
display: flex;
justify-content: center;
justify-content: space-between;
align-items: center;
background-color: var(--primary-50);
border-top: 1px solid var(--primary-100);
padding: var(--space-xs) var(--space-md);
}

.title {
flex-grow: 1;
.left,
.center,
.right {
flex: 1;
}

.left {
text-align: left;
}

.center {
text-align: center;
}

.right {
display: flex;
justify-content: flex-end;
}

.zoomContainer {
Expand Down
38 changes: 24 additions & 14 deletions src/pods/footer/footer.pod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,33 @@ import classes from './footer.pod.module.css';
import { ZoomInButton, ZoomOutButton } from './components';

export const FooterPod = () => {
const { scale, setScale } = useCanvasContext();
const { scale, setScale, getActivePageName, fileName } = useCanvasContext();

return (
<footer className={classes.container}>
<p className={classes.title}>Quickmock - © Lemoncode</p>
<div className={classes.zoomContainer}>
<ZoomOutButton
scale={scale}
setScale={setScale}
className={classes.button}
/>
<p className={classes.zoomValue}>{(scale * 100).toFixed(0)} %</p>
<ZoomInButton
scale={scale}
setScale={setScale}
className={classes.button}
/>
<div className={classes.left}>
<p>
<strong>📄 {fileName == '' ? 'New' : fileName}</strong> -{' '}
{getActivePageName()}
</p>
</div>
<div className={classes.center}>
<p>Quickmock - © Lemoncode</p>
</div>
<div className={classes.right}>
<div className={classes.zoomContainer}>
<ZoomOutButton
scale={scale}
setScale={setScale}
className={classes.button}
/>
<p className={classes.zoomValue}>{(scale * 100).toFixed(0)} %</p>
<ZoomInButton
scale={scale}
setScale={setScale}
className={classes.button}
/>
</div>
</div>
</footer>
);
Expand Down
Loading

0 comments on commit cbc6c48

Please sign in to comment.