Skip to content

Commit a9f57d1

Browse files
add package manager
1 parent cf6e197 commit a9f57d1

File tree

6 files changed

+193
-11
lines changed

6 files changed

+193
-11
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Online playground for write and play JavaScript, TypeScript, Vue, React, Lit, So
3434
- [ ] add settings
3535
- [ ] add check sketches
3636
- [ ] add comment sketch
37+
- [x] tab package manager
3738
- [ ] add like sketch
3839
- [ ] share sketch offline
3940
- [ ] add a compiler/interpreter to run C/C++, Python or Ruby

preview/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"version": "0.0.0",
55
"type": "module",
66
"scripts": {
7-
"dev": "vite --port 9999",
7+
"dev": "vite --port 9889",
88
"build": "rm -f public/src_sw.ts.js && vite build && vite build -c vite-com.config.ts --emptyOutDir false && vite build -c vite-inject.config.ts --emptyOutDir false",
99
"preview": "vite preview"
1010
},

quasar.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ module.exports = configure(function (/* ctx */) {
6868
PREVIEW_URL: process.env.GITPOD_WORKSPACE_URL
6969
? process.env.GITPOD_WORKSPACE_URL.replace(
7070
"https://",
71-
"https://9999-"
71+
"https://9889-"
7272
)
7373
: process.env.CODESPACE_NAME
74-
? `https://${process.env.CODESPACE_NAME}-9999.${process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}`
74+
? `https://${process.env.CODESPACE_NAME}-9889.${process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}`
7575
: undefined,
7676
...process.env,
7777
...require("dotenv").config().parsed,
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<template>
2+
<header class="py-2 px-3 text-12px flex justify-between">PACKAGES</header>
3+
<main v-if="sketchStore.rootのsketch" class="min-h-0 px-3 select-none">
4+
<q-select
5+
v-model="packageName"
6+
filled
7+
use-input
8+
dense
9+
hide-selected
10+
fill-input
11+
:options="options"
12+
:option-label="
13+
(item) => (isVersion(item) ? item.version : item.package.name)
14+
"
15+
@filter="filterFn"
16+
debounce="500"
17+
placeholder="Enter for add package"
18+
class="q-input--custom mt-2"
19+
>
20+
<template v-slot:option="scope">
21+
<q-item clickable @click="clickItemPackage(scope.opt)">
22+
<q-item-section>
23+
<q-item-label>
24+
<span :class="{ 'line-through': scope.opt.deprecated }">
25+
{{
26+
isVersion(scope.opt)
27+
? scope.opt.version
28+
: scope.opt.package.name
29+
}}
30+
</span>
31+
</q-item-label>
32+
<q-item-label
33+
v-if="scope.opt.package ?? scope.opt.deprecated"
34+
caption
35+
>{{
36+
scope.opt.package.description ?? scope.opt.deprecated
37+
}}</q-item-label
38+
>
39+
</q-item-section>
40+
</q-item>
41+
</template>
42+
</q-select>
43+
44+
<h4 class="text-subtitle2 mt-5">Dependencies</h4>
45+
<ul>
46+
<li
47+
v-for="(version, name) in sketchStore.packageのFile.data?.dependencies"
48+
:key="name"
49+
class="flex flex-nowrap items-center justify-between px2 py-1"
50+
>
51+
<span class="block truncate min-w-0">{{ name }}</span>
52+
<span class="text-gray-300 flex flex-nowrap">
53+
<div class="truncate">
54+
{{ version }}
55+
</div>
56+
57+
<q-btn
58+
dense
59+
round
60+
padding="0"
61+
class="ml-1"
62+
@click="delete sketchStore.packageのFile.data.dependencies![name]"
63+
>
64+
<Icon
65+
icon="fluent:delete-24-regular"
66+
width="1.3em"
67+
height="1.3em"
68+
/>
69+
</q-btn>
70+
</span>
71+
</li>
72+
</ul>
73+
</main>
74+
<MainOpenSketch v-else />
75+
</template>
76+
77+
<script lang="ts" setup>
78+
import { Icon } from "@iconify/vue"
79+
80+
const sketchStore = useSketchStore()
81+
82+
const packageName = ref()
83+
84+
interface NpmSearch {
85+
objects: {
86+
package: {
87+
name: string
88+
scope: string
89+
version: string
90+
description: string
91+
keywords: string[]
92+
date: string
93+
links: {
94+
npm: string
95+
homepage: string
96+
repository: string
97+
bugs: string
98+
}
99+
publisher: {
100+
username: string
101+
email: string
102+
}
103+
maintainers: {
104+
username: string
105+
email: string
106+
}[]
107+
author?: undefined
108+
}
109+
score: {
110+
final: number
111+
detail: {
112+
quality: number
113+
popularity: number
114+
maintenance: number
115+
}
116+
}
117+
searchScore: number
118+
flags?: undefined
119+
}[]
120+
total: number
121+
time: string
122+
}
123+
interface NpmPackage {
124+
versions: Record<
125+
string,
126+
{
127+
name: string
128+
version: string
129+
deprecated?: string
130+
}
131+
>
132+
}
133+
134+
const isVersion = (value: any): value is NpmPackage["versions"][""] =>
135+
"version" in value
136+
137+
const options = shallowRef<
138+
NpmSearch["objects"] | NpmPackage["versions"][""][]
139+
>()
140+
141+
const clickItemPackage = async (
142+
pkg: NpmSearch["objects"][0] | NpmPackage["versions"][""]
143+
) => {
144+
if (isVersion(pkg)) {
145+
await sketchStore.packageFile.ready
146+
147+
if (!sketchStore.packageFile.data) sketchStore.packageFile.data = {}
148+
if (!sketchStore.packageFile.data.dependencies)
149+
sketchStore.packageFile.data.dependencies = {}
150+
151+
sketchStore.packageFile.data.dependencies[pkg.name] = pkg.version
152+
153+
packageName.value = undefined
154+
} else
155+
options.value = await fetch(
156+
`https://registry.npmjs.org/${pkg.package.name}`
157+
)
158+
.then((res) => res.json() as Promise<NpmPackage>)
159+
.then((res) => Object.values(res.versions).reverse())
160+
}
161+
162+
function filterFn(
163+
inputValue: string,
164+
doneFn: (cb: () => void) => void,
165+
abort: () => void
166+
) {
167+
fetch(`https://registry.npmjs.org/-/v1/search?text=${inputValue}`)
168+
.then((res) => res.json())
169+
// eslint-disable-next-line promise/always-return
170+
.then((result: NpmSearch) => {
171+
doneFn(() => {
172+
options.value = result.objects
173+
})
174+
})
175+
.catch(abort)
176+
}
177+
</script>

src/components/sketch/SideBar/SideBar.vue

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131

3232
<q-separator class="!w-[calc(100%-12px)] h-1px" />
3333

34-
<button class="w-48px h-48px hover:text-gray-400 relative">
35-
<Icon icon="fluent:window-console-20-filled" class="w-24px h-24px" />
36-
</button>
37-
3834
<button
3935
class="w-48px h-48px hover:text-gray-400 relative"
4036
@click="settingsLayout = true"
@@ -138,6 +134,9 @@
138134
<KeepAlive>
139135
<Changes v-if="!sketchStore.fetching && tabSelection === 'change'" />
140136
</KeepAlive>
137+
<KeepAlive>
138+
<PackageManager v-if="!sketchStore.fetching && tabSelection === 'package'" />
139+
</KeepAlive>
141140
</div>
142141
</Resizable>
143142

@@ -155,8 +154,8 @@ const user = useUser<User>()
155154
const sketchStore = useSketchStore()
156155
157156
const tabSelection = ref<
158-
null | "info" | "file" | "search" | "change" | "setting"
159-
>("file")
157+
null | "info" | "file" | "search" | "change" | "setting" | "package"
158+
>("package")
160159
const tabs: {
161160
icon: string
162161
value: Exclude<typeof tabSelection.value, null>
@@ -179,6 +178,10 @@ const tabs: {
179178
value: "change",
180179
badge: computed(() => Object.keys(sketchStore.変化).length),
181180
},
181+
{
182+
icon: "codicon:package",
183+
value: "package",
184+
},
182185
]
183186
184187
const settingsLayout = ref(false)

src/stores/sketch.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,13 @@ export const useSketchStore = defineStore("sketch", () => {
524524

525525
return cur
526526
}
527-
const packageのFile = useFile<Readonly<PackageJSON>, false>(
527+
const packageのFile = useFile<PackageJSON, true>(
528528
() => `${rootのsketch.value}/package.json`,
529529
JSON.stringify(null),
530-
false,
530+
true,
531531
{
532532
get: parseJSON,
533+
set: (e) => JSON.stringify(e, null, 2),
533534
}
534535
)
535536

0 commit comments

Comments
 (0)