Skip to content

Commit

Permalink
feat: add wide modal in trasform
Browse files Browse the repository at this point in the history
  • Loading branch information
v8tenko committed Jul 22, 2024
1 parent 138455d commit 783d621
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ import './polyfill';
import './code';
import './cut';
import './term';
import './wide-mode';
34 changes: 34 additions & 0 deletions src/js/wide-mode/apply.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {WIDE_ELEMENTS_SELECTOR} from './constants';
import expand from './icons/expand';
import {modal} from './modal';

const wrap = (target: HTMLElement) => {
if (target.parentElement?.classList.contains('wide-element-wrapper')) {
return;
}

target.classList.add('wide-inner-element');

const handler = document.createElement('div');

handler.innerHTML = expand;
handler.classList.add('wide-content-viewer');
handler.addEventListener('click', () => modal.render(target));

const container = document.createElement('div');

container.classList.add('wide-element-wrapper');

target.before(container);

container.appendChild(handler);
container.appendChild(target);
};

export const applyWideMode = () => {
const allWideElements = Array.from(
document.querySelectorAll(WIDE_ELEMENTS_SELECTOR),
) as HTMLElement[];

allWideElements.forEach(wrap);
};
1 change: 1 addition & 0 deletions src/js/wide-mode/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const WIDE_ELEMENTS_SELECTOR = '[wide-content]';
12 changes: 12 additions & 0 deletions src/js/wide-mode/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export {};

type Template = {
label(name?: string);
content(target?: Element);
};

