Subida del módulo y tema de PrestaShop

This commit is contained in:
Kaloyan
2026-04-09 18:31:51 +02:00
parent 12c253296f
commit 16b3ff9424
39262 changed files with 7418797 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
import { Meta } from '@storybook/addon-docs';
<Meta title="Theme/JavaScript/Components/Introduction" />
# Components
The Theme exposes some components using webpack to the `window.Theme.components` object.
Everything exported from [theme.ts](https://github.com/PrestaShop/theme-refacto/blob/develop/src/js/theme.ts) is accessible inside the `window.Theme` object.

View File

@@ -0,0 +1,95 @@
import useAlertContent from './usealert.html';
export default {
title: 'Theme/JavaScript/Components/useAlert',
parameters: {
docs: {
autodocs: false,
}
}
};
export const BasicUsage = () => useAlertContent;
BasicUsage.parameters = {
docs: {
source: {
code: useAlertContent
},
description: {
story: `
<h1>useAlert</h1>
<p><strong>useAlert</strong> is accessible through <code>window.Theme.components.useAlert</code>.</p>
<h2>Concept</h2>
<p>The alert container is the default notifications container of the theme, you can use another one specifying the selector option.</p>
<p>The toast markup is generated on the fly by the javascript, based on bootstrap.</p>
<h2>Parameters</h2>
<p><strong>text</strong> (Optional): string;<br>
<strong>options</strong> (Optional): Options;</p>
<h2>Options</h2>
<p><strong>type</strong>: 'light' | 'dark' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger'<br>
<strong>icon</strong> (Optional): string;<br>
<strong>title</strong> (Optional): string;<br>
<strong>dismissible</strong> (Optional): boolean;<br>
<strong>classlist</strong> (Optional): string;<br>
<strong>selector</strong> (Optional): string;</p>
<h2>Return</h2>
<p>useAlert return an Object, here is the definition:</p>
<pre><code>interface Instance {
instance: Alert | null;
element: HTMLElement | null;
show: () => boolean;
hide: () => boolean;
dispose: () => boolean;
remove: () => boolean;
title: (markup?: string) => string | boolean;
message: (markup?: string) => string | boolean;
}</code></pre>
<h3>Examples</h3>
<p>Overall destructuring is a good practice, if you can, use it!</p>
<p>Without any options:</p>
`
}
}
};
BasicUsage.play = async ({canvasElement}) => {
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
const {show} = window.Theme.components.useAlert('Lorem ipsum sit dolor amet');
show();
});
};
export const WithPrimaryParameter = () => useAlertContent;
WithPrimaryParameter.parameters = {
docs: {
source: {
code: useAlertContent
},
description: {
story: `
<p>Without a different colorscheme:</p>
<pre><code>const {show} = window.Theme.components.useAlert('Lorem ipsum sit dolor amet', {type: 'primary'});
show();</code></pre>
`
}
}
};
WithPrimaryParameter.play = async ({canvasElement}) => {
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
const {show} = window.Theme.components.useAlert('Lorem ipsum sit dolor amet', {type: 'primary'});
show();
});
};

View File

@@ -0,0 +1,6 @@
<div id="notifications">
<div class="container">
</div>
</div>
<button class="btn btn-primary">Click to test</button>

View File

@@ -0,0 +1,81 @@
import useProgressRingContent from './useprogressring.html';
export default {
title: 'Theme/JavaScript/Components/useProgressRing',
parameters: {
docs: {
autodocs: false,
}
}
};
export const BasicUsage = () => useProgressRingContent;
BasicUsage.parameters = {
docs: {
source: {
code: useProgressRingContent
},
description: {
story: `
<h1>useProgressRing</h1>
<p><strong>useProgressRing</strong> is accessible through <code>window.Theme.components.useProgressRing</code>.</p>
<h2>Concept</h2>
<p>You can use the smarty file from <code>components/progress-circle.tpl</code>.</p>
<p>Example: <code>{include file="components/progress-circle.tpl" classes="text-success col-4" size=74 stroke=4 percent=50 text={l s='2 / 4' d='Shop.Theme.Checkout'}}</code></p>
<p>The progress ring use the text color for the ring color.</p>
<p><strong>Size, stroke, percent</strong> are required in order to set the default state of the ring.</p>
<p>Initial calculation for the ring are done in smarty, so every child themes can override it and change the behavior.</p>
<h2>Options</h2>
<p><strong>element</strong>: HTMLElement</p>
<h2>Return</h2>
<p>useProgressRing return an Object, here is the definition:</p>
<pre><code>interface ProgressRingReturn {
setProgress?: (perfect: number) => void
error?: Error
}</code></pre>
<h3>Examples</h3>
<p>Overall destructuring is a good practice, if you can, use it!</p>
`
}
}
};
BasicUsage.play = async ({canvasElement}) => {
const progressElement = document.querySelector(window.prestashop.themeSelectors.progressRing.checkout.element);
const {setProgress, error} = window.Theme.components.useProgressRing(progressElement);
if (!error && setProgress) {
setProgress(75);
}
};
export const WithExample = () => useProgressRingContent;
WithExample.parameters = {
docs: {
source: {
code: useProgressRingContent
},
description: {
story: `
<p>Without a different colorscheme:</p>
<pre><code>const progressElement = document.querySelector<HTMLElement>(window.prestashop.themeSelectors.progressRing.checkout.element);
const {setProgress, error} = window.Theme.components.useProgressRing(progressElement);
if (!error && setProgress) {
setProgress(75);
}</code></pre>
`
}
}
};

