0
Fork 0
mirror of https://github.com/penpot/penpot-plugins.git synced 2025-01-21 06:02:34 -05:00

feat: update design system css

This commit is contained in:
Juanfran 2024-05-09 14:45:15 +02:00
parent e3252387bd
commit 385c5bfa09
7 changed files with 151 additions and 57 deletions

View file

@ -1,4 +1,4 @@
import { Component, signal } from '@angular/core';
import { Component, effect, signal } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import type { PenpotShape } from '@penpot/plugin-types';
@ -7,7 +7,7 @@ import type { PenpotShape } from '@penpot/plugin-types';
selector: 'app-root',
imports: [ReactiveFormsModule],
template: `
<div class="wrapper" [attr.data-theme]="theme()">
<div class="wrapper">
<h1>Test area!</h1>
<p>
@ -17,20 +17,48 @@ import type { PenpotShape } from '@penpot/plugin-types';
<form [formGroup]="form" (ngSubmit)="updateName()">
<div class="name-wrap">
<label>Selected Shape: </label>
<input type="text" formControlName="name" />
<input class="input" type="text" formControlName="name" />
<button type="submit">Update</button>
</div>
</form>
<div class="actions-wrap">
<button type="button" (click)="createRect()">+Rect</button>
<button type="button" (click)="moveX()">Move X</button>
<button type="button" (click)="moveY()">Move Y</button>
<button type="button" (click)="resizeW()">Resize W</button>
<button type="button" (click)="resizeH()">Resize H</button>
<button type="button" (click)="loremIpsum()">Lorem Ipsum</button>
<button type="button" (click)="addIcon()">+ Icon</button>
<button type="button" (click)="createGrid()">+ Grid</button>
<button
type="button"
data-appearance="secondary"
(click)="createRect()"
>
+Rect
</button>
<button type="button" data-appearance="secondary" (click)="moveX()">
Move X
</button>
<button type="button" data-appearance="secondary" (click)="moveY()">
Move Y
</button>
<button type="button" data-appearance="secondary" (click)="resizeW()">
Resize W
</button>
<button type="button" data-appearance="secondary" (click)="resizeH()">
Resize H
</button>
<button
type="button"
data-appearance="secondary"
(click)="loremIpsum()"
>
Lorem Ipsum
</button>
<button type="button" data-appearance="secondary" (click)="addIcon()">
+ Icon
</button>
<button
type="button"
data-appearance="secondary"
(click)="createGrid()"
>
+ Grid
</button>
</div>
<p>
@ -83,6 +111,10 @@ export class AppComponent {
});
this.#sendMessage({ content: 'ready' });
effect(() => {
document.body.setAttribute('data-theme', this.theme());
});
}
close() {

View file

@ -15,9 +15,9 @@ import type {
import { Manifest, Permissions } from '../models/manifest.model.js';
import { OpenUIOptions } from '../models/open-ui-options.model.js';
import { setModalTheme } from '../create-modal.js';
import openUIApi from './openUI.api.js';
import z from 'zod';
import type { PluginModalElement } from '../plugin-modal.js';
type Callback<T> = (message: T) => void;
@ -30,7 +30,7 @@ export const validEvents = [
export let uiMessagesCallbacks: Callback<unknown>[] = [];
let modal: HTMLElement | null = null;
let modal: PluginModalElement | null = null;
const eventListeners: Map<string, Callback<unknown>[]> = new Map();
@ -45,7 +45,7 @@ export function triggerEvent(
message: EventsMap[keyof EventsMap]
) {
if (type === 'themechange' && modal) {
setModalTheme(modal, message);
modal.setTheme(message);
}
const listeners = eventListeners.get(type) || [];
listeners.forEach((listener) => listener(message));
@ -72,7 +72,7 @@ export function createApi(context: PenpotContext, manifest: Manifest): Penpot {
open: (name: string, url: string, options: OpenUIOptions) => {
const theme = context.getTheme() as 'light' | 'dark';
modal = openUIApi(name, url, theme, options);
setModalTheme(modal, theme);
modal.setTheme(theme);
modal.addEventListener('close', closePlugin, {
once: true,

View file

@ -1,6 +1,6 @@
import z from 'zod';
import { openUISchema } from '../models/open-ui-options.schema';
import { createModal } from '../create-modal';
import { openUISchema } from '../models/open-ui-options.schema.js';
import { createModal } from '../create-modal.js';
export default z
.function()

View file

@ -1,9 +1,5 @@
import { expect, describe, vi } from 'vitest';
import {
createApi,
triggerEvent,
uiMessagesCallbacks,
} from './index.js';
import { createApi, triggerEvent, uiMessagesCallbacks } from './index.js';
import openUIApi from './openUI.api.js';
import { FileState } from '@penpot/plugin-types';
@ -15,6 +11,7 @@ vi.mock('./openUI.api', () => {
removeEventListener: vi.fn(),
remove: vi.fn(),
setAttribute: vi.fn(),
setTheme: vi.fn(),
})),
};
});
@ -256,9 +253,11 @@ describe('Plugin api', () => {
api.ui.open(name, url, options);
const modalMock = openUIApiMock.mock.results[0].value;
expect(modalMock.setAttribute).toHaveBeenCalledWith('data-theme', 'light');
expect(modalMock.setAttribute).toHaveBeenCalledTimes(1);
expect(modalMock.setTheme).toHaveBeenCalledWith('light');
expect(api.getTheme()).toBe('light');
triggerEvent('themechange', 'dark' as any);
expect(modalMock.setTheme).toHaveBeenCalledWith('dark');
});
it('close puglin', () => {

View file

@ -1,10 +1,6 @@
import { OpenUIOptions } from './models/open-ui-options.model';
import type { OpenUIOptions } from './models/open-ui-options.model.js';
import type { PenpotTheme } from '@penpot/plugin-types';
export function setModalTheme(modal: HTMLElement, theme: PenpotTheme) {
modal.setAttribute('data-theme', theme);
}
import type { PluginModalElement } from './plugin-modal.js';
export function createModal(
name: string,
@ -12,14 +8,14 @@ export function createModal(
theme: PenpotTheme,
options: OpenUIOptions
) {
const modal = document.createElement('plugin-modal');
const modal = document.createElement('plugin-modal') as PluginModalElement;
setModalTheme(modal, theme);
modal.setTheme(theme);
modal.setAttribute('title', name);
modal.setAttribute('iframe-src', url);
modal.setAttribute('width', String(options.width || 300));
modal.setAttribute('height', String(options.height || 400));
modal.setAttribute('width', String(options.width || 285));
modal.setAttribute('height', String(options.height || 540));
document.body.appendChild(modal);

View file

@ -1,12 +1,22 @@
const closeSvg = `
<svg width="16" height="16"xmlns="http://www.w3.org/2000/svg" fill="none"><g class="fills"><rect rx="0" ry="0" width="16" height="16" class="frame-background"/></g><g class="frame-children"><path d="M11.997 3.997 8 8l-3.997 4.003m-.006-8L8 8l4.003 3.997" class="fills"/><g class="strokes"><path d="M11.997 3.997 8 8l-3.997 4.003m-.006-8L8 8l4.003 3.997" style="fill: none; stroke-width: 1; stroke: rgb(143, 157, 163); stroke-opacity: 1; stroke-linecap: round;" class="stroke-shape"/></g></g></svg>`;
import type { PenpotTheme } from '@penpot/plugin-types';
export class PluginModalElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
#wrapper: HTMLElement | null = null;
setTheme(theme: PenpotTheme) {
if (this.#wrapper) {
this.#wrapper.setAttribute('data-theme', theme);
}
}
connectedCallback() {
const title = this.getAttribute('title');
const iframeSrc = this.getAttribute('iframe-src');
@ -21,6 +31,9 @@ export class PluginModalElement extends HTMLElement {
throw new Error('Error creating shadow root');
}
this.#wrapper = document.createElement('div');
this.#wrapper.classList.add('wrapper');
const header = document.createElement('div');
header.classList.add('header');
@ -67,52 +80,75 @@ export class PluginModalElement extends HTMLElement {
iframe.contentWindow.postMessage((e as CustomEvent).detail, '*');
});
this.shadowRoot.appendChild(header);
this.shadowRoot.appendChild(iframe);
this.shadowRoot.appendChild(this.#wrapper);
this.#wrapper.appendChild(header);
this.#wrapper.appendChild(iframe);
const style = document.createElement('style');
style.textContent = `
:host {
--spacing-4: 0.25rem;
--spacing-8: calc(var(--spacing-4) * 2);
--spacing-12: calc(var(--spacing-4) * 3);
--spacing-16: calc(var(--spacing-4) * 4);
--spacing-20: calc(var(--spacing-4) * 5);
--spacing-24: calc(var(--spacing-4) * 6);
--spacing-28: calc(var(--spacing-4) * 7);
--spacing-32: calc(var(--spacing-4) * 8);
--spacing-36: calc(var(--spacing-4) * 9);
--spacing-40: calc(var(--spacing-4) * 10);
--font-weight-regular: 400;
--font-weight-bold: 500;
--font-line-height-s: 1.2;
--font-line-height-m: 1.4;
--font-line-height-l: 1.5;
--font-size-s: 12px;
--font-size-m: 14px;
--font-size-l: 16px;
}
[data-theme] {
background-color: var(--color-background-primary);
color: var(--color-foreground-secondary);
}
.wrapper {
display: flex;
flex-direction: column;
position: fixed;
inset-block-end: 10px;
inset-inline-start: 10px;
z-index: 1000;
padding: 20px;
border-radius: 20px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 25px;
border-radius: 15px;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3);
inline-size: ${width}px;
block-size: ${height}px;
}
:host([data-theme="dark"]) {
background: #2e3434;
border: 1px solid #2e3434;
color: #ffffff;
}
:host([data-theme="light"]) {
background: #ffffff;
border: 1px solid #eef0f2;
color: #18181a;
}
.header {
align-items: center;
display: flex;
justify-content: space-between;
border-block-end: 2px solid var(--color-background-quaternary);
padding-block-end: var(--spacing-4);
margin-block-end: var(--spacing-20);
}
button {
background: transparent;
border: 0;
cursor: pointer;
padding: 0;
}
h1 {
font-family: Arial, sans-serif;
font-size: var(--font-size-s);
font-weight: var(--font-weight-bold);
margin: 0;
margin-block-end: 10px;
margin-inline-end: var(--spacing-4);
}
iframe {

View file

@ -33,11 +33,42 @@ ul {
}
[data-theme='dark'] {
background-color: var(--db-quaternary);
color: var(--lb-primary);
color-scheme: dark;
--background-primary: var(--db-primary);
--background-secondary: var(--db-secondary);
--background-tertiary: var(--db-tertiary);
--background-quaternary: var(--db-quaternary);
--foreground-primary: var(--df-primary);
--foreground-secondary: var(--df-secondary);
--accent-primary: var(--da-primary);
--accent-primary-muted: var(--da-primary-muted);
--accent-secondary: var(--da-secondary);
--accent-tertiary: var(--da-tertiary);
--accent-quaternary: var(--da-quaternary);
}
[data-theme='light'] {
background-color: var(--lb-primary);
color: var(--db-primary);
color-scheme: light;
--background-primary: var(--lb-primary);
--background-secondary: var(--lb-secondary);
--background-tertiary: var(--lb-tertiary);
--background-quaternary: var(--lb-quaternary);
--foreground-primary: var(--lf-primary);
--foreground-secondary: var(--lf-secondary);
--accent-primary: var(--la-primary);
--accent-primary-muted: var(--la-primary-muted);
--accent-secondary: var(--la-secondary);
--accent-tertiary: var(--la-tertiary);
--accent-quaternary: var(--la-quaternary);
}
[data-theme] {
background-color: var(--background-primary);
color: var(--foreground-secondary);
}