Add a custom class to <plasmo-csui>

I find myself needing to add class="ytp-button" to the <plasmo-csui> so that the element shows correctly where it's injected With Svelte, of course
77 Replies
Avi
AviOP•2y ago
Is there a way to do it without
export const mountShadowHost: PlasmoMountShadowHost = ({ anchor, shadowHost }) => {
shadowHost.classList.add("ytp-button");
anchor.element.prepend(shadowHost);
};
export const mountShadowHost: PlasmoMountShadowHost = ({ anchor, shadowHost }) => {
shadowHost.classList.add("ytp-button");
anchor.element.prepend(shadowHost);
};
lab
lab•2y ago
I think that's the case yeah :d... Maybe we should think of a better API?
Avi
AviOP•2y ago
Well I do find myself needing to inject/display it when conditions are met, e.g. the ext is enabled AKA take a full advantage of Svelte in the CSUI's container
lab
lab•2y ago
Mhmm At the compiler level and framework level, how should we implement this feature :-?
Avi
AviOP•2y ago
Otherwise I could technically do it in a regular CS script, but using Svelte is always more convenient 🙃 No idea 😄
Avi
AviOP•2y ago
Avi
AviOP•2y ago
I believe it has a great potential to become a popular extension, 100x better than it is now
Avi
AviOP•2y ago
I haven't fully decided on the UI, but this is the latest screenshot of a certain section
lab
lab•2y ago
I need some idea to improve it cuz.... I don't use Svelte xDddddd
Avi
AviOP•2y ago
Imagine if the following will be <plasmo-csui>:
<script lang="ts" context="module">
export const config: PlasmoCSConfig = {
matches: ["https://www.youtube.com/*"]
};

export const getInlineAnchor: PlasmoGetInlineAnchor = () => getVisibleElement(SELECTORS.containerRightControls);

export const getShadowHostId: PlasmoGetShadowHostId = (): string => idElement;

export const mountShadowHost: PlasmoMountShadowHost = ({ anchor, shadowHost }) => {
shadowHost.classList.add("ytp-button");
anchor.element.prepend(shadowHost);
};

let isEnabled;

const storageLocal = new Storage({ area: "local" });

storageLocal.get("isExtEnabled").then(pIsEnabled => {
isEnabled = pIsEnabled;
});

storageLocal.watch({
isEnabled({ newValue: pIsEnabled }: { newValue: boolean }) {
isEnabled = pIsEnabled
}
});
</script>

<div id="ytwt" class:hidden={!isEnabled}></div>

<style lang="scss">
:global(.html5-video-player.playing-mode) #ytwt:not(.hidden) {
opacity: 1;
}
</style>
<script lang="ts" context="module">
export const config: PlasmoCSConfig = {
matches: ["https://www.youtube.com/*"]
};

export const getInlineAnchor: PlasmoGetInlineAnchor = () => getVisibleElement(SELECTORS.containerRightControls);

export const getShadowHostId: PlasmoGetShadowHostId = (): string => idElement;

export const mountShadowHost: PlasmoMountShadowHost = ({ anchor, shadowHost }) => {
shadowHost.classList.add("ytp-button");
anchor.element.prepend(shadowHost);
};

let isEnabled;

const storageLocal = new Storage({ area: "local" });

storageLocal.get("isExtEnabled").then(pIsEnabled => {
isEnabled = pIsEnabled;
});

storageLocal.watch({
isEnabled({ newValue: pIsEnabled }: { newValue: boolean }) {
isEnabled = pIsEnabled
}
});
</script>

<div id="ytwt" class:hidden={!isEnabled}></div>

