style: auto-fix linting issues

This commit is contained in:
SamidyFR 2026-02-23 22:58:08 +00:00 committed by github-actions[bot]
parent 38434f5419
commit 700645919c
7 changed files with 408 additions and 169 deletions

View file

@ -13,22 +13,22 @@ Themes in Monochrome are essentially CSS snippets that override the default CSS
/* Base Colors */ /* Base Colors */
--background: #0a0a0a; --background: #0a0a0a;
--foreground: #ededed; --foreground: #ededed;
/* UI Elements */ /* UI Elements */
--card: #1a1a1a; --card: #1a1a1a;
--card-foreground: #ededed; --card-foreground: #ededed;
--border: #2a2a2a; --border: #2a2a2a;
/* Accents */ /* Accents */
--primary: #3b82f6; --primary: #3b82f6;
--primary-foreground: #ffffff; --primary-foreground: #ffffff;
--secondary: #2a2a2a; --secondary: #2a2a2a;
--secondary-foreground: #ededed; --secondary-foreground: #ededed;
/* Text */ /* Text */
--muted: #2a2a2a; --muted: #2a2a2a;
--muted-foreground: #a0a0a0; --muted-foreground: #a0a0a0;
/* Special */ /* Special */
--highlight: #3b82f6; --highlight: #3b82f6;
--ring: #3b82f6; --ring: #3b82f6;
@ -39,39 +39,39 @@ Themes in Monochrome are essentially CSS snippets that override the default CSS
## CSS Variables Reference ## CSS Variables Reference
| Variable | Description | | Variable | Description |
| :--- | :--- | | :----------------------- | :-------------------------------------------------------- |
| `--background` | The main background color for your theme. | | `--background` | The main background color for your theme. |
| `--foreground` | The main text color. | | `--foreground` | The main text color. |
| `--card` | Background color for cards, modals, and panels. | | `--card` | Background color for cards, modals, and panels. |
| `--card-foreground` | Text color inside cards. | | `--card-foreground` | Text color inside cards. |
| `--border` | Color for borders and separators. | | `--border` | Color for borders and separators. |
| `--primary` | Main accent color (buttons, active states). | | `--primary` | Main accent color (buttons, active states). |
| `--primary-foreground` | Text color on top of primary elements. | | `--primary-foreground` | Text color on top of primary elements. |
| `--secondary` | Secondary background (hover states, secondary buttons). | | `--secondary` | Secondary background (hover states, secondary buttons). |
| `--secondary-foreground` | Text color on secondary elements. | | `--secondary-foreground` | Text color on secondary elements. |
| `--muted` | Muted background color (placeholders, skeletons). | | `--muted` | Muted background color (placeholders, skeletons). |
| `--muted-foreground` | Muted text color (subtitles, metadata). | | `--muted-foreground` | Muted text color (subtitles, metadata). |
| `--highlight` | Color used for text highlighting and focus rings. | | `--highlight` | Color used for text highlighting and focus rings. |
| `--radius` | Border radius for cards and buttons (e.g., `8px`, `0px`). | | `--radius` | Border radius for cards and buttons (e.g., `8px`, `0px`). |
| `--font-family` | Font stack for the theme. | | `--font-family` | Font stack for the theme. |
## Using the Theme Editor ## Using the Theme Editor
1. **Open the Theme Store**: Go to Settings > Appearance > Open Theme Store. 1. **Open the Theme Store**: Go to Settings > Appearance > Open Theme Store.
2. **Go to Upload Tab**: Click on the "Upload" tab. 2. **Go to Upload Tab**: Click on the "Upload" tab.
3. **Use the Toolbar**: 3. **Use the Toolbar**:
* **Colors**: Use the color pickers to quickly set the main colors. - **Colors**: Use the color pickers to quickly set the main colors.
* **Styles**: Use the dropdowns to set font and border radius. - **Styles**: Use the dropdowns to set font and border radius.
* **Template**: Click "Template" to insert a starter CSS block. - **Template**: Click "Template" to insert a starter CSS block.
* **Preview**: Click "Preview" to see your changes in real-time on a sample card. - **Preview**: Click "Preview" to see your changes in real-time on a sample card.
4. **Manual Editing**: You can manually edit the CSS in the text area for fine-grained control. 4. **Manual Editing**: You can manually edit the CSS in the text area for fine-grained control.
## Uploading Your Theme ## Uploading Your Theme
1. **Name & Description**: Give your theme a unique name and a brief description. 1. **Name & Description**: Give your theme a unique name and a brief description.
2. **Author Website**: Optionally provide a link to your website. 2. **Author Website**: Optionally provide a link to your website.
* *Note:* If you have a Monochrome profile, your name will automatically link to it. - _Note:_ If you have a Monochrome profile, your name will automatically link to it.
3. **Submit**: Click "Upload Theme". 3. **Submit**: Click "Upload Theme".
Once uploaded, your theme will be available for everyone to browse and apply! Once uploaded, your theme will be available for everyone to browse and apply!

View file