View File

@@ -0,0 +1,23 @@
<svg class="progress-ring text-primary col-4" width="74" height="74" style="width: 74px; height: 74px;">
<circle class="progress-ring__background-circle" stroke-width="4" fill="transparent" r="29" cx="37" cy="37"></circle>
<circle class="progress-ring__circle" stroke="currentColor" stroke-width="4" data-percent="50" fill="transparent" r="29" cx="37" cy="37" style="stroke-dasharray: 182.212, 182.212; stroke-dashoffset: 91.5531;"></circle>
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">2 / 4</text>
</svg>
<svg class="progress-ring text-secondary col-4" width="74" height="74" style="width: 74px; height: 74px;">
<circle class="progress-ring__background-circle" stroke-width="4" fill="transparent" r="29" cx="37" cy="37"></circle>
<circle class="progress-ring__circle" stroke="currentColor" stroke-width="4" data-percent="50" fill="transparent" r="29" cx="37" cy="37" style="stroke-dasharray: 182.212, 182.212; stroke-dashoffset: 91.5531;"></circle>
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">2 / 4</text>
</svg>
<svg class="progress-ring text-danger col-4" width="74" height="74" style="width: 74px; height: 74px;">
<circle class="progress-ring__background-circle" stroke-width="4" fill="transparent" r="29" cx="37" cy="37"></circle>
<circle class="progress-ring__circle" stroke="currentColor" stroke-width="4" data-percent="50" fill="transparent" r="29" cx="37" cy="37" style="stroke-dasharray: 182.212, 182.212; stroke-dashoffset: 91.5531;"></circle>
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">2 / 4</text>
</svg>
<svg class="progress-ring text-success col-4" width="74" height="74" style="width: 74px; height: 74px;">
<circle class="progress-ring__background-circle" stroke-width="4" fill="transparent" r="29" cx="37" cy="37"></circle>
<circle class="progress-ring__circle" stroke="currentColor" stroke-width="4" data-percent="50" fill="transparent" r="29" cx="37" cy="37" style="stroke-dasharray: 182.212, 182.212; stroke-dashoffset: 45.5531;"></circle>
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">3 / 4</text>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,203 @@
import { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';
import useToastContent from './usetoast.html'
import useMultipleContent from './multiple.html'
export default {
title: 'Theme/JavaScript/Components/useToast',
parameters: {
docs: {
autodocs: false,
}
}
};
export const BasicUsage = () => useToastContent;
BasicUsage.parameters = {
docs: {
source: {
code: useToastContent
},
description: {
story: `
<h1>useToast</h1>
<p><strong>useToast</strong> is accessible through <code>window.Theme.components.useToast</code>.</p>
<h2>Concept</h2>
<p>The useToast function use the markup of <a href="https://github.com/PrestaShop/theme-refacto/blob/develop/templates/components/toast-container.tpl">toast-container.tpl</a> and <a href="https://github.com/PrestaShop/theme-refacto/blob/develop/templates/components/toast.tpl">toast.tpl</a>.</p>
<p>The toast container is placed on the top right of the viewport by default.</p>
<p>The toast markup is generated on the fly using the <code>&lt;template&gt;</code> element.</p>
<p>If these files has been removed from the theme, it generates everything on-the fly using JavaScript only, to avoid failure cases.</p>
<p>If the template is not on the page, and you override the toast template, if your override is wrong, it will not throw an error to avoid blocking the JavaScript execution but it will send an error to the console and return <code>false</code>.</p>
<h2>Options</h2>
<p><strong>type</strong>: 'light' | 'dark' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger'<br>
<strong>autohide</strong> (Optional): boolean;<br>
<strong>delay</strong> (Optional): number;<br>
<strong>classlist</strong> (Optional): string;<br>
<strong>template</strong> (Optional): string;</p>
<h2>Return</h2>
<p>useToast return an Object, here is the definition:</p>
<pre><code>interface Instance {
// Bootstrap instance
instance: Toast | null;
element: HTMLElement | null;
content: HTMLElement | null;
// Bootstrap methods wrapped
show: () => boolean;
hide: () => boolean;
dispose: () => boolean;
remove: () => boolean;
message: (markup?: string) => string | boolean;
}</code></pre>
<h3>Examples</h3>
<p>Overall destructuring is a good practice, if you can, use it!</p>
<p>Without any options:</p>
`
}
}
};
BasicUsage.play = async ({canvasElement}) => {
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
const {show} = window.Theme.components.useToast('Test');
show();
});
};
export const WithPrimaryParameter = () => useToastContent;
WithPrimaryParameter.parameters = {
docs: {
source: {
code: useToastContent
},
description: {
story: `
<p>Without a different colorscheme:</p>
<pre><code>const {show} = window.Theme.components.useToast('Test', {type: 'primary'});
show();</code></pre>
`
}
}
};
WithPrimaryParameter.play = async ({canvasElement}) => {
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
const {show} = window.Theme.components.useToast('Test', {type: 'primary'});
show();
});
};
export const WithoutAutohide = () => useToastContent;
WithoutAutohide.parameters = {
docs: {
source: {
code: useToastContent
},
description: {
story: `
<p>Without autohide:</p>
<pre><code>const {show} = window.Theme.components.useToast('Test', {autohide: false});
show();</code></pre>
`
}
}
};
WithoutAutohide.play = async ({canvasElement}) => {
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
const {show} = window.Theme.components.useToast('Test', {autohide: false});
show();
});
};
export const WithTemplateOverridden = () => useToastContent;
WithTemplateOverridden.parameters = {
docs: {
source: {
code: useToastContent
},
description: {
story: `
<p>With template overridden:</p>
<pre><code>const myTemplate = \`
<div class="toast toast--override">
<div class="toast-header">My header text</div>
<div class="toast-body"></div>
</div>
\`
const {show} = window.Theme.components.useToast('Test', {template: myTemplate});
show();</code></pre>
`
}
}
};
WithTemplateOverridden.play = async ({canvasElement}) => {
const myTemplate = `
<div class="toast toast--override">
<div class="toast-header">My header text</div>
<div class="toast-body"></div>
</div>
`;
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
const {show} = window.Theme.components.useToast('Test', {template: myTemplate});
show();
});
};
export const MultipleToasts = () => useMultipleContent;
MultipleToasts.parameters = {
docs: {
source: {
code: useMultipleContent
},
description: {
story: `
<p>Use multiple toasts at the same time:</p>
<pre><code>const {useToast} = window.Theme.components;
const btnPrimary = document.querySelector('.btn-primary');
const btnSecondary = document.querySelector('.btn-secondary');
const {show: showPrimaryToast} = useToast('Test with primary', {type: 'primary'});
const {show: showSecondaryToast} = useToast('Test with secondary', {type: 'secondary'});
btnPrimary.addEventListener('click', () => {
showPrimaryToast();
});
btnSecondary.addEventListener('click', () => {
showSecondaryToast();
});</code></pre>
`
}
}
};
MultipleToasts.play = async ({canvasElement}) => {
const {useToast} = window.Theme.components;
const btnPrimary = document.querySelector('.btn-primary');
const btnSecondary = document.querySelector('.btn-secondary');
const {show: showPrimaryToast} = useToast('Test with primary', {type: 'primary'});
const {show: showSecondaryToast} = useToast('Test with secondary', {type: 'secondary'});
btnPrimary.addEventListener('click', () => {
showPrimaryToast();
});
btnSecondary.addEventListener('click', () => {
showSecondaryToast();
});
};

View File

@@ -0,0 +1,2 @@
<button class="btn btn-primary">Click to test</button>
<button class="btn btn-secondary">Click to test</button>

View File

@@ -0,0 +1 @@
<button class="btn btn-primary">Click to test</button>