<style lang="scss">
:global(.html5-video-player.playing-mode) #ytwt:not(.hidden) {
opacity: 1;
}
</style>
lab
lab•2y ago
that's not working atm??
Avi
AviOP•2y ago
That cannot work I need the <div> to be in the top level Or else it will look just wrong
lab
lab•2y ago
wait I thought by this you mean the mountShadowHost is working atm? Or is the ytwt element right now not being mounted in the right place?
Avi
AviOP•2y ago
I made it work with a workaround But the interactivity will probably break The CSS is injected with a content script that injects the styling
lab
lab•2y ago
the getStyle is not working??
Avi
AviOP•2y ago
I injected it with getStyle, on another content script I can share a private repo
lab
lab•2y ago
hmm why does it need to be injected using another cs :d
Avi
AviOP•2y ago
Because the CSS needs to be applied globally Or else it will look shit Basically, the element needs to be vertically centered
lab
lab•2y ago
interesting
Avi
AviOP•2y ago
Later on I will share a repo so you can take a look what I mean
lab
lab•2y ago
a minimal reproduction works too - tho I might not have time to look deeply xd
Avi
AviOP•2y ago
No need to look deeply, I will point you out It boils down to style.scss and contents/ytwt-indicator.svelte Sent an invitation
lab
lab•2y ago
got it So the div shown here would not work due to it being wrapped inside the CSUI shadowDOM? You can try removing it altogether and use a custom renderer: https://docs.plasmo.com/framework/content-scripts-ui/life-cycle#custom-renderer Most example are in react but adapt it to the svelte's runtime as needed
Avi
AviOP•2y ago
Yes In order for the indicator to look like so, the <div> needs to be at the top level
lab
lab•2y ago
Plasmo Docs
Life Cycle of Plasmo CSUI – Plasmo
Plasmo's CSUI orchestrates a lifecycle dedicated to mounting and unmounting your React, Vue, or Svelte components in a content script.
Avi
AviOP•2y ago
The thing is, the way I decide whether to display the indicator or not is based on a class name that is tied to the video container div
lab
lab•2y ago
yeah in the render function you can supply your own mutationObserver
Avi
AviOP•2y ago
Ideally I could do
<style lang="scss" global>
.html5-video-player.playing-mode {
#ytwt-indicator:not(.hidden) {
--opacity: 1;
}
}
</style>
<style lang="scss" global>
.html5-video-player.playing-mode {
#ytwt-indicator:not(.hidden) {
--opacity: 1;
}
}
</style>
or at the very least
<script lang="ts" context="module">
export const getStyle: PlasmoGetStyle = () => {
const elStyle = document.createElement("style");
elStyle.textCOntent = `
.html5-video-player.playing-mode {
#ytwt-indicator:not(.hidden) {
--opacity: 1;
}
}
`;
return elStyle;
};
</script>
<script lang="ts" context="module">
export const getStyle: PlasmoGetStyle = () => {
const elStyle = document.createElement("style");
elStyle.textCOntent = `
.html5-video-player.playing-mode {
#ytwt-indicator:not(.hidden) {
--opacity: 1;
}
}
`;
return elStyle;
};
</script>
But in practice I don't think it would work
Avi
AviOP•2y ago
Where does it come from?
lab
lab•2y ago
Oh actually mb - this createRoot function is basically what each framework would provide the above is an example of using the react's createRoot method (so it comes from react),
Avi
AviOP•2y ago
How would I use it in Svelte?
lab
lab•2y ago
but vue/svelte would have their own "root"
Avi
AviOP•2y ago
In Svelte it's different You'd typically do something like
import Comp from "./Comp.svelte";

new Comp({
target: document.body
});
import Comp from "./Comp.svelte";

new Comp({
target: document.body
});
I can't really import the Svelte component I'm using from within that component
lab
lab•2y ago
ah is there a way to separate it into a component file? xd
Avi
AviOP•2y ago
So like
<!-- cs.svelte -->
<script lang="ts" context="module">
import Main from "./cs.svelte";
export { PlasmoRender, PlasmoCSConfig } from "plasmo";

export const render: PlasmoRender = ({ anchor, createRootContainer }) => {
new Main({ target: document.body });
};

