@spicemod/creator 0.0.22 → 0.0.23
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/client.d.ts +47 -0
- package/dist/bin.mjs +684 -245
- package/dist/index.d.mts +697 -0
- package/dist/{client/index.mjs → index.mjs} +1 -1
- package/dist/templates/custom-app/js/react/eslint.config.ts +29 -0
- package/dist/templates/custom-app/js/react/src/app.jsx +22 -0
- package/dist/templates/custom-app/js/react/src/components/Onboarding.jsx +82 -0
- package/dist/templates/custom-app/js/react/src/extension/index.jsx +23 -0
- package/dist/templates/custom-app/meta.json +4 -0
- package/dist/templates/custom-app/shared/DOT-gitignore +34 -0
- package/dist/templates/custom-app/shared/DOT-oxlintrc.json +36 -0
- package/dist/templates/custom-app/shared/README.template.md +53 -0
- package/dist/templates/custom-app/shared/app.css +163 -0
- package/dist/templates/custom-app/shared/biome.json +36 -0
- package/dist/templates/custom-app/shared/css/app.module.scss +58 -0
- package/dist/templates/custom-app/shared/icon-active.svg +7 -0
- package/dist/templates/custom-app/shared/icon.svg +7 -0
- package/dist/templates/custom-app/shared/jsconfig.json +32 -0
- package/dist/templates/custom-app/shared/spice.config.js +9 -0
- package/dist/templates/custom-app/shared/spice.config.ts +9 -0
- package/dist/templates/custom-app/shared/tsconfig.json +32 -0
- package/dist/templates/custom-app/ts/react/eslint.config.ts +29 -0
- package/dist/templates/custom-app/ts/react/src/app.tsx +23 -0
- package/dist/templates/custom-app/ts/react/src/components/Onboarding.tsx +105 -0
- package/dist/templates/custom-app/ts/react/src/extension/index.tsx +27 -0
- package/dist/templates/extension/js/vanilla/src/components/Onboarding.js +71 -0
- package/dist/templates/extension/shared/DOT-gitignore +34 -0
- package/dist/templates/extension/shared/DOT-oxlintrc.json +36 -0
- package/dist/templates/extension/shared/spice.config.js +1 -1
- package/dist/templates/extension/shared/spice.config.ts +1 -1
- package/dist/templates/liveReload.js +0 -1
- package/dist/templates/theme/shared/DOT-gitignore +34 -0
- package/dist/templates/theme/shared/DOT-oxlintrc.json +36 -0
- package/dist/templates/theme/shared/spice.config.js +1 -1
- package/dist/templates/theme/shared/spice.config.ts +1 -1
- package/dist/templates/wrapper.js +6 -9
- package/package.json +7 -3
- package/templates/custom-app/js/react/eslint.config.ts +29 -0
- package/templates/custom-app/js/react/src/app.jsx +22 -0
- package/templates/custom-app/js/react/src/components/Onboarding.jsx +82 -0
- package/templates/custom-app/js/react/src/extension/index.jsx +23 -0
- package/templates/custom-app/meta.json +4 -0
- package/templates/custom-app/shared/DOT-gitignore +34 -0
- package/templates/custom-app/shared/DOT-oxlintrc.json +36 -0
- package/templates/custom-app/shared/README.template.md +53 -0
- package/templates/custom-app/shared/app.css +163 -0
- package/templates/custom-app/shared/biome.json +36 -0
- package/templates/custom-app/shared/css/app.module.scss +58 -0
- package/templates/custom-app/shared/icon-active.svg +7 -0
- package/templates/custom-app/shared/icon.svg +7 -0
- package/templates/custom-app/shared/jsconfig.json +32 -0
- package/templates/custom-app/shared/spice.config.js +9 -0
- package/templates/custom-app/shared/spice.config.ts +9 -0
- package/templates/custom-app/shared/tsconfig.json +32 -0
- package/templates/custom-app/ts/react/eslint.config.ts +29 -0
- package/templates/custom-app/ts/react/src/app.tsx +23 -0
- package/templates/custom-app/ts/react/src/components/Onboarding.tsx +105 -0
- package/templates/custom-app/ts/react/src/extension/index.tsx +27 -0
- package/templates/extension/js/vanilla/src/components/Onboarding.js +71 -0
- package/templates/extension/shared/DOT-gitignore +34 -0
- package/templates/extension/shared/DOT-oxlintrc.json +36 -0
- package/templates/extension/shared/spice.config.js +1 -1
- package/templates/extension/shared/spice.config.ts +1 -1
- package/templates/liveReload.js +0 -1
- package/templates/theme/shared/DOT-gitignore +34 -0
- package/templates/theme/shared/DOT-oxlintrc.json +36 -0
- package/templates/theme/shared/spice.config.js +1 -1
- package/templates/theme/shared/spice.config.ts +1 -1
- package/templates/wrapper.js +6 -9
- package/dist/client/index.d.mts +0 -2183
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import styles from "@/css/app.module.scss";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import "@/app.css";
|
|
4
|
+
|
|
5
|
+
const App: React.FC = () => {
|
|
6
|
+
const [count, setCount] = useState(0);
|
|
7
|
+
|
|
8
|
+
const onButtonClick = () => {
|
|
9
|
+
setCount((prevCount) => prevCount + 1);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={styles.container}>
|
|
14
|
+
<div className={styles.title}>{"My Custom App!"}</div>
|
|
15
|
+
<button className={styles.button} onClick={onButtonClick}>
|
|
16
|
+
{"Count up"}
|
|
17
|
+
</button>
|
|
18
|
+
<div className={styles.counter}>{count}</div>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default App;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
interface OnboardingProps {
|
|
4
|
+
config: {
|
|
5
|
+
projectName: string;
|
|
6
|
+
framework: string;
|
|
7
|
+
language: string;
|
|
8
|
+
packageManager: string;
|
|
9
|
+
linter: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Onboarding: React.FC<OnboardingProps> = ({ config }) => {
|
|
14
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
15
|
+
const [isFading, setIsFading] = useState(false);
|
|
16
|
+
|
|
17
|
+
const handleDismiss = () => {
|
|
18
|
+
setIsFading(true);
|
|
19
|
+
setTimeout(() => setIsVisible(false), 250);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (!isVisible) return null;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
className={`onboarding-overlay ${isFading ? "fade-out" : ""}`}
|
|
27
|
+
onClick={handleDismiss}
|
|
28
|
+
>
|
|
29
|
+
<div className="onboarding-card" onClick={(e) => e.stopPropagation()}>
|
|
30
|
+
<button
|
|
31
|
+
className="close-icon-btn"
|
|
32
|
+
onClick={handleDismiss}
|
|
33
|
+
aria-label="Close"
|
|
34
|
+
>
|
|
35
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
36
|
+
<path
|
|
37
|
+
d="M1 1L11 11M1 11L11 1"
|
|
38
|
+
stroke="currentColor"
|
|
39
|
+
strokeWidth="2"
|
|
40
|
+
strokeLinecap="round"
|
|
41
|
+
/>
|
|
42
|
+
</svg>
|
|
43
|
+
</button>
|
|
44
|
+
|
|
45
|
+
<div className="status-badge">🚀 {config.projectName} Ready</div>
|
|
46
|
+
|
|
47
|
+
<div className="config-grid">
|
|
48
|
+
<span className="label">Framework</span>
|
|
49
|
+
<span className="value">{config.framework}</span>
|
|
50
|
+
|
|
51
|
+
<span className="label">Language</span>
|
|
52
|
+
<span className="value">{config.language}</span>
|
|
53
|
+
|
|
54
|
+
<span className="label">Manager</span>
|
|
55
|
+
<span className="value">{config.packageManager}</span>
|
|
56
|
+
|
|
57
|
+
<span className="label">Linter</span>
|
|
58
|
+
<span className="value">{config.linter}</span>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div className="footer-tip">
|
|
62
|
+
Next Step: Edit <code>src/app.tsx</code>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div className="onboarding-actions">
|
|
66
|
+
<button
|
|
67
|
+
className="get-started-btn"
|
|
68
|
+
onClick={() => openLink("{{get-started-link}}")}
|
|
69
|
+
>
|
|
70
|
+
Get Started
|
|
71
|
+
</button>
|
|
72
|
+
<button
|
|
73
|
+
className="get-started-btn"
|
|
74
|
+
onClick={() => {
|
|
75
|
+
Spicetify.Platform.History.push("{{project-url}}");
|
|
76
|
+
handleDismiss();
|
|
77
|
+
}}
|
|
78
|
+
>
|
|
79
|
+
Go to Custom App
|
|
80
|
+
</button>
|
|
81
|
+
<button
|
|
82
|
+
className="discord-btn"
|
|
83
|
+
onClick={() => openLink("{{discord-link}}")}
|
|
84
|
+
>
|
|
85
|
+
Join Discord
|
|
86
|
+
</button>
|
|
87
|
+
<button className="dismiss-btn" onClick={handleDismiss}>
|
|
88
|
+
Dismiss
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export default Onboarding;
|
|
97
|
+
|
|
98
|
+
function openLink(url: string, newTab = true) {
|
|
99
|
+
if (!url) return;
|
|
100
|
+
if (newTab) {
|
|
101
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
102
|
+
} else {
|
|
103
|
+
window.location.href = url;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import "@/extension/app.css";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
// you can use aliases too ! (just add them to tsconfig.json)
|
|
4
|
+
import Onboarding from "@/components/Onboarding";
|
|
5
|
+
|
|
6
|
+
const config = {
|
|
7
|
+
projectName: "{{project-name}}",
|
|
8
|
+
framework: "{{framework}}",
|
|
9
|
+
language: "{{language}}",
|
|
10
|
+
packageManager: "{{package-manager}}",
|
|
11
|
+
linter: "{{linter}}",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function main() {
|
|
15
|
+
// Create a container for the React application
|
|
16
|
+
// We append this to document.body to ensure it sits above the Spotify UI
|
|
17
|
+
const container = document.createElement("div");
|
|
18
|
+
container.id = "spicetify-onboarding-root";
|
|
19
|
+
document.body.appendChild(container);
|
|
20
|
+
|
|
21
|
+
const root = createRoot(container);
|
|
22
|
+
|
|
23
|
+
// Render the Onboarding UI
|
|
24
|
+
root.render(<Onboarding config={config} />);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
main();
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export function initOnboarding(config) {
|
|
2
|
+
const overlay = document.createElement("div");
|
|
3
|
+
overlay.className = "onboarding-overlay";
|
|
4
|
+
|
|
5
|
+
overlay.innerHTML = `
|
|
6
|
+
<div class="onboarding-card">
|
|
7
|
+
<button class="close-icon-btn" aria-label="Close" id="close-x">
|
|
8
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
9
|
+
<path d="M1 1L11 11M1 11L11 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
10
|
+
</svg>
|
|
11
|
+
</button>
|
|
12
|
+
|
|
13
|
+
<div>
|
|
14
|
+
<span class="status-dot"></span>
|
|
15
|
+
🚀 ${config.projectName} Ready
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="config-grid">
|
|
19
|
+
<span class="label">Framework</span>
|
|
20
|
+
<span class="value">${config.framework}</span>
|
|
21
|
+
|
|
22
|
+
<span class="label">Language</span>
|
|
23
|
+
<span class="value">${config.language}</span>
|
|
24
|
+
|
|
25
|
+
<span class="label">Manager</span>
|
|
26
|
+
<span class="value">${config.packageManager}</span>
|
|
27
|
+
|
|
28
|
+
<span class="label">Linter</span>
|
|
29
|
+
<span class="value">${config.linter}</span>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="footer-tip">
|
|
33
|
+
Next Step: Edit <code>src/app.tsx</code>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="onboarding-actions">
|
|
36
|
+
<button class="dismiss-btn" id="dismiss-btn">Dismiss</button>
|
|
37
|
+
<button class="discord-btn" id="discord-btn">Join Discord</button>
|
|
38
|
+
<button class="get-started-btn" id="get-started-btn">Get Started</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const dismiss = () => {
|
|
44
|
+
overlay.classList.add("fade-out");
|
|
45
|
+
overlay.addEventListener("transitionend", () => overlay.remove(), {
|
|
46
|
+
once: true,
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
overlay.addEventListener("click", (e) => {
|
|
51
|
+
if (e.target === overlay) dismiss();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function openLink(url, newTab = true) {
|
|
55
|
+
if (!url) return;
|
|
56
|
+
if (newTab) {
|
|
57
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
58
|
+
} else {
|
|
59
|
+
window.location.href = url;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const getStarted = () => openLink("{{get-started-link}}");
|
|
64
|
+
const openDiscord = () => openLink("{{discord-link}}");
|
|
65
|
+
overlay.querySelector("#close-x")?.addEventListener("click", dismiss);
|
|
66
|
+
overlay.querySelector("#dismiss-btn")?.addEventListener("click", dismiss);
|
|
67
|
+
overlay.querySelector("#discord-btn")?.addEventListener("click", openDiscord);
|
|
68
|
+
overlay.querySelector("#get-started-btn")?.addEventListener("click", getStarted);
|
|
69
|
+
|
|
70
|
+
document.body.prepend(overlay);
|
|
71
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
2
|
+
|
|
3
|
+
# dependencies
|
|
4
|
+
/node_modules
|
|
5
|
+
/.pnp
|
|
6
|
+
.pnp.*
|
|
7
|
+
.yarn/*
|
|
8
|
+
!.yarn/patches
|
|
9
|
+
!.yarn/plugins
|
|
10
|
+
!.yarn/releases
|
|
11
|
+
!.yarn/versions
|
|
12
|
+
|
|
13
|
+
# testing
|
|
14
|
+
/coverage
|
|
15
|
+
|
|
16
|
+
# build files
|
|
17
|
+
/dist
|
|
18
|
+
|
|
19
|
+
# production
|
|
20
|
+
/build
|
|
21
|
+
.spicetify/
|
|
22
|
+
|
|
23
|
+
# misc
|
|
24
|
+
.DS_Store
|
|
25
|
+
*.pem
|
|
26
|
+
|
|
27
|
+
# debug
|
|
28
|
+
npm-debug.log*
|
|
29
|
+
yarn-debug.log*
|
|
30
|
+
yarn-error.log*
|
|
31
|
+
.pnpm-debug.log*
|
|
32
|
+
|
|
33
|
+
# typescript
|
|
34
|
+
*.tsbuildinfo
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"plugins": null,
|
|
4
|
+
"categories": {},
|
|
5
|
+
"rules": {
|
|
6
|
+
"no-await-in-loop": "error",
|
|
7
|
+
"unicorn/prefer-array-find": "error",
|
|
8
|
+
"unicorn/prefer-array-flat-map": "error",
|
|
9
|
+
"unicorn/prefer-set-has": "error"
|
|
10
|
+
},
|
|
11
|
+
"settings": {
|
|
12
|
+
"jsx-a11y": {
|
|
13
|
+
"polymorphicPropName": null,
|
|
14
|
+
"components": {},
|
|
15
|
+
"attributes": {}
|
|
16
|
+
},
|
|
17
|
+
"react": {
|
|
18
|
+
"formComponents": [],
|
|
19
|
+
"linkComponents": [],
|
|
20
|
+
"version": null,
|
|
21
|
+
"componentWrapperFunctions": []
|
|
22
|
+
},
|
|
23
|
+
"jsdoc": {
|
|
24
|
+
"ignorePrivate": false,
|
|
25
|
+
"ignoreInternal": false,
|
|
26
|
+
"ignoreReplacesDocs": true,
|
|
27
|
+
"overrideReplacesDocs": true,
|
|
28
|
+
"augmentsExtendsReplacesDocs": false,
|
|
29
|
+
"implementsReplacesDocs": false,
|
|
30
|
+
"exemptDestructuredRootsFromChecks": false,
|
|
31
|
+
"tagNamePreference": {}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"globals": {},
|
|
35
|
+
"ignorePatterns": ["dist/**"]
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
2
|
+
|
|
3
|
+
# dependencies
|
|
4
|
+
/node_modules
|
|
5
|
+
/.pnp
|
|
6
|
+
.pnp.*
|
|
7
|
+
.yarn/*
|
|
8
|
+
!.yarn/patches
|
|
9
|
+
!.yarn/plugins
|
|
10
|
+
!.yarn/releases
|
|
11
|
+
!.yarn/versions
|
|
12
|
+
|
|
13
|
+
# testing
|
|
14
|
+
/coverage
|
|
15
|
+
|
|
16
|
+
# build files
|
|
17
|
+
/dist
|
|
18
|
+
|
|
19
|
+
# production
|
|
20
|
+
/build
|
|
21
|
+
.spicetify/
|
|
22
|
+
|
|
23
|
+
# misc
|
|
24
|
+
.DS_Store
|
|
25
|
+
*.pem
|
|
26
|
+
|
|
27
|
+
# debug
|
|
28
|
+
npm-debug.log*
|
|
29
|
+
yarn-debug.log*
|
|
30
|
+
yarn-error.log*
|
|
31
|
+
.pnpm-debug.log*
|
|
32
|
+
|
|
33
|
+
# typescript
|
|
34
|
+
*.tsbuildinfo
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"plugins": null,
|
|
4
|
+
"categories": {},
|
|
5
|
+
"rules": {
|
|
6
|
+
"no-await-in-loop": "error",
|
|
7
|
+
"unicorn/prefer-array-find": "error",
|
|
8
|
+
"unicorn/prefer-array-flat-map": "error",
|
|
9
|
+
"unicorn/prefer-set-has": "error"
|
|
10
|
+
},
|
|
11
|
+
"settings": {
|
|
12
|
+
"jsx-a11y": {
|
|
13
|
+
"polymorphicPropName": null,
|
|
14
|
+
"components": {},
|
|
15
|
+
"attributes": {}
|
|
16
|
+
},
|
|
17
|
+
"react": {
|
|
18
|
+
"formComponents": [],
|
|
19
|
+
"linkComponents": [],
|
|
20
|
+
"version": null,
|
|
21
|
+
"componentWrapperFunctions": []
|
|
22
|
+
},
|
|
23
|
+
"jsdoc": {
|
|
24
|
+
"ignorePrivate": false,
|
|
25
|
+
"ignoreInternal": false,
|
|
26
|
+
"ignoreReplacesDocs": true,
|
|
27
|
+
"overrideReplacesDocs": true,
|
|
28
|
+
"augmentsExtendsReplacesDocs": false,
|
|
29
|
+
"implementsReplacesDocs": false,
|
|
30
|
+
"exemptDestructuredRootsFromChecks": false,
|
|
31
|
+
"tagNamePreference": {}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"globals": {},
|
|
35
|
+
"ignorePatterns": ["dist/**"]
|
|
36
|
+
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
__ESBUILD__HAS_CSS &&
|
|
2
2
|
(async () => {
|
|
3
3
|
try {
|
|
4
|
-
const css =
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
} catch {}
|
|
4
|
+
const css = __ESBUILD__INJECTED_CSS;
|
|
5
|
+
const style = document.createElement("style");
|
|
6
|
+
style.setAttribute("data-app", __ESBUILD__APP_ID);
|
|
7
|
+
style.textContent = css;
|
|
8
|
+
document.head.appendChild(style);
|
|
9
|
+
} catch { }
|
|
12
10
|
})();
|
|
13
11
|
(async () => {
|
|
14
12
|
const _ID = `${__ESBUILD__APP_SLUG}-${__ESBUILD__APP_TYPE}`;
|
|
@@ -16,7 +14,6 @@ __ESBUILD__HAS_CSS &&
|
|
|
16
14
|
window.SpiceGlobals[_ID] = {
|
|
17
15
|
id: __ESBUILD__APP_ID,
|
|
18
16
|
version: __ESBUILD__APP_VERSION,
|
|
19
|
-
hash: __ESBUILD__APP_HASH,
|
|
20
17
|
};
|
|
21
18
|
const { id: appId, version: v } = window.SpiceGlobals[_ID];
|
|
22
19
|
const _wait = (p, a = 0) =>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spicemod/creator",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"description": "Easily make Spicetify extensions and themes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -21,12 +21,16 @@
|
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"dist",
|
|
24
|
-
"templates"
|
|
24
|
+
"templates",
|
|
25
|
+
"client.d.ts"
|
|
25
26
|
],
|
|
26
27
|
"type": "module",
|
|
27
28
|
"exports": {
|
|
29
|
+
".": "./dist/index.mjs",
|
|
30
|
+
"./client": {
|
|
31
|
+
"types": "./client.d.ts"
|
|
32
|
+
},
|
|
28
33
|
"./bin": "./dist/bin.mjs",
|
|
29
|
-
"./client": "./dist/client/index.mjs",
|
|
30
34
|
"./package.json": "./package.json"
|
|
31
35
|
},
|
|
32
36
|
"scripts": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
import globals from "globals";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
import react from "eslint-plugin-react";
|
|
5
|
+
import css from "@eslint/css";
|
|
6
|
+
import { defineConfig } from "eslint/config";
|
|
7
|
+
|
|
8
|
+
export default defineConfig([
|
|
9
|
+
{
|
|
10
|
+
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
11
|
+
plugins: { js, react },
|
|
12
|
+
extends: ["js/recommended"],
|
|
13
|
+
languageOptions: {
|
|
14
|
+
parserOptions: {
|
|
15
|
+
ecmaFeatures: {
|
|
16
|
+
jsx: true,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
globals: globals.browser,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
tseslint.configs.recommended,
|
|
23
|
+
{
|
|
24
|
+
files: ["**/*.css"],
|
|
25
|
+
plugins: { css },
|
|
26
|
+
language: "css/css",
|
|
27
|
+
extends: ["css/recommended"],
|
|
28
|
+
},
|
|
29
|
+
]);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import styles from "@/css/app.module.scss";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
const App = () => {
|
|
5
|
+
const [count, setCount] = useState(0);
|
|
6
|
+
|
|
7
|
+
const onButtonClick = () => {
|
|
8
|
+
setCount((prevCount) => prevCount + 1);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className={styles.container}>
|
|
13
|
+
<div className={styles.title}>{"My Custom App!"}</div>
|
|
14
|
+
<button className={styles.button} onClick={onButtonClick}>
|
|
15
|
+
{"Count up"}
|
|
16
|
+
</button>
|
|
17
|
+
<div className={styles.counter}>{count}</div>
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default App;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
const Onboarding = ({ config }) => {
|
|
4
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
5
|
+
const [isFading, setIsFading] = useState(false);
|
|
6
|
+
|
|
7
|
+
const handleDismiss = () => {
|
|
8
|
+
setIsFading(true);
|
|
9
|
+
setTimeout(() => setIsVisible(false), 250);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
if (!isVisible) return null;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className={`onboarding-overlay ${isFading ? "fade-out" : ""}`} onClick={handleDismiss}>
|
|
16
|
+
<div className="onboarding-card" onClick={(e) => e.stopPropagation()}>
|
|
17
|
+
<button className="close-icon-btn" onClick={handleDismiss} aria-label="Close">
|
|
18
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
|
19
|
+
<path
|
|
20
|
+
d="M1 1L11 11M1 11L11 1"
|
|
21
|
+
stroke="currentColor"
|
|
22
|
+
strokeWidth="2"
|
|
23
|
+
strokeLinecap="round"
|
|
24
|
+
/>
|
|
25
|
+
</svg>
|
|
26
|
+
</button>
|
|
27
|
+
|
|
28
|
+
<div className="status-badge">🚀 {config.projectName} Ready</div>
|
|
29
|
+
|
|
30
|
+
<div className="config-grid">
|
|
31
|
+
<span className="label">Framework</span>
|
|
32
|
+
<span className="value">{config.framework}</span>
|
|
33
|
+
|
|
34
|
+
<span className="label">Language</span>
|
|
35
|
+
<span className="value">{config.language}</span>
|
|
36
|
+
|
|
37
|
+
<span className="label">Manager</span>
|
|
38
|
+
<span className="value">{config.packageManager}</span>
|
|
39
|
+
|
|
40
|
+
<span className="label">Linter</span>
|
|
41
|
+
<span className="value">{config.linter}</span>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div className="footer-tip">
|
|
45
|
+
Next Step: Edit <code>src/app.tsx</code>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div className="onboarding-actions">
|
|
49
|
+
<button className="get-started-btn" onClick={() => openLink("{{get-started-link}}")}>
|
|
50
|
+
Get Started
|
|
51
|
+
</button>
|
|
52
|
+
<button
|
|
53
|
+
className="get-started-btn"
|
|
54
|
+
onClick={() => {
|
|
55
|
+
Spicetify.Platform.History.push("{{project-url}}");
|
|
56
|
+
handleDismiss();
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
Go to Custom App
|
|
60
|
+
</button>
|
|
61
|
+
<button className="discord-btn" onClick={() => openLink("{{discord-link}}")}>
|
|
62
|
+
Join Discord
|
|
63
|
+
</button>
|
|
64
|
+
<button className="dismiss-btn" onClick={handleDismiss}>
|
|
65
|
+
Dismiss
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default Onboarding;
|
|
74
|
+
|
|
75
|
+
function openLink(url, newTab = true) {
|
|
76
|
+
if (!url) return;
|
|
77
|
+
if (newTab) {
|
|
78
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
79
|
+
} else {
|
|
80
|
+
window.location.href = url;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import styles from "@/css/app.module.scss";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import "@/app.css";
|
|
4
|
+
|
|
5
|
+
const App = () => {
|
|
6
|
+
const [count, setCount] = useState(0);
|
|
7
|
+
|
|
8
|
+
const onButtonClick = () => {
|
|
9
|
+
setCount((prevCount) => prevCount + 1);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={styles.container}>
|
|
14
|
+
<div className={styles.title}>{"My Custom App!"}</div>
|
|
15
|
+
<button className={styles.button} onClick={onButtonClick}>
|
|
16
|
+
{"Count up"}
|
|
17
|
+
</button>
|
|
18
|
+
<div className={styles.counter}>{count}</div>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default App;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
2
|
+
|
|
3
|
+
# dependencies
|
|
4
|
+
/node_modules
|
|
5
|
+
/.pnp
|
|
6
|
+
.pnp.*
|
|
7
|
+
.yarn/*
|
|
8
|
+
!.yarn/patches
|
|
9
|
+
!.yarn/plugins
|
|
10
|
+
!.yarn/releases
|
|
11
|
+
!.yarn/versions
|
|
12
|
+
|
|
13
|
+
# testing
|
|
14
|
+
/coverage
|
|
15
|
+
|
|
16
|
+
# build files
|
|
17
|
+
/dist
|
|
18
|
+
|
|
19
|
+
# production
|
|
20
|
+
/build
|
|
21
|
+
.spicetify/
|
|
22
|
+
|
|
23
|
+
# misc
|
|
24
|
+
.DS_Store
|
|
25
|
+
*.pem
|
|
26
|
+
|
|
27
|
+
# debug
|
|
28
|
+
npm-debug.log*
|
|
29
|
+
yarn-debug.log*
|
|
30
|
+
yarn-error.log*
|
|
31
|
+
.pnpm-debug.log*
|
|
32
|
+
|
|
33
|
+
# typescript
|
|
34
|
+
*.tsbuildinfo
|