@ -1260,92 +1260,233 @@
<div id="theme-store-modal" class="modal"> <div id="theme-store-modal" class="modal">
<div class="modal-overlay"></div> <div class="modal-overlay"></div>
<div class="modal-content wide" style="height: 80vh; display: flex; flex-direction: column; max-height: 80vh;"> <div
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;"> class="modal-content wide"
<h3 style="margin: 0;">Theme Store</h3> style="height: 80vh; display: flex; flex-direction: column; max-height: 80vh"
<button class="close-modal-btn" style="background:none; border:none; font-size:1.5rem; cursor:pointer; color:var(--muted-foreground);">&times;</button> >
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem">
<h3 style="margin: 0">Theme Store</h3>
<button
class="close-modal-btn"
style="
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--muted-foreground);
"
>
&times;
</button>
</div> </div>
<div class="search-tabs" style="margin-bottom: 1rem;"> <div class="search-tabs" style="margin-bottom: 1rem">
<button class="search-tab active" data-tab="browse">Browse</button> <button class="search-tab active" data-tab="browse">Browse</button>
<button class="search-tab" data-tab="upload">Upload</button> <button class="search-tab" data-tab="upload">Upload</button>
</div> </div>
<div id="theme-store-details" style="display: none; flex-direction: column; height: 100%; overflow: hidden;"> <div
<button class="btn-secondary" id="theme-details-back-btn" style="align-self: flex-start; margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem;"> id="theme-store-details"
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg> style="display: none; flex-direction: column; height: 100%; overflow: hidden"
>
<button
class="btn-secondary"
id="theme-details-back-btn"
style="
align-self: flex-start;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m15 18-6-6 6-6" />
</svg>
Back Back
</button> </button>
<div style="flex: 1; overflow-y: auto; padding-right: 0.5rem;"> <div style="flex: 1; overflow-y: auto; padding-right: 0.5rem">
<div style="display: flex; gap: 1.5rem; flex-wrap: wrap; margin-bottom: 2rem;"> <div style="display: flex; gap: 1.5rem; flex-wrap: wrap; margin-bottom: 2rem">
<div id="theme-details-preview-container" style="width: 300px; height: 220px; flex-shrink: 0; border: 1px solid var(--border); border-radius: var(--radius);"></div> <div
<div style="flex: 1; min-width: 250px;"> id="theme-details-preview-container"
<h2 id="theme-details-name" style="font-size: 2rem; margin-bottom: 0.5rem;"></h2> style="
<div class="meta" style="color: var(--muted-foreground); font-size: 0.9rem; margin-bottom: 1rem; line-height: 1.6;"> width: 300px;
<div id="theme-details-author"></div> height: 220px;
<div>Created: <span id="theme-details-created"></span> - Updated: <span id="theme-details-updated"></span></div> flex-shrink: 0;
<div>Installs: <span id="theme-details-installs">0</span></div> border: 1px solid var(--border);
</div> border-radius: var(--radius);
<button id="theme-details-apply-btn" class="btn-primary" style="width: 100%; max-width: 200px;">Apply Theme</button> "
</div> ></div>
<div style="flex: 1; min-width: 250px">
<h2 id="theme-details-name" style="font-size: 2rem; margin-bottom: 0.5rem"></h2>
<div
class="meta"
style="
color: var(--muted-foreground);
font-size: 0.9rem;
margin-bottom: 1rem;
line-height: 1.6;
"
>
<div id="theme-details-author"></div>
<div>
Created: <span id="theme-details-created"></span> - Updated:
<span id="theme-details-updated"></span>
</div>
<div>Installs: <span id="theme-details-installs">0</span></div>
</div>
<button
id="theme-details-apply-btn"
class="btn-primary"
style="width: 100%; max-width: 200px"
>
Apply Theme
</button>
</div>
</div> </div>
<div style="margin-bottom: 2rem;"> <div style="margin-bottom: 2rem">
<h3 style="font-size: 1.2rem; margin-bottom: 0.5rem;">Description</h3> <h3 style="font-size: 1.2rem; margin-bottom: 0.5rem">Description</h3>
<p id="theme-details-desc" style="white-space: pre-wrap; color: var(--foreground); line-height: 1.6;"></p> <p
id="theme-details-desc"
style="white-space: pre-wrap; color: var(--foreground); line-height: 1.6"
></p>
</div> </div>
</div> </div>
</div> </div>
<div id="theme-store-browse" class="search-tab-content active" style="flex: 1; overflow-y: auto; min-height: 0;"> <div
<div class="track-list-search-container" style="margin: 0 0 1rem 0;"> id="theme-store-browse"
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="search-icon"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg> class="search-tab-content active"
<input type="search" id="theme-store-search" placeholder="Search themes..." class="track-list-search-input" autocomplete="off"> style="flex: 1; overflow-y: auto; min-height: 0"
>
<div class="track-list-search-container" style="margin: 0 0 1rem 0">
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="search-icon"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
<input
type="search"
id="theme-store-search"
placeholder="Search themes..."
class="track-list-search-input"
autocomplete="off"
/>
</div> </div>
<div id="community-themes-grid" class="card-grid"> <div id="community-themes-grid" class="card-grid"></div>
</div> <div id="theme-store-loading" style="text-align: center; padding: 2rem; display: none">
<div id="theme-store-loading" style="text-align: center; padding: 2rem; display: none;"> <div class="animate-spin" style="display: inline-block">
<div class="animate-spin" style="display: inline-block;"> <svg
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg> xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
</svg>
</div> </div>
</div> </div>
</div> </div>
<div id="theme-store-upload" class="search-tab-content" style="flex: 1; overflow-y: auto; min-height: 0;"> <div
<div id="theme-upload-auth-message" style="display: none; text-align: center; padding: 2rem; flex-direction: column; align-items: center; gap: 1rem;"> id="theme-store-upload"
class="search-tab-content"
style="flex: 1; overflow-y: auto; min-height: 0"
>
<div
id="theme-upload-auth-message"
style="
display: none;
text-align: center;
padding: 2rem;
flex-direction: column;
align-items: center;
gap: 1rem;
"
>
<p>You need to be logged in to upload themes.</p> <p>You need to be logged in to upload themes.</p>
<button class="btn-primary" id="theme-store-login-btn">Go to Login</button> <button class="btn-primary" id="theme-store-login-btn">Go to Login</button>
</div> </div>
<form id="theme-upload-form"> <form id="theme-upload-form">
<div style="margin-bottom: 1rem;"> <div style="margin-bottom: 1rem">
<label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem;">Theme Name</label> <label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem">Theme Name</label>
<input type="text" id="theme-upload-name" class="template-input" placeholder="My Awesome Theme" required> <input
type="text"
id="theme-upload-name"
class="template-input"
placeholder="My Awesome Theme"
required
/>
</div> </div>
<div style="margin-bottom: 1rem;"> <div style="margin-bottom: 1rem">
<label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem;">Description</label> <label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem">Description</label>
<textarea id="theme-upload-desc" class="template-input" placeholder="Describe your theme..." style="min-height: 80px; resize: vertical;"></textarea> <textarea
id="theme-upload-desc"
class="template-input"
placeholder="Describe your theme..."
style="min-height: 80px; resize: vertical"
></textarea>
</div> </div>
<div style="margin-bottom: 1rem;"> <div style="margin-bottom: 1rem">
<label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem;">Author Website (Optional)</label> <label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem"
<input type="url" id="theme-upload-website" class="template-input" placeholder="https://example.com"> >Author Website (Optional)</label
<p style="font-size: 0.8rem; color: var(--muted-foreground); margin-top: 0.25rem;"> >
<input
type="url"
id="theme-upload-website"
class="template-input"
placeholder="https://example.com"
/>
<p style="font-size: 0.8rem; color: var(--muted-foreground); margin-top: 0.25rem">
It is recommended to create a Monochrome profile instead. It is recommended to create a Monochrome profile instead.
</p> </p>
</div> </div>
<div style="margin-bottom: 1rem;"> <div style="margin-bottom: 1rem">
<label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem;">CSS</label> <label style="display: block; margin-bottom: 0.5rem; font-size: 0.9rem">CSS</label>
<p style="font-size: 0.8rem; color: var(--muted-foreground); margin-bottom: 0.5rem;"> <p style="font-size: 0.8rem; color: var(--muted-foreground); margin-bottom: 0.5rem">
Define your CSS variables or custom styles here. <a href="https://github.com/monochrome-music/monochrome/blob/main/THEME_GUIDE.md" target="_blank" style="text-decoration: underline; color: var(--primary);">Read the Theme Guide</a>. Define your CSS variables or custom styles here.
<a
href="https://github.com/monochrome-music/monochrome/blob/main/THEME_GUIDE.md"
target="_blank"
style="text-decoration: underline; color: var(--primary)"
>Read the Theme Guide</a
>.
</p> </p>
<div class="theme-editor-toolbar"> <div class="theme-editor-toolbar">
<div class="color-picker-group"> <div class="color-picker-group">
<input type="color" id="te-bg-color" title="Background"> <input type="color" id="te-bg-color" title="Background" />
<input type="color" id="te-fg-color" title="Foreground"> <input type="color" id="te-fg-color" title="Foreground" />
<input type="color" id="te-primary-color" title="Primary"> <input type="color" id="te-primary-color" title="Primary" />
<input type="color" id="te-sec-color" title="Secondary"> <input type="color" id="te-sec-color" title="Secondary" />
<input type="color" id="te-accent-color" title="Accent/Highlight"> <input type="color" id="te-accent-color" title="Accent/Highlight" />
<input type="color" id="te-card-color" title="Card Background"> <input type="color" id="te-card-color" title="Card Background" />
<input type="color" id="te-border-color" title="Border Color"> <input type="color" id="te-border-color" title="Border Color" />
<input type="color" id="te-muted-color" title="Muted Text"> <input type="color" id="te-muted-color" title="Muted Text" />
</div> </div>
<div class="style-picker-group"> <div class="style-picker-group">
<select id="te-font-family" title="Font Family"> <select id="te-font-family" title="Font Family">
@ -1355,7 +1496,21 @@
<option value="'Courier New', monospace">Mono</option> <option value="'Courier New', monospace">Mono</option>
<option value="'Times New Roman', serif">Serif</option> <option value="'Times New Roman', serif">Serif</option>
</select> </select>
<input type="text" id="te-font-custom" placeholder="Custom Font..." style="height: 24px; padding: 0 4px; font-size: 0.75rem; width: 100px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--input); color: var(--foreground);"> <input
type="text"
id="te-font-custom"
placeholder="Custom Font..."
style="
height: 24px;
padding: 0 4px;
font-size: 0.75rem;
width: 100px;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--input);
color: var(--foreground);
"
/>
<select id="te-radius" title="Border Radius"> <select id="te-radius" title="Border Radius">
<option value="">Radius...</option> <option value="">Radius...</option>
<option value="0px">Square</option> <option value="0px">Square</option>
@ -1365,11 +1520,31 @@
</select> </select>
</div> </div>
<div class="editor-actions"> <div class="editor-actions">
<button type="button" id="te-insert-template" class="btn-secondary" style="padding: 2px 8px; font-size: 0.8rem;">Template</button> <button
<button type="button" id="te-toggle-preview" class="btn-secondary" style="padding: 2px 8px; font-size: 0.8rem;">Preview</button> type="button"
id="te-insert-template"
class="btn-secondary"
style="padding: 2px 8px; font-size: 0.8rem"
>
Template
</button>
<button
type="button"
id="te-toggle-preview"
class="btn-secondary"
style="padding: 2px 8px; font-size: 0.8rem"
>
Preview
</button>
</div> </div>
</div> </div>
<textarea id="theme-upload-css" class="template-input" style="min-height: 200px; font-family: monospace; white-space: pre;" placeholder=":root {&#10; --background: #000000;&#10; --foreground: #ffffff;&#10; /* ... */&#10;}" required></textarea> <textarea
id="theme-upload-css"
class="template-input"
style="min-height: 200px; font-family: monospace; white-space: pre"
placeholder=":root {&#10; --background: #000000;&#10; --foreground: #ffffff;&#10; /* ... */&#10;}"
required
></textarea>
</div> </div>
<div class="modal-actions"> <div class="modal-actions">
<button type="submit" class="btn-primary">Upload Theme</button> <button type="submit" class="btn-primary">Upload Theme</button>
@ -1379,7 +1554,7 @@
</div> </div>
</div> </div>
<div id="theme-preview-window" style="display: none;"></div> <div id="theme-preview-window" style="display: none"></div>
<div id="tracker-modal" class="modal tracker-modal"> <div id="tracker-modal" class="modal tracker-modal">
<div class="modal-overlay"></div> <div class="modal-overlay"></div>
@ -3120,15 +3295,50 @@
<div class="theme-option" data-theme="latte">Latte</div> <div class="theme-option" data-theme="latte">Latte</div>
<div class="theme-option" data-theme="custom">Custom</div> <div class="theme-option" data-theme="custom">Custom</div>
</div> </div>
<div id="applied-community-theme-container" style="display: none; margin-top: 1rem;"> <div id="applied-community-theme-container" style="display: none; margin-top: 1rem">
<button id="applied-community-theme-btn" class="btn-secondary" style="width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 1rem;"> <button
id="applied-community-theme-btn"
class="btn-secondary"
style="
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
"
>
<span>Applied Community Theme</span> <span>Applied Community Theme</span>
<span id="applied-theme-name" style="color: var(--muted-foreground); font-size: 0.9rem;"></span> <span
id="applied-theme-name"
style="color: var(--muted-foreground); font-size: 0.9rem"
></span>
</button> </button>
<div id="community-theme-details-panel" style="display: none; padding: 1rem; background: var(--secondary); border-radius: var(--radius); margin-top: 0.5rem; border: 1px solid var(--border);"> <div
<div style="margin-bottom: 0.5rem; font-weight: 600;" id="ct-details-title"></div> id="community-theme-details-panel"
<div style="margin-bottom: 1rem; font-size: 0.9rem; color: var(--muted-foreground);" id="ct-details-author"></div> style="
<button id="ct-unapply-btn" class="btn-secondary danger" style="width: 100%;">Unapply Theme</button> display: none;
padding: 1rem;
background: var(--secondary);
border-radius: var(--radius);
margin-top: 0.5rem;
border: 1px solid var(--border);
"
>
<div
style="margin-bottom: 0.5rem; font-weight: 600"
id="ct-details-title"
></div>
<div
style="
margin-bottom: 1rem;
font-size: 0.9rem;
color: var(--muted-foreground);
"
id="ct-details-author"
></div>
<button id="ct-unapply-btn" class="btn-secondary danger" style="width: 100%">
Unapply Theme
</button>
</div> </div>
</div> </div>
<div class="custom-theme-editor" id="custom-theme-editor"> <div class="custom-theme-editor" id="custom-theme-editor">
@ -3142,7 +3352,9 @@
<div class="setting-item"> <div class="setting-item">
<div class="info"> <div class="info">
<span class="label">Community Themes</span> <span class="label">Community Themes</span>
<span class="description">Browse and apply themes created by the community</span> <span class="description"
>Browse and apply themes created by the community</span
>
</div> </div>
<button id="open-theme-store-btn" class="btn-secondary">Open Theme Store</button> <button id="open-theme-store-btn" class="btn-secondary">Open Theme Store</button>
</div> </div>

