Override max width of specific docs (not all docs) - docusaurus

I have a specific "doc" in the "docs" section, for which I need the max width to be bigger (because it contains 2 IFrames side by side).
I see that the guy specifying the max-width is: DocPageLayouMain:
But this component doesn't receive as param a specific page. It is the same for all pages. A child of it, DocItem knows the current page (which may communicate via metadata that it needs the bigger size.
However, it doesn't have the "power" to make the width bigger.
Any hints of how I could achieve this?
Thanks in advance :)

I achieved my goal w/ the following modifs. However, I don't like that I've swizzeled a component = DocItem/Layout marked as "unsafe".
import React from 'react';
import Layout from '#theme-original/DocItem/Layout';
import {useDoc} from '#docusaurus/theme-common/internal';
export default function LayoutWrapper(props) {
const doc = useDoc();
return (
<div class={doc.frontMatter.full_width ? "" : "container"}>
<Layout {...props} />
</div>
);
}
custom.css:
main > .container {
/*
We disable this on the "normal" container, i.e. DocPage/Layout/Main.
We want ONLY for this, hence we base our selector on the parent, which is a DOM element: <main>.
We want to reuse this class in DocItem/Layout.
*/
max-width: initial !important;
}
my-page-that-wants-full-width.mdx
---
description: Live demo
hide_table_of_contents: true
sidebar_position: 10
full_width: true
---
# Demo
...

Related

Does pdf.js allow rendering of a selected (rectangular) part of a page instead of rendering an entire page to a canvas?

Does pdf.js allow to render a PDF page only partially? More specifically, is it possible to tell pdf.js to render a selected "rectangle of pixels" out of an entire PDF page?
Assuming a resolution of 144 dpi, a typical page (DIN A4) would have approx. 684 (width) by 1190 (height) pixels. I would like to render (for example) a rectangle like [100, 100] (top left coordinate in pixels) and [400, 400] (bottom right coordinate in pixels).
A typical use case could be a scanned document with several handwritten notes that I would like to display and further process individually.
I do understand that a "workaround" could be to save the entire page as jpg (or any other suitable bitmap format) and apply some clipping function. But this would for sure be a less performant approach than selected rendering.
pdfs.js uses a viewport object (presumably containing parameters) for rendering. This object contains
height
width
offsetX
offsetY
rotation
scale
transform
viewBox (by default [0, 0, width / scale, height / scale])
One might think that manipulating the viewBox inside it might lead to the desired outcome, but I have found that changing the viewBox parameters does not do anything at all. The entire page is rendered every time that I apply the render method.
What might I have done wrong? Does pdf.js offer the desired functionality? And if so, how can I get it to work? Thank you very much!
Here is a very simple React component demonstrating my approach (that does not work):
import React, { useRef } from 'react';
import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = 'pdf.worker.js';
function PdfTest() {
// useRef hooks
const myCanvas: React.RefObject<HTMLCanvasElement> = useRef(null);
const test = () => {
const loadDocument = pdfjs.getDocument('...');
loadDocument.promise
.then((pdf) => {
return pdf.getPage(1);
})
.then((page) => {
const viewport = page.getViewport({ scale: 2 });
// Here I modify the viewport object on purpose
viewport.viewBox = [100, 100, 400, 400];
if (myCanvas.current) {
const context = myCanvas.current.getContext('2d');
if (context) {
page.render({ canvasContext: context, viewport: viewport });
myCanvas.current.height = viewport.height;
myCanvas.current.width = viewport.width;
}
}
});
};
// Render function
return (
<div>
<button onClick={test}>Test!</button>
<canvas ref={myCanvas} />
</div>
);
}
export default PdfTest;
My initial thought was also to modify a viewBox of page Viewport. This was not the right guess (I hope that you already figured it out).
What do you need really to do to project only a part of a page to canvas is to prepare correctly the transformation of Viewport.
So it will look more or less like following:
const scale = 2
const viewport = page.getViewport({
scale,
offsetX: -100 * scale,
offsetY: - 100 * scale
})
This will move your your box section to the beginning of the canvas coordinates.
What probably you would like to do next is to make a canvas equal to the selected rectangle size (in your case is 300x300 scaled by your scale) and this solved the issue in my case.