declare global {
interface Window {
wideTemplate?: HTMLDivElement & Template;
}
}
1 change: 1 addition & 0 deletions src/js/wide-mode/icons/close.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default `<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg" class="close-action"><path fillRule="evenodd" clipRule="evenodd" d="M9.46967 9.46967C9.76256 9.17678 10.2374 9.17678 10.5303 9.46967L14 12.9393L17.4697 9.46967C17.7626 9.17678 18.2374 9.17678 18.5303 9.46967C18.8232 9.76256 18.8232 10.2374 18.5303 10.5303L15.0607 14L18.5303 17.4697C18.8232 17.7626 18.8232 18.2374 18.5303 18.5303C18.2374 18.8232 17.7626 18.8232 17.4697 18.5303L14 15.0607L10.5303 18.5303C10.2374 18.8232 9.76256 18.8232 9.46967 18.5303C9.17678 18.2374 9.17678 17.7626 9.46967 17.4697L12.9393 14L9.46967 10.5303C9.17678 10.2374 9.17678 9.76256 9.46967 9.46967Z" fill="var(--g-color-text-primary)" fillOpacity="0.85"/></svg>`;
1 change: 1 addition & 0 deletions src/js/wide-mode/icons/expand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><path fill="currentColor" fill-rule="evenodd" d="M7.754 2.004a.75.75 0 0 0 0 1.5h4.75v4.742a.75.75 0 0 0 1.5 0V2.754a.75.75 0 0 0-.75-.75zm.492 11.992a.75.75 0 0 0 0-1.5h-4.75V7.754a.75.75 0 0 0-1.5 0v5.492a.75.75 0 0 0 .75.75z" clip-rule="evenodd"/></svg>`;
5 changes: 5 additions & 0 deletions src/js/wide-mode/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {applyWideMode} from './apply';

if (typeof document !== 'undefined') {
window.addEventListener('load', applyWideMode);
}
111 changes: 111 additions & 0 deletions src/js/wide-mode/modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import closeIcon from './icons/close';

const remove = () => {
if (!window.wideTemplate) {
return;
}

window.wideTemplate.style.display = 'none';
window.wideTemplate.content(undefined);
};

const tbodyOf = (node: HTMLElement) => {
if (node.tagName !== 'TABLE') {
return undefined;
}

const elements = Array.from(node.children);

const thead = elements.find((child) => child.tagName === 'THEAD');

if (thead) {
return undefined;
}

const tbody = elements.find((child) => child.tagName === 'TBODY');

return tbody;
};

type ModalContainer = NonNullable<typeof window.wideTemplate>;

/* @todo refactor to markup with innerHTML @v8tenko */

const container = () => {
if (window.wideTemplate) {
return window.wideTemplate;
}

const template = document.createElement('div') as ModalContainer;
template.classList.add('dc-doc-page', 'wide-container');

const overlay = document.createElement('div');
overlay.classList.add('wide-content-overlay');
overlay.addEventListener('click', remove);

const wrapper = document.createElement('div');
wrapper.classList.add('yfm', 'wide-content-wrapper');

const toolbar = document.createElement('div');
toolbar.classList.add('wide-toolbar');

const close = document.createElement('div');
close.classList.add('wide-actions');
close.addEventListener('click', remove);
close.innerHTML = closeIcon;

const title = document.createElement('p');
title.classList.add('wide-entity-name');

template.label = (content: string) => {
title.innerHTML = content;
};

const content = document.createElement('div');
content.classList.add('wide-content');

template.content = (target?: Element) => {
if (typeof target === 'undefined') {
content.innerHTML = '';

return;
}

const cloned = target.cloneNode(true) as HTMLElement;

const tbody = tbodyOf(cloned);

/* used to stretch single tbody to 100% */
tbody?.classList?.add('wide-thead-content');

content.replaceChildren(cloned);
};

toolbar.append(title, close);
wrapper.append(toolbar, content);
template.append(overlay, wrapper);

template.style.display = 'none';
document.body.appendChild(template);

window.wideTemplate = template;

return template;
};

const render = (content: HTMLElement) => {
const template = container();

if (content.title) {
template.label(content.title);
}

template.content(content);

template.style.display = 'flex';
};

export const modal = {
render,
remove,
};
123 changes: 123 additions & 0 deletions src/scss/_modal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
.wide-container {
position: fixed;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
top: 0px;
left: 0px;
z-index: 200;

&.dc-doc-page {
max-width: 100% !important;
}

.wide-content-viewer {
visibility: hidden;
}

.wide-content-wrapper {
z-index: 200;
background-color: var(--g-color-base-background);
height: 90vh;
width: 70vw;
border-radius: 10px;
display: flex;
flex-direction: column;

.wide-content {
height: 95%;
width: 100%;

.wide-inner-element {
max-width: 100%;
width: 100%;
height: 100%;
}

table {
border-radius: 0px;
}

.wide-thead-content {
display: table;
width: 100%;
}
}

.wide-toolbar {
display: flex;
flex-direction: row;
width: 100%;
justify-content: space-between;
align-items: center;
padding: 10px 12px;
}

.wide-entity-name {
margin: 0;
font-size: 18px;
}

.wide-actions {
align-self: flex-end;

.close-action {
cursor: pointer;
border-radius: 3px;

transition: background 300ms;

&:hover {
background: var(--g-color-base-simple-hover);
}
}
}
}
}

.wide-element-wrapper {
display: inline-block;
position: relative;
padding-right: 30px;

&:hover > .wide-content-viewer {
visibility: visible;
}


.wide-inner-element {
max-width: 700px;
}
}

.wide-content-viewer {
position: absolute;
visibility: hidden;
width: 30px;
height: 30px;
z-index: 100;
padding: 6px;
right: -20px;
box-sizing: content-box;
color: var(--g-color-text-primary);
cursor: pointer;

& > svg {
width: 20px;
height: 20px;
}
}


.wide-content-overlay {
z-index: 100;
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
background-color: black;
opacity: 0.6;
}
1 change: 1 addition & 0 deletions src/scss/yfm.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
@import 'file';
@import 'term';
@import 'table';
@import 'modal';

@import '@diplodoc/tabs-extension/runtime';
11 changes: 11 additions & 0 deletions test/table/attrs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ describe('attrs parser tests', () => {
});
});

it('parses wide mode', () => {
const attrs = new AttrsParser();

const result = attrs.parse('{wide-view wide-name="short table"}');

expect(result).toEqual({
attr: ['wide-view'],
'wide-name': ['short table'],
});
});

it('parses full attrs', () => {
const attrs = new AttrsParser();

Expand Down

0 comments on commit 783d621

Please sign in to comment.