View file

@ -711,7 +711,16 @@ export class LosslessAPI {
const links = []; const links = [];
if (detailsData.relations) { if (detailsData.relations) {
for (const rel of detailsData.relations) { for (const rel of detailsData.relations) {
if (['social network', 'streaming', 'official homepage', 'youtube', 'soundcloud', 'bandcamp'].includes(rel.type)) { if (
[
'social network',
'streaming',
'official homepage',
'youtube',
'soundcloud',
'bandcamp',
].includes(rel.type)
) {
links.push({ type: rel.type, url: rel.url.resource }); links.push({ type: rel.type, url: rel.url.resource });
} }
} }

View file

@ -723,10 +723,10 @@ export function initializeSettings(scrobbler, player, api, ui) {
const styleEl = document.getElementById('custom-theme-style'); const styleEl = document.getElementById('custom-theme-style');
if (styleEl) styleEl.remove(); if (styleEl) styleEl.remove();
themeManager.setTheme('system'); themeManager.setTheme('system');
const themePicker = document.getElementById('theme-picker'); const themePicker = document.getElementById('theme-picker');
if (themePicker) { if (themePicker) {
themePicker.querySelectorAll('.theme-option').forEach(opt => opt.classList.remove('active')); themePicker.querySelectorAll('.theme-option').forEach((opt) => opt.classList.remove('active'));
themePicker.querySelector('[data-theme="system"]')?.classList.add('active'); themePicker.querySelector('[data-theme="system"]')?.classList.add('active');
} }
document.getElementById('custom-theme-editor').classList.remove('show'); document.getElementById('custom-theme-editor').classList.remove('show');

View file

@ -25,12 +25,11 @@ export class ThemeStore {
this.modal.classList.remove('active'); this.modal.classList.remove('active');
}); });
const tabs = this.modal?.querySelectorAll('.search-tab'); const tabs = this.modal?.querySelectorAll('.search-tab');
tabs?.forEach(tab => { tabs?.forEach((tab) => {
tab.addEventListener('click', () => { tab.addEventListener('click', () => {
tabs.forEach(t => t.classList.remove('active')); tabs.forEach((t) => t.classList.remove('active'));
this.modal.querySelectorAll('.search-tab-content').forEach(c => c.classList.remove('active')); this.modal.querySelectorAll('.search-tab-content').forEach((c) => c.classList.remove('active'));
tab.classList.add('active'); tab.classList.add('active');
const contentId = tab.dataset.tab === 'browse' ? 'theme-store-browse' : 'theme-store-upload'; const contentId = tab.dataset.tab === 'browse' ? 'theme-store-browse' : 'theme-store-upload';
document.getElementById(contentId)?.classList.add('active'); document.getElementById(contentId)?.classList.add('active');
@ -46,7 +45,6 @@ export class ThemeStore {
debounceTimer = setTimeout(() => this.loadThemes(e.target.value), 300); debounceTimer = setTimeout(() => this.loadThemes(e.target.value), 300);
}); });
this.uploadForm?.addEventListener('submit', (e) => this.handleUpload(e)); this.uploadForm?.addEventListener('submit', (e) => this.handleUpload(e));
if (authManager) { if (authManager) {
@ -57,13 +55,11 @@ export class ThemeStore {
}); });
} }
document.getElementById('theme-store-login-btn')?.addEventListener('click', () => { document.getElementById('theme-store-login-btn')?.addEventListener('click', () => {
this.modal.classList.remove('active'); this.modal.classList.remove('active');
document.getElementById('email-auth-modal')?.classList.add('active'); document.getElementById('email-auth-modal')?.classList.add('active');
}); });
this.setupEditorTools(); this.setupEditorTools();
document.getElementById('theme-details-back-btn')?.addEventListener('click', () => { document.getElementById('theme-details-back-btn')?.addEventListener('click', () => {
@ -80,7 +76,11 @@ export class ThemeStore {
const metadataStr = localStorage.getItem('community-theme'); const metadataStr = localStorage.getItem('community-theme');
let metadata = null; let metadata = null;
if (metadataStr) { if (metadataStr) {
try { metadata = JSON.parse(metadataStr); } catch (e) { console.warn(e); } try {
metadata = JSON.parse(metadataStr);
} catch (e) {
console.warn(e);
}
} }
if (metadata) { if (metadata) {
@ -88,7 +88,7 @@ export class ThemeStore {
css: css, css: css,
id: metadata.id, id: metadata.id,
name: metadata.name, name: metadata.name,
authorName: metadata.author authorName: metadata.author,
}); });
} else { } else {
this.applyTheme(css); this.applyTheme(css);
@ -104,7 +104,6 @@ export class ThemeStore {
let currentUserId = null; let currentUserId = null;
if (authManager.user) { if (authManager.user) {
try { try {
const record = await syncManager._getUserRecord(authManager.user.uid); const record = await syncManager._getUserRecord(authManager.user.uid);
currentUserId = record?.id; currentUserId = record?.id;
} catch (e) { } catch (e) {
@ -116,14 +115,14 @@ export class ThemeStore {
const result = await this.pb.collection('themes').getList(1, 50, { const result = await this.pb.collection('themes').getList(1, 50, {
sort: '-created', sort: '-created',
filter: query ? `name ~ "${query}" || description ~ "${query}"` : '', filter: query ? `name ~ "${query}" || description ~ "${query}"` : '',
expand: 'author' expand: 'author',
}); });
this.loadingIndicator.style.display = 'none'; this.loadingIndicator.style.display = 'none';
if (result.items.length === 0) { if (result.items.length === 0) {
this.grid.innerHTML = '<div class="empty-state">No themes found.</div>'; this.grid.innerHTML = '<div class="empty-state">No themes found.</div>';
return; return;
} }
result.items.forEach(theme => { result.items.forEach((theme) => {
this.grid.appendChild(this.createThemeCard(theme, currentUserId)); this.grid.appendChild(this.createThemeCard(theme, currentUserId));
}); });
} catch (err) { } catch (err) {
@ -136,14 +135,13 @@ export class ThemeStore {
createThemeCard(theme, currentUserId) { createThemeCard(theme, currentUserId) {
const div = document.createElement('div'); const div = document.createElement('div');
div.className = 'card theme-card'; div.className = 'card theme-card';
const authorName = theme.expand?.author?.username const authorName =
|| theme.expand?.author?.display_name theme.expand?.author?.username || theme.expand?.author?.display_name || theme.authorName || 'Unknown';
|| theme.authorName
|| 'Unknown';
const shortDesc = theme.description ? const shortDesc = theme.description
(theme.description.length > 80 ? theme.description.substring(0, 80) + '...' : theme.description) ? theme.description.length > 80
? theme.description.substring(0, 80) + '...'
: theme.description
: ''; : '';
let authorHtml = this.escapeHtml(authorName); let authorHtml = this.escapeHtml(authorName);
@ -213,7 +211,7 @@ export class ThemeStore {
async deleteTheme(themeId) { async deleteTheme(themeId) {
if (!confirm('Are you sure you want to delete this theme?')) return; if (!confirm('Are you sure you want to delete this theme?')) return;
try { try {
const fbUser = authManager.user; const fbUser = authManager.user;
if (!fbUser) throw new Error('Not authenticated'); if (!fbUser) throw new Error('Not authenticated');
@ -232,12 +230,12 @@ export class ThemeStore {
const browseView = document.getElementById('theme-store-browse'); const browseView = document.getElementById('theme-store-browse');
const tabs = this.modal.querySelector('.search-tabs'); const tabs = this.modal.querySelector('.search-tabs');
document.getElementById('theme-details-name').textContent = theme.name; document.getElementById('theme-details-name').textContent = theme.name;
const authorName = theme.expand?.author?.username || theme.expand?.author?.display_name || theme.authorName || 'Unknown'; const authorName =
theme.expand?.author?.username || theme.expand?.author?.display_name || theme.authorName || 'Unknown';
const authorEl = document.getElementById('theme-details-author'); const authorEl = document.getElementById('theme-details-author');
if (theme.expand?.author?.username) { if (theme.expand?.author?.username) {
authorEl.innerHTML = `by <span style="cursor: pointer; text-decoration: underline; color: var(--primary);">${this.escapeHtml(authorName)}</span>`; authorEl.innerHTML = `by <span style="cursor: pointer; text-decoration: underline; color: var(--primary);">${this.escapeHtml(authorName)}</span>`;
authorEl.querySelector('span').onclick = () => { authorEl.querySelector('span').onclick = () => {
@ -247,13 +245,12 @@ export class ThemeStore {
} else { } else {
authorEl.textContent = `by ${authorName}`; authorEl.textContent = `by ${authorName}`;
} }
document.getElementById('theme-details-created').textContent = new Date(theme.created).toLocaleDateString(); document.getElementById('theme-details-created').textContent = new Date(theme.created).toLocaleDateString();
document.getElementById('theme-details-updated').textContent = new Date(theme.updated).toLocaleDateString(); document.getElementById('theme-details-updated').textContent = new Date(theme.updated).toLocaleDateString();
document.getElementById('theme-details-installs').textContent = theme.installs || 0; document.getElementById('theme-details-installs').textContent = theme.installs || 0;
document.getElementById('theme-details-desc').textContent = theme.description || 'No description provided.'; document.getElementById('theme-details-desc').textContent = theme.description || 'No description provided.';
const applyBtn = document.getElementById('theme-details-apply-btn'); const applyBtn = document.getElementById('theme-details-apply-btn');
applyBtn.onclick = async () => { applyBtn.onclick = async () => {
this.applyTheme(theme); this.applyTheme(theme);
@ -262,18 +259,17 @@ export class ThemeStore {
try { try {
const latest = await this.pb.collection('themes').getOne(theme.id); const latest = await this.pb.collection('themes').getOne(theme.id);
await this.pb.collection('themes').update(theme.id, { await this.pb.collection('themes').update(theme.id, {
installs: (latest.installs || 0) + 1 installs: (latest.installs || 0) + 1,
}); });
} catch (e) { } catch (e) {
console.warn('Failed to update theme installs:', e); console.warn('Failed to update theme installs:', e);
} }
}; };
const previewContainer = document.getElementById('theme-details-preview-container'); const previewContainer = document.getElementById('theme-details-preview-container');
previewContainer.innerHTML = ''; previewContainer.innerHTML = '';
this.detailsPreviewShadow = previewContainer.attachShadow({ mode: 'open' }); this.detailsPreviewShadow = previewContainer.attachShadow({ mode: 'open' });
const link = document.createElement('link'); const link = document.createElement('link');
link.rel = 'stylesheet'; link.rel = 'stylesheet';
link.href = '/styles.css'; link.href = '/styles.css';
@ -300,7 +296,6 @@ export class ThemeStore {
`; `;
this.detailsPreviewShadow.appendChild(wrapper); this.detailsPreviewShadow.appendChild(wrapper);
browseView.style.display = 'none'; browseView.style.display = 'none';
tabs.style.display = 'none'; tabs.style.display = 'none';
detailsView.style.display = 'flex'; detailsView.style.display = 'flex';
@ -314,7 +309,6 @@ export class ThemeStore {
detailsView.style.display = 'none'; detailsView.style.display = 'none';
browseView.style.display = 'block'; browseView.style.display = 'block';
tabs.style.display = 'flex'; tabs.style.display = 'flex';
document.getElementById('theme-details-preview-container').innerHTML = ''; document.getElementById('theme-details-preview-container').innerHTML = '';
} }
@ -322,7 +316,7 @@ export class ThemeStore {
extractPreviewStyles(css) { extractPreviewStyles(css) {
const vars = ['--background', '--foreground', '--primary', '--card', '--border', '--muted-foreground']; const vars = ['--background', '--foreground', '--primary', '--card', '--border', '--muted-foreground'];
let style = ''; let style = '';
vars.forEach(v => { vars.forEach((v) => {
const regex = new RegExp(`${v}\\s*:\\s*([^;]+)`); const regex = new RegExp(`${v}\\s*:\\s*([^;]+)`);
const match = css.match(regex); const match = css.match(regex);
if (match) { if (match) {
@ -341,11 +335,12 @@ export class ThemeStore {
localStorage.setItem('custom_theme_css', css); localStorage.setItem('custom_theme_css', css);
localStorage.setItem('monochrome-theme', 'custom'); localStorage.setItem('monochrome-theme', 'custom');
const metadata = { const metadata = {
id: theme.id, id: theme.id,
name: theme.name, name: theme.name,
author: theme.authorName || theme.expand?.author?.username || theme.expand?.author?.display_name || 'Unknown', author:
theme.authorName || theme.expand?.author?.username || theme.expand?.author?.display_name || 'Unknown',
}; };
localStorage.setItem('community-theme', JSON.stringify(metadata)); localStorage.setItem('community-theme', JSON.stringify(metadata));
@ -362,15 +357,34 @@ export class ThemeStore {
if (fontMatch && fontMatch[1]) { if (fontMatch && fontMatch[1]) {
const fontFamilyValue = fontMatch[1].trim(); const fontFamilyValue = fontMatch[1].trim();
const mainFont = fontFamilyValue.split(',')[0].trim().replace(/['"]/g, ''); const mainFont = fontFamilyValue.split(',')[0].trim().replace(/['"]/g, '');
const genericFamilies = [ const genericFamilies = [
'serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'serif',
'system-ui', 'inter', 'ibm plex mono', 'roboto', 'open sans', 'sans-serif',
'lato', 'montserrat', 'poppins', 'apple music', 'sf pro display', 'monospace',
'courier new', 'times new roman', 'arial', 'helvetica', 'verdana', 'cursive',
'tahoma', 'trebuchet ms', 'impact', 'gill sans' 'fantasy',
'system-ui',
'inter',
'ibm plex mono',
'roboto',
'open sans',
'lato',
'montserrat',
'poppins',
'apple music',
'sf pro display',
'courier new',
'times new roman',
'arial',
'helvetica',
'verdana',
'tahoma',
'trebuchet ms',
'impact',
'gill sans',
]; ];
const isPresetOrGeneric = genericFamilies.some(generic => mainFont.toLowerCase() === generic); const isPresetOrGeneric = genericFamilies.some((generic) => mainFont.toLowerCase() === generic);
if (!isPresetOrGeneric) { if (!isPresetOrGeneric) {
const FONT_LINK_ID = 'monochrome-dynamic-font'; const FONT_LINK_ID = 'monochrome-dynamic-font';
@ -418,14 +432,15 @@ export class ThemeStore {
styleEl.textContent = css; styleEl.textContent = css;
const root = document.documentElement; const root = document.documentElement;
['background', 'foreground', 'primary', 'secondary', 'muted', 'border', 'highlight', 'font-family'].forEach(key => { ['background', 'foreground', 'primary', 'secondary', 'muted', 'border', 'highlight', 'font-family'].forEach(
root.style.removeProperty(`--${key}`); (key) => {
}); root.style.removeProperty(`--${key}`);
}
);
root.setAttribute('data-theme', 'custom'); root.setAttribute('data-theme', 'custom');
document.querySelectorAll('.theme-option').forEach(el => el.classList.remove('active')); document.querySelectorAll('.theme-option').forEach((el) => el.classList.remove('active'));
document.querySelector('[data-theme="custom"]')?.classList.add('active'); document.querySelector('[data-theme="custom"]')?.classList.add('active');
document.documentElement.style.display = 'none'; document.documentElement.style.display = 'none';
@ -439,7 +454,6 @@ export class ThemeStore {
if (this._isCheckingAuth) return; if (this._isCheckingAuth) return;
this._isCheckingAuth = true; this._isCheckingAuth = true;
const isLoggedIn = !!authManager?.user; const isLoggedIn = !!authManager?.user;
const authMessage = document.getElementById('theme-upload-auth-message'); const authMessage = document.getElementById('theme-upload-auth-message');
@ -487,7 +501,6 @@ export class ThemeStore {
let userName = null; let userName = null;
try { try {
const dbUser = await syncManager._getUserRecord(fbUser.uid); const dbUser = await syncManager._getUserRecord(fbUser.uid);
if (!dbUser) { if (!dbUser) {
throw new Error('Could not find or create your user record. Please try again.'); throw new Error('Could not find or create your user record. Please try again.');
@ -499,7 +512,7 @@ export class ThemeStore {
if (userId.length !== 15) { if (userId.length !== 15) {
throw new Error( throw new Error(
`Your user ID is corrupted (${userId.length} chars, expected 15). ` + `Your user ID is corrupted (${userId.length} chars, expected 15). ` +
`Please go to Settings > System > Clear Cloud Data, then log out and back in.` `Please go to Settings > System > Clear Cloud Data, then log out and back in.`
); );
} }
@ -513,12 +526,10 @@ export class ThemeStore {
formData.append('authorName', userName); formData.append('authorName', userName);
if (website) formData.append('authorUrl', website); if (website) formData.append('authorUrl', website);
await this.pb.collection('themes').create(formData, { f_id: fbUser.uid }); await this.pb.collection('themes').create(formData, { f_id: fbUser.uid });
alert('Theme uploaded successfully!'); alert('Theme uploaded successfully!');
e.target.reset(); e.target.reset();
const previewWindow = document.getElementById('theme-preview-window'); const previewWindow = document.getElementById('theme-preview-window');
const togglePreviewBtn = document.getElementById('te-toggle-preview'); const togglePreviewBtn = document.getElementById('te-toggle-preview');
@ -530,7 +541,6 @@ export class ThemeStore {
this.modal.querySelector('[data-tab="browse"]').click(); this.modal.querySelector('[data-tab="browse"]').click();
this.loadThemes(); this.loadThemes();
} catch (err) { } catch (err) {
console.error('Upload failed:', err); console.error('Upload failed:', err);
console.error('Response data:', err.data); console.error('Response data:', err.data);
@ -562,7 +572,7 @@ export class ThemeStore {
const insertTemplateBtn = document.getElementById('te-insert-template'); const insertTemplateBtn = document.getElementById('te-insert-template');
const togglePreviewBtn = document.getElementById('te-toggle-preview'); const togglePreviewBtn = document.getElementById('te-toggle-preview');
const previewWindow = document.getElementById('theme-preview-window'); const previewWindow = document.getElementById('theme-preview-window');
const colorMap = { const colorMap = {
'te-bg-color': '--background', 'te-bg-color': '--background',
'te-fg-color': '--foreground', 'te-fg-color': '--foreground',
@ -571,7 +581,7 @@ export class ThemeStore {
'te-accent-color': '--highlight', 'te-accent-color': '--highlight',
'te-card-color': '--card', 'te-card-color': '--card',
'te-border-color': '--border', 'te-border-color': '--border',
'te-muted-color': '--muted-foreground' 'te-muted-color': '--muted-foreground',
}; };
Object.entries(colorMap).forEach(([id, variable]) => { Object.entries(colorMap).forEach(([id, variable]) => {
@ -583,7 +593,7 @@ export class ThemeStore {
const styleMap = { const styleMap = {
'te-font-family': '--font-family', 'te-font-family': '--font-family',
'te-radius': '--radius' 'te-radius': '--radius',
}; };
Object.entries(styleMap).forEach(([id, variable]) => { Object.entries(styleMap).forEach(([id, variable]) => {
@ -591,7 +601,7 @@ export class ThemeStore {
if (e.target.value) { if (e.target.value) {
this.updateCssVariable(cssInput, variable, e.target.value); this.updateCssVariable(cssInput, variable, e.target.value);
this.updatePreview(); this.updatePreview();
e.target.value = ""; e.target.value = '';
} }
}); });
}); });
@ -655,7 +665,7 @@ export class ThemeStore {
let css = textarea.value; let css = textarea.value;
const regex = new RegExp(`${variable}:\\s*[^;\\}]+(?:;|(?=\\}))`, 'g'); const regex = new RegExp(`${variable}:\\s*[^;\\}]+(?:;|(?=\\}))`, 'g');
const newLine = `${variable}: ${value};`; const newLine = `${variable}: ${value};`;
if (regex.test(css)) { if (regex.test(css)) {
css = css.replace(regex, newLine); css = css.replace(regex, newLine);
} else { } else {
@ -672,7 +682,7 @@ export class ThemeStore {
const container = document.getElementById('theme-preview-window'); const container = document.getElementById('theme-preview-window');
if (!this.previewShadow) { if (!this.previewShadow) {
this.previewShadow = container.attachShadow({ mode: 'open' }); this.previewShadow = container.attachShadow({ mode: 'open' });
const link = document.createElement('link'); const link = document.createElement('link');
link.rel = 'stylesheet'; link.rel = 'stylesheet';
link.href = '/styles.css'; link.href = '/styles.css';
@ -688,7 +698,7 @@ export class ThemeStore {
wrapper.style.background = 'var(--background)'; wrapper.style.background = 'var(--background)';
wrapper.style.color = 'var(--foreground)'; wrapper.style.color = 'var(--foreground)';
wrapper.style.overflow = 'auto'; wrapper.style.overflow = 'auto';
wrapper.innerHTML = ` wrapper.innerHTML = `
<h3 style="margin-top: 0;">Preview</h3> <h3 style="margin-top: 0;">Preview</h3>
<div class="card" style="margin-bottom: 1rem;"> <div class="card" style="margin-bottom: 1rem;">
@ -710,4 +720,4 @@ export class ThemeStore {
const scopedCss = css.replace(/:root/g, ':host'); const scopedCss = css.replace(/:root/g, ':host');
this.previewStyleTag.textContent = scopedCss; this.previewStyleTag.textContent = scopedCss;
} }
} }

View file

@ -52,14 +52,22 @@ import { trackSearch, trackChangeSort } from './analytics.js';
fontSettings.applyFont(); fontSettings.applyFont();
fontSettings.applyFontSize(); fontSettings.applyFontSize();
const SVG_GLOBE = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>'; const SVG_GLOBE =
const SVG_INSTAGRAM = '<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke=""><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M12 18C15.3137 18 18 15.3137 18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z" fill="#9E9E9E"></path> <path d="M18 5C17.4477 5 17 5.44772 17 6C17 6.55228 17.4477 7 18 7C18.5523 7 19 6.55228 19 6C19 5.44772 18.5523 5 18 5Z" fill="#9E9E9E"></path> <path fill-rule="evenodd" clip-rule="evenodd" d="M1.65396 4.27606C1 5.55953 1 7.23969 1 10.6V13.4C1 16.7603 1 18.4405 1.65396 19.7239C2.2292 20.8529 3.14708 21.7708 4.27606 22.346C5.55953 23 7.23969 23 10.6 23H13.4C16.7603 23 18.4405 23 19.7239 22.346C20.8529 21.7708 21.7708 20.8529 22.346 19.7239C23 18.4405 23 16.7603 23 13.4V10.6C23 7.23969 23 5.55953 22.346 4.27606C21.7708 3.14708 20.8529 2.2292 19.7239 1.65396C18.4405 1 16.7603 1 13.4 1H10.6C7.23969 1 5.55953 1 4.27606 1.65396C3.14708 2.2292 2.2292 3.14708 1.65396 4.27606ZM13.4 3H10.6C8.88684 3 7.72225 3.00156 6.82208 3.0751C5.94524 3.14674 5.49684 3.27659 5.18404 3.43597C4.43139 3.81947 3.81947 4.43139 3.43597 5.18404C3.27659 5.49684 3.14674 5.94524 3.0751 6.82208C3.00156 7.72225 3 8.88684 3 10.6V13.4C3 15.1132 3.00156 16.2777 3.0751 17.1779C3.14674 18.0548 3.27659 18.5032 3.43597 18.816C3.81947 19.5686 4.43139 20.1805 5.18404 20.564C5.49684 20.7234 5.94524 20.8533 6.82208 20.9249C7.72225 20.9984 8.88684 21 10.6 21H13.4C15.1132 21 16.2777 20.9984 17.1779 20.9249C18.0548 20.8533 18.5032 20.7234 18.816 20.564C19.5686 20.1805 20.1805 19.5686 20.564 18.816C20.7234 18.5032 20.8533 18.0548 20.9249 17.1779C20.9984 16.2777 21 15.1132 21 13.4V10.6C21 8.88684 20.9984 7.72225 20.9249 6.82208C20.8533 5.94524 20.7234 5.49684 20.564 5.18404C20.1805 4.43139 19.5686 3.81947 18.816 3.43597C18.5032 3.27659 18.0548 3.14674 17.1779 3.0751C16.2777 3.00156 15.1132 3 13.4 3Z" fill="#9E9E9E"></path> </g></svg>'; '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>';
const SVG_FACEBOOK = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg>'; const SVG_INSTAGRAM =
const SVG_YOUTUBE = '<svg viewBox="0 -3 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>youtube [#9E9E9E168]</title> <desc>Created with Sketch.</desc> <defs> </defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Dribbble-Light-Preview" transform="translate(-300.000000, -7442.000000)" fill="#9E9E9E"> <g id="icons" transform="translate(56.000000, 160.000000)"> <path d="M251.988432,7291.58588 L251.988432,7285.97425 C253.980638,7286.91168 255.523602,7287.8172 257.348463,7288.79353 C255.843351,7289.62824 253.980638,7290.56468 251.988432,7291.58588 M263.090998,7283.18289 C262.747343,7282.73013 262.161634,7282.37809 261.538073,7282.26141 C259.705243,7281.91336 248.270974,7281.91237 246.439141,7282.26141 C245.939097,7282.35515 245.493839,7282.58153 245.111335,7282.93357 C243.49964,7284.42947 244.004664,7292.45151 244.393145,7293.75096 C244.556505,7294.31342 244.767679,7294.71931 245.033639,7294.98558 C245.376298,7295.33761 245.845463,7295.57995 246.384355,7295.68865 C247.893451,7296.0008 255.668037,7296.17532 261.506198,7295.73552 C262.044094,7295.64178 262.520231,7295.39147 262.895762,7295.02447 C264.385932,7293.53455 264.28433,7285.06174 263.090998,7283.18289" id="youtube-[#9E9E9E168]"> </path> </g> </g> </g> </g></svg>'; '<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke=""><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M12 18C15.3137 18 18 15.3137 18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z" fill="#9E9E9E"></path> <path d="M18 5C17.4477 5 17 5.44772 17 6C17 6.55228 17.4477 7 18 7C18.5523 7 19 6.55228 19 6C19 5.44772 18.5523 5 18 5Z" fill="#9E9E9E"></path> <path fill-rule="evenodd" clip-rule="evenodd" d="M1.65396 4.27606C1 5.55953 1 7.23969 1 10.6V13.4C1 16.7603 1 18.4405 1.65396 19.7239C2.2292 20.8529 3.14708 21.7708 4.27606 22.346C5.55953 23 7.23969 23 10.6 23H13.4C16.7603 23 18.4405 23 19.7239 22.346C20.8529 21.7708 21.7708 20.8529 22.346 19.7239C23 18.4405 23 16.7603 23 13.4V10.6C23 7.23969 23 5.55953 22.346 4.27606C21.7708 3.14708 20.8529 2.2292 19.7239 1.65396C18.4405 1 16.7603 1 13.4 1H10.6C7.23969 1 5.55953 1 4.27606 1.65396C3.14708 2.2292 2.2292 3.14708 1.65396 4.27606ZM13.4 3H10.6C8.88684 3 7.72225 3.00156 6.82208 3.0751C5.94524 3.14674 5.49684 3.27659 5.18404 3.43597C4.43139 3.81947 3.81947 4.43139 3.43597 5.18404C3.27659 5.49684 3.14674 5.94524 3.0751 6.82208C3.00156 7.72225 3 8.88684 3 10.6V13.4C3 15.1132 3.00156 16.2777 3.0751 17.1779C3.14674 18.0548 3.27659 18.5032 3.43597 18.816C3.81947 19.5686 4.43139 20.1805 5.18404 20.564C5.49684 20.7234 5.94524 20.8533 6.82208 20.9249C7.72225 20.9984 8.88684 21 10.6 21H13.4C15.1132 21 16.2777 20.9984 17.1779 20.9249C18.0548 20.8533 18.5032 20.7234 18.816 20.564C19.5686 20.1805 20.1805 19.5686 20.564 18.816C20.7234 18.5032 20.8533 18.0548 20.9249 17.1779C20.9984 16.2777 21 15.1132 21 13.4V10.6C21 8.88684 20.9984 7.72225 20.9249 6.82208C20.8533 5.94524 20.7234 5.49684 20.564 5.18404C20.1805 4.43139 19.5686 3.81947 18.816 3.43597C18.5032 3.27659 18.0548 3.14674 17.1779 3.0751C16.2777 3.00156 15.1132 3 13.4 3Z" fill="#9E9E9E"></path> </g></svg>';
const SVG_TWITTER = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"/></svg>'; const SVG_FACEBOOK =
const SVG_LINK = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>'; '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"/></svg>';
const SVG_SOUNDCLOUD = '<svg fill="#9E9E9E" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve" stroke="#9E9E9E"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g id="5151e0c8492e5103c096af88a50061c5"> <path display="inline" d="M25.173,355.106c1.076,0,1.946-0.849,2.117-2.067l5.717-44.884l-5.717-45.889 c-0.171-1.22-1.041-2.061-2.117-2.061c-1.091,0-1.982,0.862-2.125,2.061c0,0.007-5.026,45.889-5.026,45.889l5.026,44.876 C23.191,354.229,24.083,355.106,25.173,355.106z M8.328,336.058c0,0,0,0,0,0.007l0,0V336.058z M6.274,338.047 c1.041,0,1.875-0.813,2.053-1.982l4.42-27.909l-4.42-28.395c-0.171-1.169-1.012-1.981-2.053-1.981 c-1.062,0-1.896,0.819-2.046,1.996L0.5,308.155l3.729,27.896C4.378,337.227,5.212,338.047,6.274,338.047z M47.808,253.712 c-0.157-1.454-1.233-2.51-2.56-2.51c-1.354,0-2.424,1.063-2.566,2.51l-4.762,54.45l4.762,52.455 c0.143,1.461,1.212,2.509,2.566,2.509c1.326,0,2.402-1.048,2.552-2.495l5.425-52.469L47.808,253.712z M65.487,365.236 c1.568,0,2.852-1.269,3.001-2.944l0,0l5.119-54.123l-5.119-55.947c-0.149-1.675-1.433-2.944-3.001-2.944 c-1.583,0-2.873,1.27-3.001,2.951l-4.513,55.94l4.513,54.123C62.614,363.968,63.904,365.236,65.487,365.236z M85.89,366.127 c1.825,0,3.301-1.461,3.436-3.386l-0.007,0.007l4.827-54.571l-4.827-51.913c-0.128-1.918-1.604-3.372-3.429-3.372 c-1.839,0-3.315,1.454-3.429,3.387l-4.256,51.898l4.256,54.564C82.575,364.666,84.051,366.127,85.89,366.127z M114.848,308.198 l-4.527-84.436c-0.114-2.152-1.811-3.828-3.864-3.828s-3.764,1.676-3.864,3.828l-4,84.436l4,54.564 c0.1,2.124,1.811,3.813,3.864,3.813s3.75-1.689,3.864-3.828v0.015L114.848,308.198z M127.195,366.677 c2.303,0,4.185-1.868,4.299-4.264v0.036l4.228-54.244l-4.228-103.74c-0.114-2.395-1.996-4.27-4.299-4.27 c-2.317,0-4.213,1.875-4.313,4.27c0,0.008-3.735,103.74-3.735,103.74l3.743,54.229 C122.982,364.809,124.878,366.677,127.195,366.677z M148.09,191.112c-2.574,0-4.655,2.067-4.748,4.705 c0,0.008-3.472,112.402-3.472,112.402l3.479,53.666c0.085,2.616,2.167,4.677,4.741,4.677c2.552,0,4.641-2.061,4.741-4.698v0.036 l3.928-53.681l-3.928-112.409C152.73,193.173,150.642,191.112,148.09,191.112z M169.156,366.669c2.809,0,5.083-2.26,5.175-5.14 v0.035l3.622-53.338l-3.622-116.188c-0.093-2.887-2.366-5.146-5.175-5.146c-2.823,0-5.097,2.26-5.183,5.146l-3.223,116.188 l3.223,53.331C164.059,364.409,166.333,366.669,169.156,366.669z M190.378,366.619c3.065,0,5.532-2.452,5.611-5.589v0.043 l3.336-52.84l-3.336-113.229c-0.079-3.129-2.546-5.582-5.611-5.582c-3.072,0-5.546,2.46-5.617,5.582l-2.958,113.229l2.965,52.825 C184.832,364.167,187.306,366.619,190.378,366.619z M220.848,308.248l-3.03-109.108c-0.071-3.372-2.73-6.017-6.045-6.017 c-3.329,0-5.988,2.645-6.053,6.024l-2.702,109.093l2.702,52.49c0.064,3.344,2.724,5.988,6.053,5.988 c3.314,0,5.974-2.645,6.045-6.023v0.043L220.848,308.248z M233.33,366.826c3.515,0,6.423-2.901,6.48-6.466v0.043l2.737-52.148 l-2.737-129.824c-0.058-3.558-2.966-6.459-6.48-6.459c-3.521,0-6.431,2.901-6.487,6.459l-2.445,129.781 c0,0.079,2.445,52.184,2.445,52.184C226.899,363.925,229.809,366.826,233.33,366.826z M254.788,159.767 c-3.771,0-6.872,3.108-6.93,6.908l-2.83,141.595l2.83,51.385c0.058,3.75,3.158,6.851,6.93,6.851c3.764,0,6.865-3.101,6.922-6.9 v0.057l3.08-51.392l-3.08-141.602C261.653,162.875,258.552,159.767,254.788,159.767z M274.428,366.861 c0.157,0.015,173.098,0.101,174.224,0.101c34.718,0,62.849-28.146,62.849-62.863s-28.131-62.849-62.849-62.849 c-8.618,0-16.824,1.74-24.31,4.877c-4.997-56.646-52.512-101.089-110.448-101.089c-14.179,0-28.002,2.795-40.207,7.521 c-4.74,1.832-6.01,3.729-6.052,7.386c0,0.007,0,199.488,0,199.488C267.685,363.283,270.671,366.491,274.428,366.861z"> </path> </g> </g></svg>'; const SVG_YOUTUBE =
const SVG_APPLE = '<svg viewBox="-1.5 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>apple [#9E9E9E173]</title> <desc>Created with Sketch.</desc> <defs> </defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Dribbble-Light-Preview" transform="translate(-102.000000, -7439.000000)" fill="#9E9E9E"> <g id="icons" transform="translate(56.000000, 160.000000)"> <path d="M57.5708873,7282.19296 C58.2999598,7281.34797 58.7914012,7280.17098 58.6569121,7279 C57.6062792,7279.04 56.3352055,7279.67099 55.5818643,7280.51498 C54.905374,7281.26397 54.3148354,7282.46095 54.4735932,7283.60894 C55.6455696,7283.69593 56.8418148,7283.03894 57.5708873,7282.19296 M60.1989864,7289.62485 C60.2283111,7292.65181 62.9696641,7293.65879 63,7293.67179 C62.9777537,7293.74279 62.562152,7295.10677 61.5560117,7296.51675 C60.6853718,7297.73474 59.7823735,7298.94772 58.3596204,7298.97372 C56.9621472,7298.99872 56.5121648,7298.17973 54.9134635,7298.17973 C53.3157735,7298.17973 52.8162425,7298.94772 51.4935978,7298.99872 C50.1203933,7299.04772 49.0738052,7297.68074 48.197098,7296.46676 C46.4032359,7293.98379 45.0330649,7289.44985 46.8734421,7286.3899 C47.7875635,7284.87092 49.4206455,7283.90793 51.1942837,7283.88393 C52.5422083,7283.85893 53.8153044,7284.75292 54.6394294,7284.75292 C55.4635543,7284.75292 57.0106846,7283.67793 58.6366882,7283.83593 C59.3172232,7283.86293 61.2283842,7284.09893 62.4549652,7285.8199 C62.355868,7285.8789 60.1747177,7287.09489 60.1989864,7289.62485" id="apple-[#9E9E9E173]"> </path> </g> </g> </g> </g></svg>'; '<svg viewBox="0 -3 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>youtube [#9E9E9E168]</title> <desc>Created with Sketch.</desc> <defs> </defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Dribbble-Light-Preview" transform="translate(-300.000000, -7442.000000)" fill="#9E9E9E"> <g id="icons" transform="translate(56.000000, 160.000000)"> <path d="M251.988432,7291.58588 L251.988432,7285.97425 C253.980638,7286.91168 255.523602,7287.8172 257.348463,7288.79353 C255.843351,7289.62824 253.980638,7290.56468 251.988432,7291.58588 M263.090998,7283.18289 C262.747343,7282.73013 262.161634,7282.37809 261.538073,7282.26141 C259.705243,7281.91336 248.270974,7281.91237 246.439141,7282.26141 C245.939097,7282.35515 245.493839,7282.58153 245.111335,7282.93357 C243.49964,7284.42947 244.004664,7292.45151 244.393145,7293.75096 C244.556505,7294.31342 244.767679,7294.71931 245.033639,7294.98558 C245.376298,7295.33761 245.845463,7295.57995 246.384355,7295.68865 C247.893451,7296.0008 255.668037,7296.17532 261.506198,7295.73552 C262.044094,7295.64178 262.520231,7295.39147 262.895762,7295.02447 C264.385932,7293.53455 264.28433,7285.06174 263.090998,7283.18289" id="youtube-[#9E9E9E168]"> </path> </g> </g> </g> </g></svg>';
const SVG_TWITTER =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"/></svg>';
const SVG_LINK =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>';
const SVG_SOUNDCLOUD =
'<svg fill="#9E9E9E" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve" stroke="#9E9E9E"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g id="5151e0c8492e5103c096af88a50061c5"> <path display="inline" d="M25.173,355.106c1.076,0,1.946-0.849,2.117-2.067l5.717-44.884l-5.717-45.889 c-0.171-1.22-1.041-2.061-2.117-2.061c-1.091,0-1.982,0.862-2.125,2.061c0,0.007-5.026,45.889-5.026,45.889l5.026,44.876 C23.191,354.229,24.083,355.106,25.173,355.106z M8.328,336.058c0,0,0,0,0,0.007l0,0V336.058z M6.274,338.047 c1.041,0,1.875-0.813,2.053-1.982l4.42-27.909l-4.42-28.395c-0.171-1.169-1.012-1.981-2.053-1.981 c-1.062,0-1.896,0.819-2.046,1.996L0.5,308.155l3.729,27.896C4.378,337.227,5.212,338.047,6.274,338.047z M47.808,253.712 c-0.157-1.454-1.233-2.51-2.56-2.51c-1.354,0-2.424,1.063-2.566,2.51l-4.762,54.45l4.762,52.455 c0.143,1.461,1.212,2.509,2.566,2.509c1.326,0,2.402-1.048,2.552-2.495l5.425-52.469L47.808,253.712z M65.487,365.236 c1.568,0,2.852-1.269,3.001-2.944l0,0l5.119-54.123l-5.119-55.947c-0.149-1.675-1.433-2.944-3.001-2.944 c-1.583,0-2.873,1.27-3.001,2.951l-4.513,55.94l4.513,54.123C62.614,363.968,63.904,365.236,65.487,365.236z M85.89,366.127 c1.825,0,3.301-1.461,3.436-3.386l-0.007,0.007l4.827-54.571l-4.827-51.913c-0.128-1.918-1.604-3.372-3.429-3.372 c-1.839,0-3.315,1.454-3.429,3.387l-4.256,51.898l4.256,54.564C82.575,364.666,84.051,366.127,85.89,366.127z M114.848,308.198 l-4.527-84.436c-0.114-2.152-1.811-3.828-3.864-3.828s-3.764,1.676-3.864,3.828l-4,84.436l4,54.564 c0.1,2.124,1.811,3.813,3.864,3.813s3.75-1.689,3.864-3.828v0.015L114.848,308.198z M127.195,366.677 c2.303,0,4.185-1.868,4.299-4.264v0.036l4.228-54.244l-4.228-103.74c-0.114-2.395-1.996-4.27-4.299-4.27 c-2.317,0-4.213,1.875-4.313,4.27c0,0.008-3.735,103.74-3.735,103.74l3.743,54.229 C122.982,364.809,124.878,366.677,127.195,366.677z M148.09,191.112c-2.574,0-4.655,2.067-4.748,4.705 c0,0.008-3.472,112.402-3.472,112.402l3.479,53.666c0.085,2.616,2.167,4.677,4.741,4.677c2.552,0,4.641-2.061,4.741-4.698v0.036 l3.928-53.681l-3.928-112.409C152.73,193.173,150.642,191.112,148.09,191.112z M169.156,366.669c2.809,0,5.083-2.26,5.175-5.14 v0.035l3.622-53.338l-3.622-116.188c-0.093-2.887-2.366-5.146-5.175-5.146c-2.823,0-5.097,2.26-5.183,5.146l-3.223,116.188 l3.223,53.331C164.059,364.409,166.333,366.669,169.156,366.669z M190.378,366.619c3.065,0,5.532-2.452,5.611-5.589v0.043 l3.336-52.84l-3.336-113.229c-0.079-3.129-2.546-5.582-5.611-5.582c-3.072,0-5.546,2.46-5.617,5.582l-2.958,113.229l2.965,52.825 C184.832,364.167,187.306,366.619,190.378,366.619z M220.848,308.248l-3.03-109.108c-0.071-3.372-2.73-6.017-6.045-6.017 c-3.329,0-5.988,2.645-6.053,6.024l-2.702,109.093l2.702,52.49c0.064,3.344,2.724,5.988,6.053,5.988 c3.314,0,5.974-2.645,6.045-6.023v0.043L220.848,308.248z M233.33,366.826c3.515,0,6.423-2.901,6.48-6.466v0.043l2.737-52.148 l-2.737-129.824c-0.058-3.558-2.966-6.459-6.48-6.459c-3.521,0-6.431,2.901-6.487,6.459l-2.445,129.781 c0,0.079,2.445,52.184,2.445,52.184C226.899,363.925,229.809,366.826,233.33,366.826z M254.788,159.767 c-3.771,0-6.872,3.108-6.93,6.908l-2.83,141.595l2.83,51.385c0.058,3.75,3.158,6.851,6.93,6.851c3.764,0,6.865-3.101,6.922-6.9 v0.057l3.08-51.392l-3.08-141.602C261.653,162.875,258.552,159.767,254.788,159.767z M274.428,366.861 c0.157,0.015,173.098,0.101,174.224,0.101c34.718,0,62.849-28.146,62.849-62.863s-28.131-62.849-62.849-62.849 c-8.618,0-16.824,1.74-24.31,4.877c-4.997-56.646-52.512-101.089-110.448-101.089c-14.179,0-28.002,2.795-40.207,7.521 c-4.74,1.832-6.01,3.729-6.052,7.386c0,0.007,0,199.488,0,199.488C267.685,363.283,270.671,366.491,274.428,366.861z"> </path> </g> </g></svg>';
const SVG_APPLE =
'<svg viewBox="-1.5 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>apple [#9E9E9E173]</title> <desc>Created with Sketch.</desc> <defs> </defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Dribbble-Light-Preview" transform="translate(-102.000000, -7439.000000)" fill="#9E9E9E"> <g id="icons" transform="translate(56.000000, 160.000000)"> <path d="M57.5708873,7282.19296 C58.2999598,7281.34797 58.7914012,7280.17098 58.6569121,7279 C57.6062792,7279.04 56.3352055,7279.67099 55.5818643,7280.51498 C54.905374,7281.26397 54.3148354,7282.46095 54.4735932,7283.60894 C55.6455696,7283.69593 56.8418148,7283.03894 57.5708873,7282.19296 M60.1989864,7289.62485 C60.2283111,7292.65181 62.9696641,7293.65879 63,7293.67179 C62.9777537,7293.74279 62.562152,7295.10677 61.5560117,7296.51675 C60.6853718,7297.73474 59.7823735,7298.94772 58.3596204,7298.97372 C56.9621472,7298.99872 56.5121648,7298.17973 54.9134635,7298.17973 C53.3157735,7298.17973 52.8162425,7298.94772 51.4935978,7298.99872 C50.1203933,7299.04772 49.0738052,7297.68074 48.197098,7296.46676 C46.4032359,7293.98379 45.0330649,7289.44985 46.8734421,7286.3899 C47.7875635,7284.87092 49.4206455,7283.90793 51.1942837,7283.88393 C52.5422083,7283.85893 53.8153044,7284.75292 54.6394294,7284.75292 C55.4635543,7284.75292 57.0106846,7283.67793 58.6366882,7283.83593 C59.3172232,7283.86293 61.2283842,7284.09893 62.4549652,7285.8199 C62.355868,7285.8789 60.1747177,7287.09489 60.1989864,7289.62485" id="apple-[#9E9E9E173]"> </path> </g> </g> </g> </g></svg>';
function sortTracks(tracks, sortType) { function sortTracks(tracks, sortType) {
if (sortType === 'custom') return [...tracks]; if (sortType === 'custom') return [...tracks];

View file

@ -7641,7 +7641,7 @@ textarea:focus {
cursor: pointer; cursor: pointer;
} }
.theme-editor-toolbar input[type="color"] { .theme-editor-toolbar input[type='color'] {
width: 24px; width: 24px;
height: 24px; height: 24px;
padding: 0; padding: 0;
@ -7663,7 +7663,7 @@ textarea:focus {
right: 20px; right: 20px;
width: 300px; width: 300px;
height: 400px; height: 400px;
background: var(--background); background: var(--background);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius); border-radius: var(--radius);
box-shadow: var(--shadow-xl); box-shadow: var(--shadow-xl);