ywana-core8 0.2.8 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +292 -56
- package/dist/index.js +215 -114
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +215 -114
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +215 -114
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/desktop/AppManager.js +179 -115
- package/src/desktop/ApplicationMenu.css +292 -53
- package/src/desktop/ApplicationMenu.js +55 -15
- package/src/desktop/Desktop.stories.jsx +148 -584
- package/src/desktop/desktop-windows.css +0 -3
- package/src/desktop/desktop.js +43 -23
- package/src/desktop.backup/desktop.css +0 -6
- package/src/desktop.backup/desktop.js +0 -13
- package/src/desktop.backup/window.css +0 -58
- package/src/desktop.backup/window.js +0 -27
package/dist/index.modern.js
CHANGED
@@ -32444,6 +32444,8 @@ const ApplicationMenu = ({ isOpen, onClose }) => {
|
|
32444
32444
|
const [selectedCategory, setSelectedCategory] = useState("all");
|
32445
32445
|
const [apps, setApps] = useState([]);
|
32446
32446
|
const [categories, setCategories] = useState([]);
|
32447
|
+
const [viewMode, setViewMode] = useState("list");
|
32448
|
+
const [isCondensed, setIsCondensed] = useState(true);
|
32447
32449
|
const searchInputRef = useRef(null);
|
32448
32450
|
const { createWindow } = useWindows();
|
32449
32451
|
useEffect(() => {
|
@@ -32505,7 +32507,31 @@ const ApplicationMenu = ({ isOpen, onClose }) => {
|
|
32505
32507
|
setSearchTerm("");
|
32506
32508
|
};
|
32507
32509
|
if (!isOpen) return null;
|
32508
|
-
return /* @__PURE__ */ React.createElement("div", { className: "application-menu-overlay", onClick: onClose }, /* @__PURE__ */ React.createElement("div", { className: "application-menu"
|
32510
|
+
return /* @__PURE__ */ React.createElement("div", { className: "application-menu-overlay", onClick: onClose }, /* @__PURE__ */ React.createElement("div", { className: `application-menu ${isCondensed ? "application-menu--condensed" : ""}`, onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React.createElement("div", { className: "application-menu__header" }, /* @__PURE__ */ React.createElement("div", { className: "application-menu__header-controls" }, /* @__PURE__ */ React.createElement(
|
32511
|
+
"button",
|
32512
|
+
{
|
32513
|
+
className: `application-menu__view-toggle ${isCondensed ? "active" : ""}`,
|
32514
|
+
onClick: () => setIsCondensed(!isCondensed),
|
32515
|
+
title: isCondensed ? "Normal view" : "Condensed view"
|
32516
|
+
},
|
32517
|
+
"⚏"
|
32518
|
+
), /* @__PURE__ */ React.createElement(
|
32519
|
+
"button",
|
32520
|
+
{
|
32521
|
+
className: `application-menu__view-toggle ${viewMode === "grid" ? "active" : ""}`,
|
32522
|
+
onClick: () => setViewMode("grid"),
|
32523
|
+
title: "Grid view"
|
32524
|
+
},
|
32525
|
+
"⊞"
|
32526
|
+
), /* @__PURE__ */ React.createElement(
|
32527
|
+
"button",
|
32528
|
+
{
|
32529
|
+
className: `application-menu__view-toggle ${viewMode === "list" ? "active" : ""}`,
|
32530
|
+
onClick: () => setViewMode("list"),
|
32531
|
+
title: "List view"
|
32532
|
+
},
|
32533
|
+
"☰"
|
32534
|
+
), /* @__PURE__ */ React.createElement(
|
32509
32535
|
"button",
|
32510
32536
|
{
|
32511
32537
|
className: "application-menu__close",
|
@@ -32513,7 +32539,7 @@ const ApplicationMenu = ({ isOpen, onClose }) => {
|
|
32513
32539
|
title: "Close menu"
|
32514
32540
|
},
|
32515
32541
|
"×"
|
32516
|
-
)), /* @__PURE__ */ React.createElement("div", { className: "application-menu__search" }, /* @__PURE__ */ React.createElement(
|
32542
|
+
))), /* @__PURE__ */ React.createElement("div", { className: "application-menu__search" }, /* @__PURE__ */ React.createElement(
|
32517
32543
|
"input",
|
32518
32544
|
{
|
32519
32545
|
ref: searchInputRef,
|
@@ -32527,7 +32553,8 @@ const ApplicationMenu = ({ isOpen, onClose }) => {
|
|
32527
32553
|
"button",
|
32528
32554
|
{
|
32529
32555
|
className: `application-menu__category ${selectedCategory === "all" ? "active" : ""}`,
|
32530
|
-
onClick: () => handleCategorySelect("all")
|
32556
|
+
onClick: () => handleCategorySelect("all"),
|
32557
|
+
title: "All Apps"
|
32531
32558
|
},
|
32532
32559
|
/* @__PURE__ */ React.createElement("span", { className: "category-icon" }, "📱"),
|
32533
32560
|
/* @__PURE__ */ React.createElement("span", { className: "category-name" }, "All Apps")
|
@@ -32536,30 +32563,31 @@ const ApplicationMenu = ({ isOpen, onClose }) => {
|
|
32536
32563
|
{
|
32537
32564
|
key: category.id,
|
32538
32565
|
className: `application-menu__category ${selectedCategory === category.id ? "active" : ""}`,
|
32539
|
-
onClick: () => handleCategorySelect(category.id)
|
32566
|
+
onClick: () => handleCategorySelect(category.id),
|
32567
|
+
title: category.name
|
32540
32568
|
},
|
32541
32569
|
/* @__PURE__ */ React.createElement("span", { className: "category-icon" }, category.icon),
|
32542
32570
|
/* @__PURE__ */ React.createElement("span", { className: "category-name" }, category.name)
|
32543
|
-
)))), /* @__PURE__ */ React.createElement("div", { className: "application-menu__content" }, searchTerm && /* @__PURE__ */ React.createElement("div", { className: "application-menu__search-results" }, /* @__PURE__ */ React.createElement("h3", null, "Search Results (", filteredApps.length, ")"), /* @__PURE__ */ React.createElement("div", { className:
|
32571
|
+
)))), /* @__PURE__ */ React.createElement("div", { className: "application-menu__content" }, searchTerm && /* @__PURE__ */ React.createElement("div", { className: "application-menu__search-results" }, /* @__PURE__ */ React.createElement("h3", null, "Search Results (", filteredApps.length, ")"), /* @__PURE__ */ React.createElement("div", { className: `application-menu__apps-${viewMode}` }, filteredApps.map((app) => /* @__PURE__ */ React.createElement(
|
32544
32572
|
"div",
|
32545
32573
|
{
|
32546
32574
|
key: app.id,
|
32547
|
-
className:
|
32575
|
+
className: `application-menu__app--${viewMode}`,
|
32548
32576
|
onClick: () => handleLaunchApp(app),
|
32549
32577
|
title: app.description
|
32550
32578
|
},
|
32551
32579
|
/* @__PURE__ */ React.createElement("div", { className: "app-icon" }, app.icon),
|
32552
|
-
/* @__PURE__ */ React.createElement("div", { className: "app-name" }, app.name)
|
32553
|
-
)))), !searchTerm && /* @__PURE__ */ React.createElement("div", { className: "application-menu__categories-content" }, Object.entries(groupedApps).map(([categoryName, categoryApps]) => /* @__PURE__ */ React.createElement("div", { key: categoryName, className: "application-menu__category-section" }, /* @__PURE__ */ React.createElement("h3", { className: "category-title" }, categoryName), /* @__PURE__ */ React.createElement("div", { className:
|
32580
|
+
viewMode === "list" ? /* @__PURE__ */ React.createElement("div", { className: "app-info" }, /* @__PURE__ */ React.createElement("div", { className: "app-name" }, app.name), /* @__PURE__ */ React.createElement("div", { className: "app-description" }, app.description)) : /* @__PURE__ */ React.createElement("div", { className: "app-name" }, app.name)
|
32581
|
+
)))), !searchTerm && /* @__PURE__ */ React.createElement("div", { className: "application-menu__categories-content" }, Object.entries(groupedApps).map(([categoryName, categoryApps]) => /* @__PURE__ */ React.createElement("div", { key: categoryName, className: "application-menu__category-section" }, /* @__PURE__ */ React.createElement("h3", { className: "category-title" }, categoryName), /* @__PURE__ */ React.createElement("div", { className: `application-menu__apps-${viewMode}` }, categoryApps.map((app) => /* @__PURE__ */ React.createElement(
|
32554
32582
|
"div",
|
32555
32583
|
{
|
32556
32584
|
key: app.id,
|
32557
|
-
className:
|
32585
|
+
className: `application-menu__app--${viewMode}`,
|
32558
32586
|
onClick: () => handleLaunchApp(app),
|
32559
32587
|
title: app.description
|
32560
32588
|
},
|
32561
32589
|
/* @__PURE__ */ React.createElement("div", { className: "app-icon" }, app.icon),
|
32562
|
-
/* @__PURE__ */ React.createElement("div", { className: "app-name" }, app.name)
|
32590
|
+
viewMode === "list" ? /* @__PURE__ */ React.createElement("div", { className: "app-info" }, /* @__PURE__ */ React.createElement("div", { className: "app-name" }, app.name), /* @__PURE__ */ React.createElement("div", { className: "app-description" }, app.description)) : /* @__PURE__ */ React.createElement("div", { className: "app-name" }, app.name)
|
32563
32591
|
)))))), filteredApps.length === 0 && /* @__PURE__ */ React.createElement("div", { className: "application-menu__no-results" }, /* @__PURE__ */ React.createElement("div", { style: { fontSize: "48px", marginBottom: "16px" } }, "🔍"), /* @__PURE__ */ React.createElement("h3", null, "No applications found"), /* @__PURE__ */ React.createElement("p", null, "Try adjusting your search or category filter."))))));
|
32564
32592
|
};
|
32565
32593
|
class AppManager {
|
@@ -32567,107 +32595,6 @@ class AppManager {
|
|
32567
32595
|
this.applications = /* @__PURE__ */ new Map();
|
32568
32596
|
this.categories = /* @__PURE__ */ new Map();
|
32569
32597
|
this.listeners = /* @__PURE__ */ new Set();
|
32570
|
-
this.initializeDefaultApps();
|
32571
|
-
}
|
32572
|
-
/**
|
32573
|
-
* Initialize default applications
|
32574
|
-
*/
|
32575
|
-
initializeDefaultApps() {
|
32576
|
-
this.registerApp({
|
32577
|
-
id: "file-explorer",
|
32578
|
-
name: "File Explorer",
|
32579
|
-
description: "Browse and manage files",
|
32580
|
-
icon: "📁",
|
32581
|
-
category: "System",
|
32582
|
-
component: null,
|
32583
|
-
// Will be set when registering actual components
|
32584
|
-
size: { width: 600, height: 400 },
|
32585
|
-
toolbar: null,
|
32586
|
-
statusBar: null
|
32587
|
-
});
|
32588
|
-
this.registerApp({
|
32589
|
-
id: "text-editor",
|
32590
|
-
name: "Text Editor",
|
32591
|
-
description: "Edit text files",
|
32592
|
-
icon: "📝",
|
32593
|
-
category: "Productivity",
|
32594
|
-
component: null,
|
32595
|
-
size: { width: 500, height: 350 },
|
32596
|
-
toolbar: null,
|
32597
|
-
statusBar: null
|
32598
|
-
});
|
32599
|
-
this.registerApp({
|
32600
|
-
id: "calculator",
|
32601
|
-
name: "Calculator",
|
32602
|
-
description: "Perform calculations",
|
32603
|
-
icon: "🧮",
|
32604
|
-
category: "Utilities",
|
32605
|
-
component: null,
|
32606
|
-
size: { width: 300, height: 400 }
|
32607
|
-
});
|
32608
|
-
this.registerApp({
|
32609
|
-
id: "settings",
|
32610
|
-
name: "Settings",
|
32611
|
-
description: "System configuration",
|
32612
|
-
icon: "⚙️",
|
32613
|
-
category: "System",
|
32614
|
-
component: null,
|
32615
|
-
size: { width: 450, height: 300 }
|
32616
|
-
});
|
32617
|
-
this.registerApp({
|
32618
|
-
id: "browser",
|
32619
|
-
name: "Web Browser",
|
32620
|
-
description: "Browse the internet",
|
32621
|
-
icon: "🌐",
|
32622
|
-
category: "Internet",
|
32623
|
-
component: null,
|
32624
|
-
size: { width: 800, height: 500 }
|
32625
|
-
});
|
32626
|
-
this.registerApp({
|
32627
|
-
id: "terminal",
|
32628
|
-
name: "Terminal",
|
32629
|
-
description: "Command line interface",
|
32630
|
-
icon: "💻",
|
32631
|
-
category: "Development",
|
32632
|
-
component: null,
|
32633
|
-
size: { width: 700, height: 400 }
|
32634
|
-
});
|
32635
|
-
this.registerApp({
|
32636
|
-
id: "image-viewer",
|
32637
|
-
name: "Image Viewer",
|
32638
|
-
description: "View and edit images",
|
32639
|
-
icon: "🖼️",
|
32640
|
-
category: "Media",
|
32641
|
-
component: null,
|
32642
|
-
size: { width: 600, height: 500 }
|
32643
|
-
});
|
32644
|
-
this.registerApp({
|
32645
|
-
id: "music-player",
|
32646
|
-
name: "Music Player",
|
32647
|
-
description: "Play audio files",
|
32648
|
-
icon: "🎵",
|
32649
|
-
category: "Media",
|
32650
|
-
component: null,
|
32651
|
-
size: { width: 400, height: 300 }
|
32652
|
-
});
|
32653
|
-
this.initializeCategories();
|
32654
|
-
}
|
32655
|
-
/**
|
32656
|
-
* Initialize application categories
|
32657
|
-
*/
|
32658
|
-
initializeCategories() {
|
32659
|
-
const categoryData = [
|
32660
|
-
{ id: "system", name: "System", icon: "⚙️", color: "#607d8b" },
|
32661
|
-
{ id: "productivity", name: "Productivity", icon: "📊", color: "#2196f3" },
|
32662
|
-
{ id: "utilities", name: "Utilities", icon: "🔧", color: "#ff9800" },
|
32663
|
-
{ id: "internet", name: "Internet", icon: "🌐", color: "#4caf50" },
|
32664
|
-
{ id: "development", name: "Development", icon: "💻", color: "#9c27b0" },
|
32665
|
-
{ id: "media", name: "Media", icon: "🎬", color: "#e91e63" },
|
32666
|
-
{ id: "games", name: "Games", icon: "🎮", color: "#f44336" }
|
32667
|
-
];
|
32668
|
-
categoryData.forEach((category) => {
|
32669
|
-
this.categories.set(category.id, category);
|
32670
|
-
});
|
32671
32598
|
}
|
32672
32599
|
/**
|
32673
32600
|
* Register a new application
|
@@ -32787,6 +32714,160 @@ class AppManager {
|
|
32787
32714
|
return grouped;
|
32788
32715
|
}
|
32789
32716
|
}
|
32717
|
+
class AppLoader {
|
32718
|
+
/**
|
32719
|
+
* Load configuration into AppManager
|
32720
|
+
* @param {AppManager} appManager - The AppManager instance
|
32721
|
+
* @param {Object} config - JSON configuration object
|
32722
|
+
* @param {Array} config.categories - Array of category definitions
|
32723
|
+
* @param {Array} config.applications - Array of application definitions
|
32724
|
+
*/
|
32725
|
+
static load(appManager, config) {
|
32726
|
+
if (!config) {
|
32727
|
+
console.warn("AppLoader: No configuration provided");
|
32728
|
+
return;
|
32729
|
+
}
|
32730
|
+
if (config.categories && Array.isArray(config.categories)) {
|
32731
|
+
this.loadCategories(appManager, config.categories);
|
32732
|
+
}
|
32733
|
+
if (config.applications && Array.isArray(config.applications)) {
|
32734
|
+
this.loadApplications(appManager, config.applications);
|
32735
|
+
}
|
32736
|
+
}
|
32737
|
+
/**
|
32738
|
+
* Load categories from configuration
|
32739
|
+
* @param {AppManager} appManager - The AppManager instance
|
32740
|
+
* @param {Array} categories - Array of category definitions
|
32741
|
+
*/
|
32742
|
+
static loadCategories(appManager, categories) {
|
32743
|
+
categories.forEach((category) => {
|
32744
|
+
if (this.validateCategory(category)) {
|
32745
|
+
appManager.categories.set(category.id, category);
|
32746
|
+
} else {
|
32747
|
+
console.warn("AppLoader: Invalid category configuration:", category);
|
32748
|
+
}
|
32749
|
+
});
|
32750
|
+
}
|
32751
|
+
/**
|
32752
|
+
* Load applications from configuration
|
32753
|
+
* @param {AppManager} appManager - The AppManager instance
|
32754
|
+
* @param {Array} applications - Array of application definitions
|
32755
|
+
*/
|
32756
|
+
static loadApplications(appManager, applications) {
|
32757
|
+
applications.forEach((app) => {
|
32758
|
+
if (this.validateApplication(app)) {
|
32759
|
+
appManager.registerApp(app);
|
32760
|
+
} else {
|
32761
|
+
console.warn("AppLoader: Invalid application configuration:", app);
|
32762
|
+
}
|
32763
|
+
});
|
32764
|
+
}
|
32765
|
+
/**
|
32766
|
+
* Validate category configuration
|
32767
|
+
* @param {Object} category - Category definition
|
32768
|
+
* @returns {boolean} - True if valid
|
32769
|
+
*/
|
32770
|
+
static validateCategory(category) {
|
32771
|
+
return category && typeof category.id === "string" && typeof category.name === "string" && category.id.length > 0 && category.name.length > 0;
|
32772
|
+
}
|
32773
|
+
/**
|
32774
|
+
* Validate application configuration
|
32775
|
+
* @param {Object} app - Application definition
|
32776
|
+
* @returns {boolean} - True if valid
|
32777
|
+
*/
|
32778
|
+
static validateApplication(app) {
|
32779
|
+
return app && typeof app.id === "string" && typeof app.name === "string" && app.id.length > 0 && app.name.length > 0;
|
32780
|
+
}
|
32781
|
+
}
|
32782
|
+
const defaultDesktopConfig = {
|
32783
|
+
categories: [
|
32784
|
+
{ id: "system", name: "System", icon: "⚙️", color: "#607d8b" },
|
32785
|
+
{ id: "productivity", name: "Productivity", icon: "📊", color: "#2196f3" },
|
32786
|
+
{ id: "utilities", name: "Utilities", icon: "🔧", color: "#ff9800" },
|
32787
|
+
{ id: "internet", name: "Internet", icon: "🌐", color: "#4caf50" },
|
32788
|
+
{ id: "development", name: "Development", icon: "💻", color: "#9c27b0" },
|
32789
|
+
{ id: "media", name: "Media", icon: "🎬", color: "#e91e63" },
|
32790
|
+
{ id: "games", name: "Games", icon: "🎮", color: "#f44336" }
|
32791
|
+
],
|
32792
|
+
applications: [
|
32793
|
+
{
|
32794
|
+
id: "file-explorer",
|
32795
|
+
name: "File Explorer",
|
32796
|
+
description: "Browse and manage files",
|
32797
|
+
icon: "📁",
|
32798
|
+
category: "System",
|
32799
|
+
component: null,
|
32800
|
+
size: { width: 600, height: 400 },
|
32801
|
+
toolbar: null,
|
32802
|
+
statusBar: null
|
32803
|
+
},
|
32804
|
+
{
|
32805
|
+
id: "text-editor",
|
32806
|
+
name: "Text Editor",
|
32807
|
+
description: "Edit text files",
|
32808
|
+
icon: "📝",
|
32809
|
+
category: "Productivity",
|
32810
|
+
component: null,
|
32811
|
+
size: { width: 500, height: 350 },
|
32812
|
+
toolbar: null,
|
32813
|
+
statusBar: null
|
32814
|
+
},
|
32815
|
+
{
|
32816
|
+
id: "calculator",
|
32817
|
+
name: "Calculator",
|
32818
|
+
description: "Perform calculations",
|
32819
|
+
icon: "🧮",
|
32820
|
+
category: "Utilities",
|
32821
|
+
component: null,
|
32822
|
+
size: { width: 300, height: 400 }
|
32823
|
+
},
|
32824
|
+
{
|
32825
|
+
id: "settings",
|
32826
|
+
name: "Settings",
|
32827
|
+
description: "System configuration",
|
32828
|
+
icon: "⚙️",
|
32829
|
+
category: "System",
|
32830
|
+
component: null,
|
32831
|
+
size: { width: 450, height: 300 }
|
32832
|
+
},
|
32833
|
+
{
|
32834
|
+
id: "browser",
|
32835
|
+
name: "Web Browser",
|
32836
|
+
description: "Browse the internet",
|
32837
|
+
icon: "🌐",
|
32838
|
+
category: "Internet",
|
32839
|
+
component: null,
|
32840
|
+
size: { width: 800, height: 500 }
|
32841
|
+
},
|
32842
|
+
{
|
32843
|
+
id: "terminal",
|
32844
|
+
name: "Terminal",
|
32845
|
+
description: "Command line interface",
|
32846
|
+
icon: "💻",
|
32847
|
+
category: "Development",
|
32848
|
+
component: null,
|
32849
|
+
size: { width: 700, height: 400 }
|
32850
|
+
},
|
32851
|
+
{
|
32852
|
+
id: "image-viewer",
|
32853
|
+
name: "Image Viewer",
|
32854
|
+
description: "View and edit images",
|
32855
|
+
icon: "🖼️",
|
32856
|
+
category: "Media",
|
32857
|
+
component: null,
|
32858
|
+
size: { width: 600, height: 500 }
|
32859
|
+
},
|
32860
|
+
{
|
32861
|
+
id: "music-player",
|
32862
|
+
name: "Music Player",
|
32863
|
+
description: "Play audio files",
|
32864
|
+
icon: "🎵",
|
32865
|
+
category: "Media",
|
32866
|
+
component: null,
|
32867
|
+
size: { width: 400, height: 300 }
|
32868
|
+
}
|
32869
|
+
]
|
32870
|
+
};
|
32790
32871
|
const defaultAppManager = new AppManager();
|
32791
32872
|
const AppContext = createContext();
|
32792
32873
|
const useApplicationMenu = () => {
|
@@ -32803,8 +32884,17 @@ const useAppManager = () => {
|
|
32803
32884
|
}
|
32804
32885
|
return context.appManager;
|
32805
32886
|
};
|
32806
|
-
const AppProvider = ({
|
32887
|
+
const AppProvider = ({
|
32888
|
+
children,
|
32889
|
+
desktopConfig = defaultDesktopConfig
|
32890
|
+
}) => {
|
32891
|
+
const appManager = new AppManager();
|
32807
32892
|
const [isApplicationMenuOpen, setIsApplicationMenuOpen] = useState(false);
|
32893
|
+
useEffect(() => {
|
32894
|
+
if (appManager.getAllApps().length === 0 && desktopConfig) {
|
32895
|
+
AppLoader.load(appManager, desktopConfig);
|
32896
|
+
}
|
32897
|
+
}, [appManager, desktopConfig]);
|
32808
32898
|
const value = {
|
32809
32899
|
// Application Menu state
|
32810
32900
|
applicationMenu: {
|
@@ -33068,8 +33158,19 @@ const DesktopInternal = ({ desktopSize, children, ...props }) => {
|
|
33068
33158
|
}
|
33069
33159
|
)), /* @__PURE__ */ React.createElement(DesktopTaskbar, null)));
|
33070
33160
|
};
|
33071
|
-
const Desktop = ({
|
33072
|
-
|
33161
|
+
const Desktop = ({
|
33162
|
+
desktopSize,
|
33163
|
+
children,
|
33164
|
+
desktopConfig,
|
33165
|
+
...props
|
33166
|
+
}) => {
|
33167
|
+
return /* @__PURE__ */ React.createElement(
|
33168
|
+
AppProvider,
|
33169
|
+
{
|
33170
|
+
desktopConfig
|
33171
|
+
},
|
33172
|
+
/* @__PURE__ */ React.createElement(DesktopInternal, { desktopSize, ...props }, children)
|
33173
|
+
);
|
33073
33174
|
};
|
33074
33175
|
const ContentForm = ({ content, columns = 1, filter: filter2, rules, onChange }) => {
|
33075
33176
|
const form = content.form();
|