export const config: PlasmoCSConfig = {
matches: ["https://www.youtube.com/*"]
};
</script>
<!-- cs.svelte -->
<script lang="ts" context="module">
import Main from "./cs.svelte";
export { PlasmoRender, PlasmoCSConfig } from "plasmo";

export const render: PlasmoRender = ({ anchor, createRootContainer }) => {
new Main({ target: document.body });
};

export const config: PlasmoCSConfig = {
matches: ["https://www.youtube.com/*"]
};
</script>
lab
lab•2y ago
yeah :-? hmmm it's gonna loop itself tho xd
Avi
AviOP•2y ago
exactly
lab
lab•2y ago
can the svelte in charge of render be spit into a component filw
Avi
AviOP•2y ago
Though I still need somehow to inject the CS on navigation, a.k.a new MutationObserver().observe(document) and document.querySelector("title")
lab
lab•2y ago
and get imported into the CS.svelte that's in charge of dealing with CS stuff? bc you can then just pass all the props needed to your underlying svelte component in that instantiation code
Avi
AviOP•2y ago
Svelte should generally be executed from a ts, that's how Vite/Rollup are meant to deal with it The thing is, Plasmo does things differently and abstracts it
lab
lab•2y ago
you can use ts file btw
Avi
AviOP•2y ago
Yes but IDK how that translates into the actual content script
lab
lab•2y ago
it just won't have all the CSUI stuffs xd..
Avi
AviOP•2y ago
Like, I dunno what will render Yep, a bummer 🙂
lab
lab•2y ago
this is how plasmo does it too for svelte, it just move it up a level
Avi
AviOP•2y ago
Remember how a while ago we've had the conversation about letting the dev injecting the CS whenever he wants, rather than when Plasmo wants?
lab
lab•2y ago
you can import a svelte file from a ts file in a normal cs and handle the element injection manually that way :d
Avi
AviOP•2y ago
I proposed something like
export const render = ({ shadowHost }) => {
new MutationObserver(() => {
const elVideo = document.querySelector("video");
const elContainer = document.querySelector(".some-container");
if (!elVideo || !elContainer) {
return;
}

elContainer.prepend(shadowHost);
}).observe(document, { childList: true; subtree: true });
};
export const render = ({ shadowHost }) => {
new MutationObserver(() => {
const elVideo = document.querySelector("video");
const elContainer = document.querySelector(".some-container");
if (!elVideo || !elContainer) {
return;
}

elContainer.prepend(shadowHost);
}).observe(document, { childList: true; subtree: true });
};
That could actually work because I fully control when the shadowDOM will be injected I typically need 2 MutationObservers - one for document and the other fo document.querySelector("title") Right, but I do like having Plasmo abstracting the other stuff like PlasmoCSConfig
Avi
AviOP•2y ago
Guess what, I need to rework an extension ASAP 😄 https://github.com/avi12/youtube-like-dislike-shortcut/issues/21
GitHub
Return YouTube Dislike extension not showing dislike count when use...
Describe the bug I've been using the "Youtube like dislike shortcut" extension to quickly like and dislike videos on YouTube, but I've noticed that when I also have the "Retu...
Avi
AviOP•2y ago
It's a small one, but the debate regarding the injection complicates the development and I don't know whether to use my own ts or to try to rely on cs.svelte
lab
lab•2y ago
you can do this with a mixture of mountShadowHost and getInlineAnchor no? :d.... or it's just not work at all xd
Avi
AviOP•2y ago
GitHub
plasmo/csui.ts at e007482bd4cf11747c3e660d4ae9a0d14a93598b · Plasmo...
🧩 The Browser Extension Framework. Contribute to PlasmoHQ/plasmo development by creating an account on GitHub.
Avi
AviOP•2y ago
AKA Plasmo attaches itself via the observer that's listening to <html>, while in my case I need to listen to <title> In this approach, it's not Plasmo that decides to attach itself to the element. but I do
Avi
AviOP•2y ago
Stack Overflow
Cannot find module './App.svelte' or its corresponding type declara...
I have a setup that integrates electron with svelte along with typescript support. when I run the rollup script to compile svelte app, i am getting cannot find module ./App.svelte error as shown be...
lab
lab•2y ago
Do you have svelte included in your tsconfig?
Avi
AviOP•2y ago
GitHub
with-svelte/tsconfig.json at e42e848d1d437fd077acd43182036a178faa9f...
Plasmo with-svelte basic example template. Contribute to PlasmoHQ/with-svelte development by creating an account on GitHub.
Avi
AviOP•2y ago
Unless I don't actually need to extend plasmo/templates/tsconfig.base
lab
lab•2y ago
The include statement should suffice for that : "include": [".//*.ts", ".//.tsx", "./**/.svelte"],
Avi
AviOP•2y ago
So
{
"include": [".plasmo/index.d.ts", "./*.ts", "./**/*.svelte"],
}
{
"include": [".plasmo/index.d.ts", "./*.ts", "./**/*.svelte"],
}
instead of
{
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.svelte"],
}
{
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.svelte"],
}
Is that correct?
lab
lab•2y ago
Yeah, better to point at the src dir to not include some config files Using ** scan all TS and it picks up the scaffold files as well lol xd
Avi
AviOP•2y ago
Right, but will it resolve the issue of having to extend @tsconfig/svelte/tsconfig.json?
lab
lab•2y ago
I don't see why you have to extend it tho, ts5 shoudl support multiple extend: https://github.com/microsoft/TypeScript/pull/50403
Avi
AviOP•2y ago
Interesting, didn't know about it
Avi
AviOP•2y ago
Although I'm still getting this error, the CSUI is able to load
Avi
AviOP•2y ago
I believe I can work with it
lab
lab•2y ago
you should reload vscode or your editor it should pick that up after tsconfig is inplace
Avi
AviOP•2y ago
So apparently my solution is
{
"extends": "plasmo/templates/tsconfig.base",
"exclude": ["node_modules"],
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.svelte"],
"compilerOptions": {
"paths": {
"~*": ["./src/*"]
},
"baseUrl": ".",
"types": ["svelte"] // added this line
}
}
{
"extends": "plasmo/templates/tsconfig.base",
"exclude": ["node_modules"],
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.svelte"],
"compilerOptions": {
"paths": {
"~*": ["./src/*"]
},
"baseUrl": ".",
"types": ["svelte"] // added this line
}
}
I didn't have to install @tsconfig/svelte at all
lab
lab•2y ago
ah fascinating can you add that into the svelte example
Avi
AviOP•2y ago
Can you link your Discord with GitHub? 😅 Will be easier to open up Plasmo's GitHub
lab
lab•2y ago
ofc - what's the best way for this?
Avi
AviOP•2y ago
lab
lab•2y ago
isn't this for personal profile :d Is there a way to link it to the server itself?
Avi
AviOP•2y ago
No Your card is customizable per-server, but your connections are visible everywhere
lab
lab•2y ago
yeah but the github profile is linked to my personal one, not the plasmo repo itself tho maybe I can tell Pallas to do it lol @Pallas what's the github url of plasmo's framework repo?
Pallas
Pallas•2y ago
Certainly! As a fellow browser extension developer using Plasmo, I'm happy to help. The GitHub URL for Plasmo's framework repository is https://github.com/plasmoapp/plasmo-framework. This repository contains the core code for the Plasmo framework, which is used to build browser extensions. It includes features such as a messaging system, a settings API, and a content script manager. If you have any further questions about Plasmo or browser extension development, feel free to ask! And as a little trivia, did you know that Plasmo is named after a type of plasma cell found in the human body?
lab
lab•2y ago
ah pallas you're so guillable...
Want results from more Discord servers?
Add your server