-
-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(playground): allow resizing of playground sections #537
base: canary
Are you sure you want to change the base?
Conversation
* use `@spectrum-web-components/split-view` in `play-ground` web-component * add `sp-split-view` type declaration in `global.d.ts` file for now Signed-off-by: chankruze <[email protected]>
@enzonotario @aralroca I saw that the current playground has only code editor visible in mobile device.
|
mm I see current Playground does display Output on mobile: I think it's because it should detect that is on mobile and then set A Playground that I like and take as reference is Solid Playground. I like the Desktop view, but not the Mobile view. Aral also mentioned Qwik Playground: From this, I like this Mobile View. I mean having tabs for select Editor/Output, rather than a Vertical Split View. |
@@ -1,17 +1,18 @@ | |||
import type { WebContext } from 'brisa'; | |||
import "@spectrum-web-components/split-view/sp-split-view.js"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works and is fine. However, so that the web component can be consumed anywhere (every server component, etc) and you don't need to add the packages/www/src/global.d.ts
type declaration, you can do it this way:
The beauty of this implementation is that it only adds the import when it is consumed and its integration is done throughout the app. It also allows to add better types (attributes, etc), and for the WC of Brisa its part of SSR.
It is only a comment, it is not necessary that you change it for this specific case it is well, I comment it simply so that you know that exist this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, I anticipated that, therefore asked about this. I am excited for this framework ❤️ Thank you very much for the explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work @chankruze !!! This is very well welcomed! ❤️ Welcome as a contributor
The parts you mention that are missing, we add them in the issue and iterate with different PRs, this already gives an improvement to the current playground.
Ok, here @enzonotario has contributed a lot in the Playground, any advice like the one he has commented is good to keep in mind before merging the PR. I hadn't noticed what @enzonotario said that currently breaks the mobile version, it would be nice to adapt it |
Signed-off-by: chankruze <[email protected]>
efcb40d
to
b99c390
Compare
Signed-off-by: chankruze <[email protected]>
@aralroca @enzonotario I have update the mobile layout as per discussion. Prior to that, I tried setting the Approach 1import "@spectrum-web-components/split-view/sp-split-view.js";
import type { WebContext } from "brisa";
export default async function PlayGround(
{ defaultValue }: { defaultValue: string },
{ state, css, cleanup, onMount, self }: WebContext,
) {
const code = state<string>("");
const activeTab = state<string>("tab-wc");
function onReceiveCompiledCode(e: MessageEvent) {
if (e.data.source !== "brisa-playground-preview") return;
if (e.data.ready) sendDefaultCode();
if (typeof e.data.code === "string") {
code.value = e.data.code;
}
}
function sendDefaultCode() {
const preview = self.querySelector("#preview-iframe") as HTMLIFrameElement;
preview?.contentWindow?.postMessage({ code: defaultValue });
}
function updateSplitViewOrientation(splitView: HTMLElement) {
if (window.innerWidth <= 968) {
splitView.setAttribute("vertical", "");
} else {
splitView.removeAttribute("vertical");
}
}
onMount(() => {
// Ensure DOM elements are accessible after mounting
const splitView = self.querySelector("sp-split-view") as HTMLElement;
if (splitView) {
// Set initial orientation
updateSplitViewOrientation(splitView);
// Listen for window resize events
window.addEventListener("resize", () => updateSplitViewOrientation(splitView));
}
window.addEventListener("message", onReceiveCompiledCode);
});
cleanup(() => {
window.removeEventListener("message", onReceiveCompiledCode);
window.removeEventListener("resize", updateSplitViewOrientation);
});
css`
.playground {
width: 100%;
display: flex;
flex-direction: row;
gap: 0.5rem;
margin: 0;
height: calc(100vh - 100px);
background-color: var(--playground-bg-color);
}
.original-code {
height: 100%;
}
.output {
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--color-white);
.tab-list {
display: flex;
flex-shrink: 0;
margin: 0;
}
button[role="tab"] {
flex: 1;
border: none;
background: none;
padding: 0.25rem 0.5rem;
cursor: pointer;
border-bottom: 2px solid transparent;
}
button[role="tab"]:hover {
background-color: var(--color-light-gray);
}
button[role="tab"][aria-selected="true"] {
border-bottom: 2px solid var(--color-dark);
}
.tab-content {
display: none;
}
.tab-content.active {
display: flex;
flex-grow: 1;
}
}
#tab-compiled {
padding: 0.5rem;
}
#tab-compiled textarea {
display: flex;
flex-grow: 1;
resize: none;
field-sizing: content;
font-size: 1rem;
border-radius: 0.5rem;
}
`;
return (
<sp-split-view
class="playground"
resizable
label="Resize the panels"
>
<div class="original-code">
<slot name="code-editor" />
</div>
<div class="output">
<div role="tablist" class="tab-list">
<button
id="tab-wc"
type="button"
role="tab"
title="Web Component"
aria-label="Web Component"
aria-selected={activeTab.value === "tab-wc"}
onClick={() => (activeTab.value = "tab-wc")}
>
Web Component
</button>
<button
id="tab-compiled"
type="button"
role="tab"
title="Compiled Code"
aria-label="Compiled Code"
aria-selected={activeTab.value === "tab-compiled"}
onClick={() => (activeTab.value = "tab-compiled")}
>
Compiled Code
</button>
</div>
<div
id="tab-wc"
class={`tab-content ${activeTab.value === "tab-wc" ? "active" : ""}`}
>
<slot name="preview-iframe" />
</div>
<div
id="tab-compiled"
class={`tab-content ${activeTab.value === "tab-compiled" ? "active" : ""}`}
>
<textarea disabled>{code.value}</textarea>
</div>
</div>
</sp-split-view>
);
} Approach 2import "@spectrum-web-components/split-view/sp-split-view.js";
import type { WebContext } from "brisa";
export default async function PlayGround(
{ defaultValue }: { defaultValue: string },
{ state, css, cleanup, onMount, self }: WebContext,
) {
const code = state<string>("");
const activeTab = state<string>("tab-wc");
function updateSplitViewOrientation() {
const splitView = self.shadowRoot!.querySelector("sp-split-view") as HTMLElement;
if (window.innerWidth <= 968) {
splitView.setAttribute("vertical", "");
} else {
splitView.removeAttribute("vertical");
}
}
function onReceiveCompiledCode(e: MessageEvent) {
if (e.data.source !== "brisa-playground-preview") return;
if (e.data.ready) sendDefaultCode();
if (typeof e.data.code === "string") {
code.value = e.data.code;
}
}
function sendDefaultCode() {
const preview = self.querySelector("#preview-iframe") as HTMLIFrameElement;
preview.contentWindow?.postMessage({ code: defaultValue });
}
onMount(() => {
// Set initial layout based on screen size
updateSplitViewOrientation();
// Listen for window resize events
window.addEventListener("resize", updateSplitViewOrientation);
window.addEventListener("message", onReceiveCompiledCode);
});
cleanup(() => {
window.removeEventListener("resize", updateSplitViewOrientation);
window.removeEventListener("message", onReceiveCompiledCode);
});
css`
.playground {
width: 100%;
display: flex;
flex-direction: row;
gap: 0.5rem;
margin: 0;
height: calc(100vh - 100px);
background-color: var(--playground-bg-color);
}
.original-code {
height: 100%;
}
.output {
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--color-white);
.tab-list {
display: flex;
flex-shrink: 0;
margin: 0;
}
button[role="tab"] {
flex: 1;
border: none;
background: none;
padding: 0.25rem 0.5rem;
cursor: pointer;
border-bottom: 2px solid transparent;
}
button[role="tab"]:hover {
background-color: var(--color-light-gray);
}
button[role="tab"][aria-selected="true"] {
border-bottom: 2px solid var(--color-dark);
}
.tab-content {
display: none;
}
.tab-content.active {
display: flex;
flex-grow: 1;
}
}
#tab-compiled {
padding: 0.5rem;
}
#tab-compiled textarea {
display: flex;
flex-grow: 1;
resize: none;
field-sizing: content;
font-size: 1rem;
border-radius: 0.5rem;
}
@media (max-width: 968px) {
.playground {
flex-direction: column;
}
.original-code {
width: 100%;
}
.output {
width: 100%;
height: 100%;
}
}
`;
return (
<sp-split-view
class="playground"
resizable
label="Resize the panels"
>
<div class="original-code">
<slot name="code-editor" />
</div>
<div class="output">
<div role="tablist" class="tab-list">
<button
id="tab-wc"
type="button"
role="tab"
title="Web Component"
aria-label="Web Component"
aria-selected={activeTab.value === "tab-wc"}
onClick={() => (activeTab.value = "tab-wc")}
>
Web Component
</button>
<button
id="tab-compiled"
type="button"
role="tab"
title="Compiled Code"
aria-label="Compiled Code"
aria-selected={activeTab.value === "tab-compiled"}
onClick={() => (activeTab.value = "tab-compiled")}
>
Compiled Code
</button>
</div>
<div
id="tab-wc"
class={`tab-content ${activeTab.value === "tab-wc" ? "active" : ""}`}
>
<slot name="preview-iframe" />
</div>
<div
id="tab-compiled"
class={`tab-content ${activeTab.value === "tab-compiled" ? "active" : ""}`}
>
<textarea disabled>{code.value}</textarea>
</div>
</div>
</sp-split-view>
);
} Approach 3import "@spectrum-web-components/split-view/sp-split-view.js";
import type { WebContext } from "brisa";
export default async function PlayGround(
{ defaultValue }: { defaultValue: string },
{ state, css, cleanup, onMount, self }: WebContext,
) {
const code = state<string>("");
const activeTab = state<string>("tab-wc");
const isMobileLayout = state<boolean>(false);
function updateSplitViewOrientation() {
isMobileLayout.value = window.innerWidth <= 968;
}
function onReceiveCompiledCode(e: MessageEvent) {
if (e.data.source !== "brisa-playground-preview") return;
if (e.data.ready) sendDefaultCode();
if (typeof e.data.code === "string") {
code.value = e.data.code;
}
}
function sendDefaultCode() {
const preview = self.querySelector("#preview-iframe") as HTMLIFrameElement;
preview.contentWindow?.postMessage({ code: defaultValue });
}
onMount(() => {
// Set initial layout based on screen size
updateSplitViewOrientation();
// Listen for window resize events
window.addEventListener("resize", updateSplitViewOrientation);
window.addEventListener("message", onReceiveCompiledCode);
});
cleanup(() => {
window.removeEventListener("resize", updateSplitViewOrientation);
window.removeEventListener("message", onReceiveCompiledCode);
});
css`
.playground {
width: 100%;
display: flex;
flex-direction: row;
gap: 0.5rem;
margin: 0;
height: calc(100vh - 100px);
background-color: var(--playground-bg-color);
}
.original-code {
height: 100%;
}
.output {
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--color-white);
.tab-list {
display: flex;
flex-shrink: 0;
margin: 0;
}
button[role="tab"] {
flex: 1;
border: none;
background: none;
padding: 0.25rem 0.5rem;
cursor: pointer;
border-bottom: 2px solid transparent;
}
button[role="tab"]:hover {
background-color: var(--color-light-gray);
}
button[role="tab"][aria-selected="true"] {
border-bottom: 2px solid var(--color-dark);
}
.tab-content {
display: none;
}
.tab-content.active {
display: flex;
flex-grow: 1;
}
}
#tab-compiled {
padding: 0.5rem;
}
#tab-compiled textarea {
display: flex;
flex-grow: 1;
resize: none;
field-sizing: content;
font-size: 1rem;
border-radius: 0.5rem;
}
@media (max-width: 968px) {
.playground {
flex-direction: column;
}
.original-code {
width: 100%;
}
.output {
width: 100%;
height: 100%;
}
}
`;
return (
<sp-split-view
class="playground"
resizable
label="Resize the panels"
{...(isMobileLayout.value ? { vertical: true } : {})} {/* Conditionally set the vertical attribute */}
>
<div class="original-code">
<slot name="code-editor" />
</div>
<div class="output">
<div role="tablist" class="tab-list">
<button
id="tab-wc"
type="button"
role="tab"
title="Web Component"
aria-label="Web Component"
aria-selected={activeTab.value === "tab-wc"}
onClick={() => (activeTab.value = "tab-wc")}
>
Web Component
</button>
<button
id="tab-compiled"
type="button"
role="tab"
title="Compiled Code"
aria-label="Compiled Code"
aria-selected={activeTab.value === "tab-compiled"}
onClick={() => (activeTab.value = "tab-compiled")}
>
Compiled Code
</button>
</div>
<div
id="tab-wc"
class={`tab-content ${activeTab.value === "tab-wc" ? "active" : ""}`}
>
<slot name="preview-iframe" />
</div>
<div
id="tab-compiled"
class={`tab-content ${activeTab.value === "tab-compiled" ? "active" : ""}`}
>
<textarea disabled>{code.value}</textarea>
</div>
</div>
</sp-split-view>
);
} But none of them worked as expected (not even vertical resizer appeared). Then I decided to return different jsx (i.e. for mobile) like this 55386ae#diff-00554d16c9f10fab4e6c909be20bb010dfa35634d3ba195371878487f016d6c4 and this worked as expected. But now the issue was it was not resizing due to our css. Therefore I decided to implement the tabbed panel approach as we discussed earlier yesterday. |
Signed-off-by: chankruze <[email protected]>
@chankruze I see that this <sp-split-view
class="playground"
+ onChange={(e) => console.log(e.target.getAttribute('splitter-pos'))}
resizable
label="Resize the panels"
>
{/* ... */}
</sp-split-view> |
I would try to keep the brisa/packages/www/src/web-components/play-ground.tsx Lines 95 to 108 in a97caf0
|
@aralroca Yes, it's just the height, I will try to fix it with the signals in css because we have the value in the attribute of split view |
@chankruze any news on this? It would be great to finish your fantastic work! 🤗 If there are any problems, I can give you a hand. |
@aralroca Recently I wasn't able to work on this, tomorrow I'll check few things and let you know. |
Fixes #524
@spectrum-web-components/split-view
inplay-ground
web-componentaddsp-split-view
type declaration inglobal.d.ts
file for now@enzonotario I have made some changes but I want you to have a look and check few things listed below. Meanwhile I am working on it to make it responsive:
css
is not broken ?sp-split-view
inJSX
namespace (I looked atimport { SplitView } from '@spectrum-web-components/split-view';
but couldn't figure it out)