Vue: get image width + height returns zero on component load

My component is a modal which displays an <img> with some tags on top.
I get the image dimensions using const size = this.$refs.media.getBoundingClientRect().
However, the height and width is 0, so the tags become placed wrong.
So it seems the image hasn't loaded yet? If I delay getting the height+width with setTimeout, I do get the width and height. But it seems like a not too reliable workaround.
I have "v-cloak" on the modal, but that doesn't work.
I can get the html element with this.$refs.media, but it doesn't mean that the image is loaded, apparently.
So, is there a way to check if the image is loaded? Is there some way to delay the component until the image is loaded?
One more thing: if I add a "width" and "height" in inline style on the img, then those values are available directly. But I don't want to set the size that way because it ruins the responsiveness.
The code doesn't say much more, but it is basically:
<modal>
<vue-draggable-resizable // <-- each tag
v-for="( tag, index ) in tags"
:x="convertX(tag.position.x)"
:y="convertY(tag.position.y)"
(other parameters)
convertX (x) {
const size = this.$refs.media.getBoundingClientRect()
return x * (size.width - 100) // <--- 0 width
async mounted () {
this.renderTags(this.media.tags) // <-- needs img width and height
Updated, solution
As the below answer says, I can use the onload event. I also came across the "#load" event, which I tried and it worked. I can't find it in the documentation though(?) (I searched for #load and v-on:load). Using "onload" directly on the image element didn't work though, so #load seems to be the way.
If I have a data property:
data () {
return {
imgLoaded: false
I can set it to true with a method using #load on the image:
<img
#load="whenImgLoaded"
<template v-if="imgLoaded = true">
<vue-draggable-resizable
:x="convertX(tag.position.x)"
:y="convertY(tag.position.y)"
(other parameters)
methods: {
whenImgLoaded(){
this.imgLoaded = true;
this.renderTags(this.media.tags)
}
You could load the image first via javascript, and after it's loaded run the renderTags method.
E.g., do something like this:
async mounted() {
let image = new Image();
image.onload = function () {
this.renderTags(this.media.tags)
};
image.src = 'https://some-image.png'
}

Object reactivity of complex object

I have an issue with complex object reactivity.
I've read everything I can on stack to find a way to solve it, but nothing works. I've looked at object reactvity and array caveats on vuejs, but not working either.
So I'm asking some help please.
Let me explain the project:
I have 2 columns :
- on the left side, I CRUD my content
- on the right side, I display the results
I have my object, and I'm adding new elements on its "blocks" property (text, images, etc...)
[
{
"uid": 1573224607087,
"animation": "animationName",
"background": {
"bckColor": "#ff55ee",
...
},
"blocks": []
}
]
On click event, I add a new element via this method. Everything is ok, I can CRUD a block.
addBloc(el) {
if (el.type == "text") {
const datasA = {
type: "text",
uid: Date.now(),
slideId: this.pagination.currentPage,
content: el.content,
css: {
color: "#373737",
...
},
...
};
this.slides[this.pagination.currentPage].blocks.push(datasA);
this.$bus.$emit("newElement", datasA);
}
To modify the order of my elements on the display side, I added a drag and drop module to move my block on my DOM tree. Smooth dnd
The problem is, when I drang&drop my element, my object is updated correctly, but the DOM isn't. The dragged element goes back to its initial position.
What is strange, when I try to modify my block (the one I dragged), it modifies the other one.
I'me adding a small video, so you can see what's happening.
Small animation to show you what's going on
I add some more explainations.
I use event bus to communicate between my components, and the right side is using its own object!
I don't know how I can solve this issue.
Tell me if you need more information.
Thank you all !
EDIT 1 :
I added an id to each block to see what happens when I start Drag&Drop. ==> blocks are moving correctly. The problem is not coming from the method onDrop() but from my nested components if I understand well. They don't update. I'm going to search for this new issue.
I've added a new gif to show what's going on.
This is the nested structure
TheSidebar.vue => top container
<Container
:data-index="i"
#drop="onDrop(i,$event)"
:get-child-payload="itemIndex => getChildPayload(i, itemIndex)"
lock-axis="y"
>
<Draggable
v-show="pagination.currentPage === i"
v-for="(input, index) in slides[i].blocks"
:key="index.uid"
:id="'slideBlocksContainer'+index"
class="item"
>
blockId #{{input.uid}}
<AppContainer
v-if="input.type == 'text'"
:blocType="input.type"
:placeholder="input.content"
:id="index"
:slideId="i"
></AppContainer>
</Draggable>
</Container>
Then I have my AppContainer.vue file, which is a top level. In this I have the specific elements of each input type
And I have AppElement.vue file, which is common elements, I can use everywhere
Something like this
TheSidebar
--AppContainer
----AppElement
Know I don't know yet, how to force vue to update AppContainer.vue and AppElement.vue
EDIT 2 :
As suggested in this article I've changed the key of the component and now , when I drag and drop my elements, they stay where they are dropped.
What I see also, is that the AppElement inputs, are related to their own AppContainer. So everything is ok now, but I don't know if it is best practices.
The issue appears to be that the Smooth dnd library you are using is not updating the array of blocks that you are passing to it, it is likely making a copy of the array internally. So when you change the position of the blocks by dragging and dropping, you are not changing your blocks array, just the internal copy.
Looking at the Smooth dnd documentation, if you wanted to access the modified array you could try using the drag-end event handler:
onDragEnd (dragResult) {
const { isSource, payload, willAcceptDrop } = dragResult
}

Office Fabric UI React - HoverCard width

I use HoverCard Office Fabric UI React component to show preview of images, although I can configure height of the card I don't see similar properties for width. What is a possible solution to set width? I saw property styles?: IHoverCardStyles but don't understand how to use it. Thanks.
HoverCard.styles allows to specify style for the host element but what you are after HoverCard.expandingCardProps property.
One option to specify HoverCard custom width would be to override style via IExpandingCardProps.styles like this:
public render() {
const rootStyle = { width: "800px" }; //set custom width
const expandingCardProps: IExpandingCardProps = {
onRenderCompactCard: this.renderCompactCard,
onRenderExpandedCard: this.renderExpandedCard,
renderData: itemDetails,
styles: {"root": rootStyle}
};
return (
<div>
<HoverCard expandingCardProps={expandingCardProps} instantOpenOnClick={true}>
<div>{itemDetails.title}</div>
</HoverCard>
</div>
);
}
Here is the demo for your reference

React Native HTMLView Space between Paragaphs

I currently use (tried some others) for an project HTMLView (https://github.com/jsdf/react-native-htmlview) but its adds to much space between every element.
I just basicly need to render two types of tags P and H3 from a string. I also tried in my style to set margin and padding to 0 - but it hasnt any effect.
Any code suggestions? Or an easy function to run through the item.teaser and replace every P and H3 to a TEXT-Element with a specific class?
<HTMLView addLineBreaks={false} value={item.teaser} stylesheet={htmlStyles.teaser} />
You can try this:
value={"<div>"+item.teaser+"</div>"}
As seen here:
https://github.com/jsdf/react-native-htmlview/issues/202
Cheers :-)
This works const regex = /<br|\n|\r\s*\\?>/g; and then use replace data with regex
Example :
<HTMLView
value={symptom.text.trim().replace(regex, '')}
stylesheet={webViewStyle}
/>
Styles
const webViewStyle = StyleSheet.create({
font: {
color: '#7ab900',
},
});
I think the main issue will be the data which your passing to value param in HTMLView. There might be multiple tags in between and which are wrapped with parent tag. This library expects valid HTML, which means everything should be wrapped in a single top level tag. So wrap the value using main tag / parent tag.
Example: value={"<div>"+item+"</div>"}
This is the other method I found.
use variable which stores regex const regex = /<br|\n|\r\s*\\?>/g;
Then use this regex in replace function
<HTMLView
value={`<div>${symptom.text.trim().replace(regex, '')}</div>`}
stylesheet={webViewStyle}
/>