mirror of
https://github.com/web3privacy/explorer-app.git
synced 2024-10-15 16:46:26 +02:00
Merge pull request #20 from web3privacy/dw/form
feat: form & github api
This commit is contained in:
commit
6a8a305ce7
48 changed files with 3666 additions and 126 deletions
7
app.config.ts
Normal file
7
app.config.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export default defineAppConfig({
|
||||||
|
github: {
|
||||||
|
appId: 0,
|
||||||
|
privateKey: '',
|
||||||
|
installationId: 0,
|
||||||
|
},
|
||||||
|
})
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
defineProps<{
|
||||||
border?: boolean
|
border?: boolean
|
||||||
|
invertedColor?: boolean
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -8,14 +9,14 @@ defineProps<{
|
||||||
<div
|
<div
|
||||||
flex
|
flex
|
||||||
items-center
|
items-center
|
||||||
|
justify-center
|
||||||
gap-12px
|
gap-12px
|
||||||
px-12px
|
px-12px
|
||||||
py-6px
|
py-6px
|
||||||
cursor-pointer
|
cursor-pointer
|
||||||
text-app-white
|
:class="[border ? 'border-2px border-app-white' : 'border-0',
|
||||||
:class="[border ? 'border-2px border-app-white' : 'border-0']"
|
invertedColor ? 'bg-app-white text-app-black hover:text-app-white hover:bg-app-black' : 'text-app-white bg-app-black hover:text-app-black hover:bg-app-white',
|
||||||
hover:text-app-black
|
]"
|
||||||
hover:bg-app-white
|
|
||||||
>
|
>
|
||||||
<template v-if="!!$slots.prefix">
|
<template v-if="!!$slots.prefix">
|
||||||
<div text-24px>
|
<div text-24px>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { InputOption } from '~/types'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
options: InputOption[]
|
options: InputOption[]
|
||||||
modelValue: string
|
modelValue: string | number
|
||||||
count?: number
|
count?: number
|
||||||
titleShowCount?: boolean
|
titleShowCount?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
@ -14,7 +14,7 @@ const selectedValue = useVModel(props, 'modelValue', emits)
|
||||||
const isOptionSelected = computed(() => {
|
const isOptionSelected = computed(() => {
|
||||||
return props.options.find(option => option.value === selectedValue.value)
|
return props.options.find(option => option.value === selectedValue.value)
|
||||||
})
|
})
|
||||||
function onOptionSelected(value: string) {
|
function onOptionSelected(value: string | number) {
|
||||||
emits('selected', value)
|
emits('selected', value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
defineProps<{
|
||||||
to: string
|
to?: string
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ watch(y, (newY, oldY) => {
|
||||||
lg:bg-app-bg-dark_grey
|
lg:bg-app-bg-dark_grey
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="!isProjectRoute"
|
v-if="!isProjectRoute && !route.fullPath.includes('create') && !route.fullPath.includes('edit')"
|
||||||
relative
|
relative
|
||||||
app-container
|
app-container
|
||||||
w-full
|
w-full
|
||||||
|
@ -355,7 +355,10 @@ watch(y, (newY, oldY) => {
|
||||||
:class="[(!showBar && width < 768) ? 'translate-y--128px' : 'translate-y-0px']"
|
:class="[(!showBar && width < 768) ? 'translate-y--128px' : 'translate-y-0px']"
|
||||||
duration-200ms
|
duration-200ms
|
||||||
>
|
>
|
||||||
<ProjectNavigation md:mt-16px />
|
<ProjectNavigation
|
||||||
|
v-if="!route.fullPath.includes('create') && !route.fullPath.includes('edit')"
|
||||||
|
md:mt-16px
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
|
|
181
components/Project/Create/Categories/Assets.vue
Normal file
181
components/Project/Create/Categories/Assets.vue
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
type Token = {
|
||||||
|
name: string
|
||||||
|
symbol: string
|
||||||
|
contract_address: string
|
||||||
|
token_link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function useTokens(project?: Partial<Project>) {
|
||||||
|
const tokens = ref<Token[]>(project?.tokens as Token[] || [])
|
||||||
|
const newToken = reactive<Token>({
|
||||||
|
symbol: '',
|
||||||
|
name: '',
|
||||||
|
contract_address: '',
|
||||||
|
token_link: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
function addToken() {
|
||||||
|
tokens.value.push({ ...newToken })
|
||||||
|
newToken.symbol = ''
|
||||||
|
newToken.name = ''
|
||||||
|
newToken.contract_address = ''
|
||||||
|
newToken.token_link = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeToken(index: number) {
|
||||||
|
tokens.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
tokens,
|
||||||
|
newToken,
|
||||||
|
addToken,
|
||||||
|
removeToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tokens, newToken, addToken, removeToken } = useTokens(props.project)
|
||||||
|
const assetsUsed = ref<string[]>(Array.isArray(props.project?.assets_used) ? props.project?.assets_used.map(a => a.toLowerCase()) : [])
|
||||||
|
|
||||||
|
const { assets: assetsData } = useData()
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
assets_used: assetsUsed.value,
|
||||||
|
have_token: tokens.value.length > 0 && tokens.value.some(token => token.contract_address),
|
||||||
|
tokens: tokens.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div mt-24px>
|
||||||
|
<ClientOnly>
|
||||||
|
<ProjectCreateComponentsSelectChips
|
||||||
|
v-model="assetsUsed"
|
||||||
|
label="Assets used"
|
||||||
|
:options="assetsData?.map(asset => ({ label: asset.name, value: asset.id }))"
|
||||||
|
placeholder="Add assets"
|
||||||
|
hint="Most used assets user can use to interact with your project"
|
||||||
|
can-add-new
|
||||||
|
/>
|
||||||
|
</ClientOnly>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="NATIVE TOKENS"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsItem
|
||||||
|
v-for="token in tokens"
|
||||||
|
:key="token.name"
|
||||||
|
@remove="() => removeToken(tokens.indexOf(token))"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
gap-2px
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-app-black text-14px font-700"
|
||||||
|
lg="text-16px"
|
||||||
|
> {{ token.symbol }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-if="token.name"
|
||||||
|
class="text-app-black text-14px font-400"
|
||||||
|
lg="text-16px"
|
||||||
|
> {{ `(${token.name})` }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #desc>
|
||||||
|
<NuxtLink
|
||||||
|
target="_blank"
|
||||||
|
:to="token.token_link"
|
||||||
|
hover:text-app-black
|
||||||
|
class="text-app-black/50 text-16px hidden"
|
||||||
|
lg="block"
|
||||||
|
>Etherscan
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItem>
|
||||||
|
<ProjectCreateComponentsItemAdd
|
||||||
|
button-label="ADD TOKEN"
|
||||||
|
@add="addToken()"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="gap-24px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
lg="flex-row gap-24px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-100%"
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="flex-row gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newToken.symbol"
|
||||||
|
w-full
|
||||||
|
label="Token symbol"
|
||||||
|
placeholder="Token symbol"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newToken.name"
|
||||||
|
w-full
|
||||||
|
label="Token name"
|
||||||
|
placeholder="Token name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="w-100%"
|
||||||
|
lg="mt-32px left-1/2 self-center"
|
||||||
|
font-400
|
||||||
|
italic
|
||||||
|
lg:text-14px
|
||||||
|
text-12px
|
||||||
|
text-app-white
|
||||||
|
opacity-50
|
||||||
|
>
|
||||||
|
{{ 'Does your project have native token? Enter Symbol, name and address' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newToken.contract_address"
|
||||||
|
lg="w-1/2"
|
||||||
|
label="Token contract address"
|
||||||
|
placeholder="Contract address"
|
||||||
|
hint="Enter token contract address"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newToken.token_link"
|
||||||
|
lg="w-1/2"
|
||||||
|
label="URL for explorer"
|
||||||
|
placeholder="Token explorer URL"
|
||||||
|
hint="Link to any explorer showing data about your native token"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItemAdd>
|
||||||
|
</div>
|
||||||
|
</template>
|
128
components/Project/Create/Categories/BasicInfo.vue
Normal file
128
components/Project/Create/Categories/BasicInfo.vue
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as yup from 'yup'
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { categories: categoriesData, usecases: usecasesData, ecosystems: ecosystemsData } = useData()
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
const validationSchema = yup.object().shape({
|
||||||
|
categories: yup.array().of(yup.string()).required().min(1),
|
||||||
|
usecases: yup.array().of(yup.string()).required().min(1),
|
||||||
|
ecosystems: yup.array().of(yup.string()).required().min(1),
|
||||||
|
description: yup.string().required(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const { validate, meta, resetForm } = useForm({
|
||||||
|
validationSchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { value: categories, errorMessage: categoriesError } = useField<string[]>('categories')
|
||||||
|
const { value: usecases, errorMessage: usecasesError } = useField<string[]>('usecases')
|
||||||
|
const { value: ecosystems, errorMessage: ecosystemsError } = useField<string[]>('ecosystems')
|
||||||
|
const { value: description, errorMessage: descriptionError } = useField<string>('description')
|
||||||
|
const day = ref(new Date(props.project?.product_launch_day || '').getDay())
|
||||||
|
const month = ref(new Date(props.project?.product_launch_day || '').getMonth())
|
||||||
|
const year = ref(new Date(props.project?.product_launch_day || '').getFullYear())
|
||||||
|
const isDead = ref(props.project?.sunset || false)
|
||||||
|
|
||||||
|
resetForm({
|
||||||
|
values: {
|
||||||
|
categories: Array.isArray(props.project?.categories) ? props.project?.categories?.map(c => c.toLowerCase()) : [],
|
||||||
|
usecases: Array.isArray(props.project?.usecases) ? props.project?.usecases?.map(u => u.toLowerCase()) : [],
|
||||||
|
ecosystems: Array.isArray(props.project?.ecosystem) ? props.project?.ecosystem?.map(e => e.toLowerCase()) : [],
|
||||||
|
description: props.project?.description || '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
function isFormValid() {
|
||||||
|
validate()
|
||||||
|
|
||||||
|
if (meta.value.valid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
categories: categories.value,
|
||||||
|
usecases: usecases.value,
|
||||||
|
ecosystem: ecosystems.value,
|
||||||
|
description: description.value,
|
||||||
|
product_launch_day: (year.value && month.value && day.value) ? new Date(year.value, month.value, day.value).toISOString() : undefined,
|
||||||
|
sunset: isDead.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
isFormValid,
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div mt-24px>
|
||||||
|
<ProjectCreateComponentsSelectChips
|
||||||
|
v-model="categories"
|
||||||
|
label="Categories"
|
||||||
|
required
|
||||||
|
:options="categoriesData?.map(cat => ({ label: cat.name, value: cat.id }))"
|
||||||
|
placeholder="Add category"
|
||||||
|
hint="Choose categories that fits your project"
|
||||||
|
:error="categoriesError"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsSelectChips
|
||||||
|
v-model="usecases"
|
||||||
|
label="Use-cases"
|
||||||
|
required
|
||||||
|
:options="usecasesData?.map(uc => ({ label: uc.name, value: uc.id }))"
|
||||||
|
placeholder="Add use-case"
|
||||||
|
hint="What can be your project used for?"
|
||||||
|
:error="usecasesError"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsSelectChips
|
||||||
|
v-model="ecosystems"
|
||||||
|
label="Ecosystems"
|
||||||
|
required
|
||||||
|
:options="ecosystemsData?.map(ec => ({ label: ec.name, value: ec.id }))"
|
||||||
|
placeholder="Add ecosystem"
|
||||||
|
hint="Choose ecosystems that is your project part of"
|
||||||
|
:error="ecosystemsError"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="description"
|
||||||
|
lg="w-1/2"
|
||||||
|
label="Description"
|
||||||
|
text-area
|
||||||
|
required
|
||||||
|
hint="What kind of technology you use, what are your special features
|
||||||
|
and why should user use your project."
|
||||||
|
placeholder="Write something about your project"
|
||||||
|
:error="descriptionError"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsDatePicker
|
||||||
|
v-model:day="day"
|
||||||
|
v-model:month="month"
|
||||||
|
v-model:year="year"
|
||||||
|
label="Project launch date"
|
||||||
|
hint="Date of project emergence (Optional)"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
text-16px
|
||||||
|
font-400
|
||||||
|
lg="text-16px"
|
||||||
|
>Other Information
|
||||||
|
</span>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="isDead"
|
||||||
|
label="Sunset (project is dead)"
|
||||||
|
hint="Check if project is currently running and working"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
115
components/Project/Create/Categories/Funding.vue
Normal file
115
components/Project/Create/Categories/Funding.vue
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
type Fundings = {
|
||||||
|
name: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function useFundings(project?: Partial<Project>) {
|
||||||
|
const fundings = ref<Fundings[]>(project?.funding as Fundings[] || [])
|
||||||
|
const newFunding = reactive<Fundings>({
|
||||||
|
name: '',
|
||||||
|
link: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
function addFunding() {
|
||||||
|
fundings.value.push({ ...newFunding })
|
||||||
|
newFunding.name = ''
|
||||||
|
newFunding.link = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFunding(index: number) {
|
||||||
|
fundings.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
fundings,
|
||||||
|
newFunding,
|
||||||
|
addFunding,
|
||||||
|
removeFunding,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { fundings, newFunding, addFunding, removeFunding } = useFundings(props.project)
|
||||||
|
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
funding: fundings.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="FUNDING"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsItem
|
||||||
|
v-for="funding in fundings"
|
||||||
|
:key="funding.name"
|
||||||
|
@remove="() => removeFunding(fundings.indexOf(funding))"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
gap-2px
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-app-black text-14px font-700"
|
||||||
|
lg="text-16px"
|
||||||
|
> {{ funding.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #desc>
|
||||||
|
<NuxtLink
|
||||||
|
:to="funding.link"
|
||||||
|
hover:text-app-black
|
||||||
|
class="text-app-black/50 text-16px hidden"
|
||||||
|
lg="block"
|
||||||
|
>Link
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItem>
|
||||||
|
<ProjectCreateComponentsItemAdd
|
||||||
|
button-label="ADD FUNDING"
|
||||||
|
@add="addFunding()"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newFunding.name"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Name"
|
||||||
|
placeholder="Investor's name"
|
||||||
|
hint="Name of entity investing into project"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newFunding.link"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Link confirming investment"
|
||||||
|
placeholder="Add URL"
|
||||||
|
hint="Link to Article, PR or other sources confirming funding information"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItemAdd>
|
||||||
|
</div>
|
||||||
|
</template>
|
165
components/Project/Create/Categories/History.vue
Normal file
165
components/Project/Create/Categories/History.vue
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
type Event = {
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
link: string
|
||||||
|
time: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function useEvents(project?: Partial<Project>) {
|
||||||
|
const events = ref<Event[]>(project?.history as Event[] || [])
|
||||||
|
const newEvent = reactive<Event>({
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
link: '',
|
||||||
|
time: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const day = ref<number>()
|
||||||
|
const month = ref<number>()
|
||||||
|
const year = ref<number>()
|
||||||
|
|
||||||
|
function addEvent() {
|
||||||
|
events.value.push({ ...newEvent })
|
||||||
|
newEvent.title = ''
|
||||||
|
newEvent.description = ''
|
||||||
|
newEvent.link = ''
|
||||||
|
newEvent.time = ''
|
||||||
|
day.value = undefined
|
||||||
|
month.value = undefined
|
||||||
|
year.value = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeEvent(index: number) {
|
||||||
|
events.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
events,
|
||||||
|
newEvent,
|
||||||
|
day,
|
||||||
|
month,
|
||||||
|
year,
|
||||||
|
addEvent,
|
||||||
|
removeEvent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { events, newEvent, addEvent, removeEvent, day, month, year } = useEvents(props.project)
|
||||||
|
|
||||||
|
watch([day, month, year], () => {
|
||||||
|
const yearValue = year.value
|
||||||
|
const monthValue = month.value
|
||||||
|
const dayValue = day.value
|
||||||
|
|
||||||
|
if (!yearValue || !monthValue || !dayValue) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
newEvent.time = new Date(yearValue, monthValue - 1, dayValue).toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
function formatDate(date: string) {
|
||||||
|
const d = new Date(date)
|
||||||
|
const day = String(d.getDate()).padStart(2, '0')
|
||||||
|
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||||
|
const year = d.getFullYear()
|
||||||
|
return `${day}/${month}/${year}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
history: events.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div mt-24px>
|
||||||
|
<ProjectCreateComponentsItem
|
||||||
|
v-for="event in events"
|
||||||
|
:key="event.title"
|
||||||
|
@remove="() => removeEvent(events.indexOf(event))"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
gap-2px
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-app-black text-14px font-700"
|
||||||
|
lg="text-16px"
|
||||||
|
> {{ event.title }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #desc>
|
||||||
|
<span
|
||||||
|
class="text-app-black/50 text-16px hidden"
|
||||||
|
lg="block"
|
||||||
|
>{{ formatDate(event.time) }}
|
||||||
|
</span>
|
||||||
|
<NuxtLink
|
||||||
|
:to="event.link"
|
||||||
|
hover:text-app-black
|
||||||
|
class="text-app-black/50 text-16px hidden"
|
||||||
|
lg="block"
|
||||||
|
>Link
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItem>
|
||||||
|
<ProjectCreateComponentsItemAdd
|
||||||
|
button-label="ADD EVENT"
|
||||||
|
@add="addEvent()"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newEvent.title"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Event title"
|
||||||
|
placeholder="Enter title of event"
|
||||||
|
hint="Specific name of events (or what happened)"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newEvent.description"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Event description"
|
||||||
|
placeholder="Describe this event"
|
||||||
|
hint="Detailed description of event (max. 1000 glyphs)"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newEvent.link"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Event URL"
|
||||||
|
placeholder="Enter URL with event details"
|
||||||
|
hint="Link to Article, PR or other sources confirming event information"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsDatePicker
|
||||||
|
v-model:day="day"
|
||||||
|
v-model:month="month"
|
||||||
|
v-model:year="year"
|
||||||
|
label="Date of event"
|
||||||
|
placeholder="When this event happened?"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItemAdd>
|
||||||
|
</div>
|
||||||
|
</template>
|
159
components/Project/Create/Categories/Links.vue
Normal file
159
components/Project/Create/Categories/Links.vue
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const web = ref<string>(props.project?.links?.web || '')
|
||||||
|
const blog = ref<string>(props.project?.links?.blog || '')
|
||||||
|
const github = ref<string>(props.project?.links?.github || '')
|
||||||
|
const forum = ref<string>(props.project?.links?.forum || '')
|
||||||
|
const docs = ref<string>(props.project?.links?.docs || '')
|
||||||
|
const whitepaper = ref<string>(props.project?.links?.whitepaper || '')
|
||||||
|
const block_explorer = ref<string>(props.project?.links?.block_explorer || '')
|
||||||
|
const governance = ref<string>(props.project?.links?.governance || '')
|
||||||
|
const twitter = ref<string>(props.project?.links?.twitter || '')
|
||||||
|
const discord = ref<string>(props.project?.links?.discord || '')
|
||||||
|
const telegram = ref<string>(props.project?.links?.telegram || '')
|
||||||
|
const lens = ref<string>(props.project?.links?.lens || '')
|
||||||
|
const farcaster = ref<string>(props.project?.links?.farcaster || '')
|
||||||
|
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
links: {
|
||||||
|
web: web.value,
|
||||||
|
blog: blog.value,
|
||||||
|
github: github.value,
|
||||||
|
forum: forum.value,
|
||||||
|
docs: docs.value,
|
||||||
|
whitepaper: whitepaper.value,
|
||||||
|
block_explorer: block_explorer.value,
|
||||||
|
governance: governance.value,
|
||||||
|
twitter: twitter.value,
|
||||||
|
discord: discord.value,
|
||||||
|
telegram: telegram.value,
|
||||||
|
lens: lens.value,
|
||||||
|
farcaster: farcaster.value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div mt-24px>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="grid grid-cols-2 gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="web"
|
||||||
|
w-full
|
||||||
|
label="Website"
|
||||||
|
placeholder="ex. https://www.yourproject.com"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="blog"
|
||||||
|
w-full
|
||||||
|
label="Blog"
|
||||||
|
placeholder="https://blog,yourproject.com"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="github"
|
||||||
|
w-full
|
||||||
|
label="Github repository"
|
||||||
|
placeholder="Github.com/Yourproject"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="forum"
|
||||||
|
w-full
|
||||||
|
label="Forum"
|
||||||
|
placeholder="https://forum,yourproject.com"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="TECHNOGY DETAILS"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="grid grid-cols-2 gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="docs"
|
||||||
|
w-full
|
||||||
|
label="Documentation"
|
||||||
|
placeholder="https://docs.yourproject.com"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="whitepaper"
|
||||||
|
w-full
|
||||||
|
label="Whitepaper"
|
||||||
|
placeholder="https://www.yourproject.com/whitepaper.pdf"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="block_explorer"
|
||||||
|
w-full
|
||||||
|
label="Explorer"
|
||||||
|
placeholder="https://explorer.yourproject.com"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="governance"
|
||||||
|
w-full
|
||||||
|
label="Governance"
|
||||||
|
placeholder="https://governance.yourproject.com"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="SOCIAL NETWORKS"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="grid grid-cols-2 gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="twitter"
|
||||||
|
w-full
|
||||||
|
label="Twitter"
|
||||||
|
placeholder="Twitter profile URL"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="discord"
|
||||||
|
w-full
|
||||||
|
label="Discord"
|
||||||
|
placeholder="Discord invite link"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="telegram"
|
||||||
|
w-full
|
||||||
|
label="Telegram"
|
||||||
|
placeholder="Telegram channel URL"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="lens"
|
||||||
|
w-full
|
||||||
|
label="Lens"
|
||||||
|
placeholder="Lens profile URL"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="farcaster"
|
||||||
|
w-full
|
||||||
|
label="Farcaster"
|
||||||
|
placeholder="Farcaster profile URL"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
104
components/Project/Create/Categories/Privacy.vue
Normal file
104
components/Project/Create/Categories/Privacy.vue
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const privacyPolicyUrl = ref(props.project?.privacy_policy?.link || '')
|
||||||
|
const compliance = ref(props.project?.compliance || '')
|
||||||
|
const kyc = ref(props.project?.tracebility?.kyc || false)
|
||||||
|
const defaultPrivacy = ref(props.project?.default_privacy || false)
|
||||||
|
const signRequirements = ref(Array.isArray(props.project?.tracebility?.sign_in_type_requirments) ? props.project?.tracebility?.sign_in_type_requirments?.map(s => s.toLowerCase()) : [])
|
||||||
|
const trackedData = ref(props.project?.tracebility?.tracked_data || '')
|
||||||
|
const dataUsage = ref(props.project?.privacy_policy?.data_usage || '')
|
||||||
|
|
||||||
|
const { signInRequirments: signInRequirmentsData } = useData()
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
privacy_policy: {
|
||||||
|
defined: privacyPolicyUrl.value ? true : false,
|
||||||
|
link: privacyPolicyUrl.value,
|
||||||
|
data_usage: dataUsage.value,
|
||||||
|
},
|
||||||
|
compliance: compliance.value,
|
||||||
|
tracebility: {
|
||||||
|
kyc: kyc.value,
|
||||||
|
tracked_data: trackedData.value,
|
||||||
|
},
|
||||||
|
default_privacy: defaultPrivacy.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div mt-24px>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="privacyPolicyUrl"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Link to project’s Privacy Policy"
|
||||||
|
placeholder="https://policy.yourproject.com"
|
||||||
|
hint="URL of document defining you privacy policy and data usage"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="compliance"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Compliance"
|
||||||
|
placeholder="Enter compliance that project follow"
|
||||||
|
hint="Is project Compliant with regulations? (ex. OFAC, Privacy Act)"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="kyc"
|
||||||
|
label="KYC (Know your customer)"
|
||||||
|
hint="Is project requiering KYC for its users?"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="defaultPrivacy"
|
||||||
|
label="Defult privacy"
|
||||||
|
hint="Is maximum privacy turned on by default,"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="ADDITIONAL INFO"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsSelectChips
|
||||||
|
v-model="signRequirements"
|
||||||
|
label="Sign-in requirements"
|
||||||
|
:options="signInRequirmentsData.map(s => ({ label: s.name, value: s.id }))"
|
||||||
|
placeholder="Add requirement"
|
||||||
|
hint="What do you need to provide to use your project?"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="trackedData"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Tracked data"
|
||||||
|
placeholder="Enter tracked data"
|
||||||
|
hint="What data does project collect? (ex. IP, Location, E-mail, Wallet,...)"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="dataUsage"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Data usage"
|
||||||
|
placeholder="What are you using data for?"
|
||||||
|
hint="How does project use user info (resseling, information gathering, none,...)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
198
components/Project/Create/Categories/Security.vue
Normal file
198
components/Project/Create/Categories/Security.vue
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
type Audit = {
|
||||||
|
name: string
|
||||||
|
url: string
|
||||||
|
time: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function useAudits(project?: Partial<Project>) {
|
||||||
|
const audits = ref<Audit[]>(project?.audits as Audit[] || [])
|
||||||
|
const newAudit = reactive<Audit>({
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
time: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const day = ref<number>()
|
||||||
|
const month = ref<number>()
|
||||||
|
const year = ref<number>()
|
||||||
|
|
||||||
|
function addAudit() {
|
||||||
|
audits.value.push({ ...newAudit })
|
||||||
|
newAudit.name = ''
|
||||||
|
newAudit.url = ''
|
||||||
|
newAudit.time = ''
|
||||||
|
day.value = undefined
|
||||||
|
month.value = undefined
|
||||||
|
year.value = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeAudit(index: number) {
|
||||||
|
audits.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
audits,
|
||||||
|
newAudit,
|
||||||
|
day,
|
||||||
|
month,
|
||||||
|
year,
|
||||||
|
addAudit,
|
||||||
|
removeAudit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { audits, newAudit, addAudit, removeAudit, day, month, year } = useAudits(props.project)
|
||||||
|
|
||||||
|
watch([day, month, year], () => {
|
||||||
|
const yearValue = year.value
|
||||||
|
const monthValue = month.value
|
||||||
|
const dayValue = day.value
|
||||||
|
|
||||||
|
if (!yearValue || !monthValue || !dayValue) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
newAudit.time = new Date(yearValue, monthValue - 1, dayValue).toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
function formatDate(date: string) {
|
||||||
|
const d = new Date(date)
|
||||||
|
const day = String(d.getDate()).padStart(2, '0')
|
||||||
|
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||||
|
const year = d.getFullYear()
|
||||||
|
return `${day}/${month}/${year}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const thirdPartyDep = ref(props.project?.third_party_dependency || '')
|
||||||
|
const socialTrust = ref(props.project?.social_trust || '')
|
||||||
|
const spof = ref(props.project?.technical_spof || '')
|
||||||
|
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
audits: audits.value,
|
||||||
|
third_party_dependency: thirdPartyDep.value,
|
||||||
|
social_trust: socialTrust.value,
|
||||||
|
technical_spof: spof.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="AUDITS"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsItem
|
||||||
|
v-for="audit in audits"
|
||||||
|
:key="audit.name"
|
||||||
|
@remove="() => removeAudit(audits.indexOf(audit))"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
gap-2px
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-app-black text-14px font-700"
|
||||||
|
lg="text-16px"
|
||||||
|
> {{ audit.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #desc>
|
||||||
|
<span
|
||||||
|
class="text-app-black/50 text-16px hidden"
|
||||||
|
lg="block"
|
||||||
|
>{{ formatDate(audit.time) }}
|
||||||
|
</span>
|
||||||
|
<NuxtLink
|
||||||
|
target="_blank"
|
||||||
|
:to="audit.url"
|
||||||
|
hover:text-app-black
|
||||||
|
class="text-app-black/50 text-16px hidden"
|
||||||
|
lg="block"
|
||||||
|
>Link
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItem>
|
||||||
|
<ProjectCreateComponentsItemAdd
|
||||||
|
button-label="ADD AUDIT"
|
||||||
|
@add="addAudit()"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newAudit.name"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Audit name"
|
||||||
|
placeholder="Audit name"
|
||||||
|
hint="Title and Name of audit company"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newAudit.url"
|
||||||
|
lg="w-50%"
|
||||||
|
label="URL of audit"
|
||||||
|
placeholder="URL of audit"
|
||||||
|
hint="Enter URL of audit"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsDatePicker
|
||||||
|
v-model:day="day"
|
||||||
|
v-model:month="month"
|
||||||
|
v-model:year="year"
|
||||||
|
label="Date of audit"
|
||||||
|
placeholder="When has been project audited?"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItemAdd>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="ADDITIONAL INFO"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="thirdPartyDep"
|
||||||
|
textarea
|
||||||
|
:textarea-rows="3"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Third party dependency"
|
||||||
|
placeholder="Write about dependencies"
|
||||||
|
hint="Is your project dependend on third service like Uniswap pools, Network or third party contract, Chainlink oracle,...?"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="socialTrust"
|
||||||
|
textarea
|
||||||
|
:textarea-rows="3"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Social trust"
|
||||||
|
placeholder="Who does project trust with treasury and security?"
|
||||||
|
hint="Who is governing project and how? DAO, Multisig wallet of X,"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="spof"
|
||||||
|
textarea
|
||||||
|
:textarea-rows="3"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Single point of failure"
|
||||||
|
placeholder="What is single point of failture for project"
|
||||||
|
hint="What have to happen to shutdown, hack project or leak data? ex. Hack of SHA256, Stolen admin keys,..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
126
components/Project/Create/Categories/Team.vue
Normal file
126
components/Project/Create/Categories/Team.vue
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const isAnonymousTeam = ref<boolean>(props.project?.team?.anonymous || false)
|
||||||
|
|
||||||
|
type Member = {
|
||||||
|
name: string
|
||||||
|
link: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function useMembers(project?: Partial<Project>) {
|
||||||
|
const members = ref<Member[]>(project?.team?.teammembers as Member[] || [])
|
||||||
|
const newMember = reactive<Member>({
|
||||||
|
name: '',
|
||||||
|
link: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
function addMember() {
|
||||||
|
members.value.push({ ...newMember })
|
||||||
|
newMember.name = ''
|
||||||
|
newMember.link = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeMember(index: number) {
|
||||||
|
members.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
members,
|
||||||
|
newMember,
|
||||||
|
addMember,
|
||||||
|
removeMember,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { members, newMember, addMember, removeMember } = useMembers(props.project)
|
||||||
|
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
team: {
|
||||||
|
anonymous: isAnonymousTeam.value,
|
||||||
|
teammembers: members.value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div mt-24px>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="isAnonymousTeam"
|
||||||
|
label="Anonymous team"
|
||||||
|
hint="Are developers able to upgrade and change deployed contract?"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="TEAM MEMBERS"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsItem
|
||||||
|
v-for="member in members"
|
||||||
|
:key="member.name"
|
||||||
|
@remove="() => removeMember(members.indexOf(member))"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
gap-2px
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-app-black text-14px font-700"
|
||||||
|
lg="text-16px"
|
||||||
|
> {{ member.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #desc>
|
||||||
|
<NuxtLink
|
||||||
|
target="_blank"
|
||||||
|
:to="member.link"
|
||||||
|
hover:text-app-black
|
||||||
|
class="text-app-black/50 text-16px hidden"
|
||||||
|
lg="block"
|
||||||
|
>Link
|
||||||
|
</NuxtLink>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItem>
|
||||||
|
<ProjectCreateComponentsItemAdd
|
||||||
|
button-label="ADD MEMBER"
|
||||||
|
@add="addMember()"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
lg="gap-24px"
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newMember.name"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Team member name"
|
||||||
|
placeholder="Enter member name"
|
||||||
|
hint="Full member's name"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="newMember.link"
|
||||||
|
lg="w-50%"
|
||||||
|
label="Profile URL"
|
||||||
|
placeholder="Linkedin, Farcaster, Twitter,..."
|
||||||
|
hint="Link to member’s social profile (ex. Twitter, Linkedin, Lens,...)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ProjectCreateComponentsItemAdd>
|
||||||
|
</div>
|
||||||
|
</template>
|
107
components/Project/Create/Categories/Technology.vue
Normal file
107
components/Project/Create/Categories/Technology.vue
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project?: Partial<Project>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const version = ref(props.project?.project_phase?.toLowerCase() || undefined)
|
||||||
|
const openSource = ref(props.project?.blockchain_features?.opensource || false)
|
||||||
|
const upgradability = ref(props.project?.blockchain_features?.upgradability?.enabled || false)
|
||||||
|
const assetType = ref(props.project?.blockchain_features?.asset_custody_type?.toLowerCase() || '')
|
||||||
|
const encryption = ref(props.project?.blockchain_features?.encryption || '')
|
||||||
|
const peerToPeer = ref(props.project?.blockchain_features?.p2p)
|
||||||
|
const decentralizedStorage = ref(props.project?.storage?.decentralized)
|
||||||
|
|
||||||
|
const { projectPhase: projectPhaseData, assetCustody: assetCustodyData } = useData()
|
||||||
|
const { saveProject } = useProject()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
project_phase: version.value,
|
||||||
|
blockchain_features: {
|
||||||
|
opensource: openSource.value,
|
||||||
|
upgradability: {
|
||||||
|
enabled: upgradability.value,
|
||||||
|
},
|
||||||
|
asset_custody_type: assetType.value,
|
||||||
|
encryption: encryption.value,
|
||||||
|
p2p: peerToPeer.value,
|
||||||
|
},
|
||||||
|
storage: {
|
||||||
|
decentralized: decentralizedStorage.value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
save,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="VERSION"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsRadio
|
||||||
|
v-model="version"
|
||||||
|
:options="projectPhaseData.map(p => ({ label: p.name, value: p.id }))"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="FEATURES"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="openSource"
|
||||||
|
label="Open source"
|
||||||
|
hint="Check when projects source code is openly available and editable"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="upgradability"
|
||||||
|
label="Upgradability"
|
||||||
|
hint="Are developers able to upgrade and change deployed contract?"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ProjectCreateComponentsSelect
|
||||||
|
v-model="assetType"
|
||||||
|
:options="assetCustodyData.map(c => ({ label: c.name, value: c.id }))"
|
||||||
|
label="Asset custody type"
|
||||||
|
placeholder="Select custody type"
|
||||||
|
hint="How are user’s fund handled? (non-custody, multisig, pool,...)"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsCategoryDivider
|
||||||
|
w-full
|
||||||
|
title="ADDITIONAL INFO"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
>
|
||||||
|
<ProjectCreateComponentsInput
|
||||||
|
v-model="encryption"
|
||||||
|
lg="w-1/2"
|
||||||
|
label="Technology type / Encryption"
|
||||||
|
hint="Define technologies your project uses for privacy ex. Zero-Knowledge (ZK), SHA256,"
|
||||||
|
placeholder="Technology name"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="peerToPeer"
|
||||||
|
label="Peer to Peer (P2P)"
|
||||||
|
hint="Check when you transfer / communicate withou intermediaries"
|
||||||
|
/>
|
||||||
|
<ProjectCreateComponentsToggle
|
||||||
|
v-model="decentralizedStorage"
|
||||||
|
label="Decentralized storage"
|
||||||
|
hint="Is your data hosted on IPFS, Filecoin or other decentralized storage?"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
38
components/Project/Create/Components/CategoryDivider.vue
Normal file
38
components/Project/Create/Components/CategoryDivider.vue
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
title: string
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
w-full
|
||||||
|
flex
|
||||||
|
justify-between
|
||||||
|
gap-8px
|
||||||
|
my-40px
|
||||||
|
lg="gap-32px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
gap-8px
|
||||||
|
text-16px
|
||||||
|
font-700
|
||||||
|
class="text-app-white/50"
|
||||||
|
>
|
||||||
|
<span text-nowrap>{{ title }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
w-full
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
>
|
||||||
|
<hr
|
||||||
|
border="t-2px white/50"
|
||||||
|
w-full
|
||||||
|
shrink-1
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
119
components/Project/Create/Components/DatePicker.vue
Normal file
119
components/Project/Create/Components/DatePicker.vue
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
export interface SelectProps {
|
||||||
|
label?: string
|
||||||
|
hint?: string
|
||||||
|
placeholder?: string
|
||||||
|
required?: boolean
|
||||||
|
modelValue?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<SelectProps>()
|
||||||
|
|
||||||
|
const months = [
|
||||||
|
{ label: 'January', value: 1 },
|
||||||
|
{ label: 'February', value: 2 },
|
||||||
|
{ label: 'March', value: 3 },
|
||||||
|
{ label: 'April', value: 4 },
|
||||||
|
{ label: 'May', value: 5 },
|
||||||
|
{ label: 'June', value: 6 },
|
||||||
|
{ label: 'July', value: 7 },
|
||||||
|
{ label: 'August', value: 8 },
|
||||||
|
{ label: 'September', value: 9 },
|
||||||
|
{ label: 'October', value: 10 },
|
||||||
|
{ label: 'November', value: 11 },
|
||||||
|
{ label: 'December', value: 12 },
|
||||||
|
]
|
||||||
|
const years = Array.from({ length: 101 }, (_, i) => new Date().getFullYear() - i)
|
||||||
|
|
||||||
|
const day = defineModel<number>('day')
|
||||||
|
const month = defineModel<number>('month')
|
||||||
|
const year = defineModel<number>('year')
|
||||||
|
|
||||||
|
const daysInMonth = (month: number, year: number) => {
|
||||||
|
const monthObj = months.find(m => m.value === month)
|
||||||
|
if (!monthObj) {
|
||||||
|
throw new Error(`Invalid month value: ${month}`)
|
||||||
|
}
|
||||||
|
const monthIndex = months.indexOf(monthObj)
|
||||||
|
return new Date(year, monthIndex + 1, 0).getDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
const days = computed(() => {
|
||||||
|
if (month.value && year.value) {
|
||||||
|
return Array.from({ length: daysInMonth(month.value, year.value) }, (_, i) => i + 1)
|
||||||
|
}
|
||||||
|
return Array.from({ length: 31 }, (_, i) => i + 1)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
v-if="label"
|
||||||
|
font-400
|
||||||
|
text-14px
|
||||||
|
lg:text-16px
|
||||||
|
text-app-white
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
<span
|
||||||
|
v-if="required"
|
||||||
|
text-app-danger
|
||||||
|
text-16px
|
||||||
|
>*</span>
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
class="flex flex-col"
|
||||||
|
gap-8px
|
||||||
|
lg="flex flex-row gap-24px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-row"
|
||||||
|
lg="w-1/2"
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<SelectBox
|
||||||
|
v-model="day"
|
||||||
|
w-full
|
||||||
|
:options="days.map(day => ({ label: day.toString(), value: day }))"
|
||||||
|
placeholder="Day"
|
||||||
|
:border-opacity="30"
|
||||||
|
:is-margin-top="false"
|
||||||
|
/>
|
||||||
|
<SelectBox
|
||||||
|
v-model="month"
|
||||||
|
w-full
|
||||||
|
mx--2px
|
||||||
|
:options="months.map(month => ({ label: month.label, value: month.value }))"
|
||||||
|
placeholder="Month"
|
||||||
|
:border-opacity="30"
|
||||||
|
:is-margin-top="false"
|
||||||
|
/>
|
||||||
|
<SelectBox
|
||||||
|
v-model="year"
|
||||||
|
w-full
|
||||||
|
:options="years.map(year => ({ label: year.toString(), value: year }))"
|
||||||
|
placeholder="Year"
|
||||||
|
:border-opacity="30"
|
||||||
|
:is-margin-top="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
v-if="hint"
|
||||||
|
lg="left-1/2 self-center"
|
||||||
|
font-400
|
||||||
|
italic
|
||||||
|
lg:text-14px
|
||||||
|
text-12px
|
||||||
|
text-app-white
|
||||||
|
opacity-50
|
||||||
|
>
|
||||||
|
{{ hint }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
81
components/Project/Create/Components/Input.vue
Normal file
81
components/Project/Create/Components/Input.vue
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
export interface SelectProps {
|
||||||
|
label?: string
|
||||||
|
hint?: string
|
||||||
|
placeholder?: string
|
||||||
|
required?: boolean
|
||||||
|
modelValue?: any
|
||||||
|
textarea?: boolean
|
||||||
|
textareaRows?: number
|
||||||
|
lgWidth?: string
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<SelectProps>()
|
||||||
|
|
||||||
|
const model = defineModel<string>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="w-full!"
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
v-if="label"
|
||||||
|
font-400
|
||||||
|
text-14px
|
||||||
|
lg:text-16px
|
||||||
|
text-app-white
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
<span
|
||||||
|
v-if="required"
|
||||||
|
text-app-danger
|
||||||
|
text-16px
|
||||||
|
>*</span>
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
w-full
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
lg="flex flex-row gap-24px"
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<div v-bind="$attrs">
|
||||||
|
<textarea
|
||||||
|
v-if="textarea"
|
||||||
|
v-model="model"
|
||||||
|
:rows="textareaRows"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
class="relative w-full p-8px text-left border-2px text-app-white bg-black sm:text-sm sm:leading-6 focus:ring-0 focus:outline-none"
|
||||||
|
:class="error ? 'border-app-danger/50' : 'border-white/30'"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
v-else
|
||||||
|
v-model="model"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
type="text"
|
||||||
|
class="relative w-full p-8px text-left border-2px text-app-white bg-black sm:text-sm sm:leading-6 focus:ring-0 focus:outline-none"
|
||||||
|
:class="error ? 'border-app-danger/50' : 'border-white/30'"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
v-if="hint"
|
||||||
|
lg="left-1/2 self-center"
|
||||||
|
v-bind="$attrs"
|
||||||
|
font-400
|
||||||
|
italic
|
||||||
|
lg:text-14px
|
||||||
|
text-12px
|
||||||
|
text-app-white
|
||||||
|
opacity-50
|
||||||
|
>
|
||||||
|
{{ hint }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
33
components/Project/Create/Components/Item.vue
Normal file
33
components/Project/Create/Components/Item.vue
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const emits = defineEmits(['remove'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
justify-between
|
||||||
|
items-center
|
||||||
|
py-12px
|
||||||
|
px-16px
|
||||||
|
bg-app-white
|
||||||
|
>
|
||||||
|
<slot name="label" />
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
gap-16px
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
class="text-app-black/50"
|
||||||
|
name="desc"
|
||||||
|
/>
|
||||||
|
<button @click="emits('remove')">
|
||||||
|
<UnoIcon
|
||||||
|
i-heroicons-solid-x
|
||||||
|
text-12px
|
||||||
|
text-app-black
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
31
components/Project/Create/Components/ItemAdd.vue
Normal file
31
components/Project/Create/Components/ItemAdd.vue
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
buttonLabel: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emits = defineEmits(['add'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
w-full
|
||||||
|
border-2
|
||||||
|
border-app-white
|
||||||
|
p-24px
|
||||||
|
>
|
||||||
|
<slot name="content" />
|
||||||
|
<Button
|
||||||
|
mt-16px
|
||||||
|
lg="w-fit mt-24px"
|
||||||
|
border
|
||||||
|
inverted-color
|
||||||
|
@click="emits('add')"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
px-24px
|
||||||
|
>{{ buttonLabel }}</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</template>
|
61
components/Project/Create/Components/Radio.vue
Normal file
61
components/Project/Create/Components/Radio.vue
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface OptionItem<T> {
|
||||||
|
label: string
|
||||||
|
value: T
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SelectProps {
|
||||||
|
options: OptionItem<string>[]
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<SelectProps>()
|
||||||
|
|
||||||
|
const selected = defineModel<string>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div w-full>
|
||||||
|
<div w-full>
|
||||||
|
<HeadlessRadioGroup v-model="selected">
|
||||||
|
<div class="flex flex-wrap gap-20px">
|
||||||
|
<HeadlessRadioGroupOption
|
||||||
|
v-for="option in options"
|
||||||
|
:key="option.label"
|
||||||
|
v-slot="{ checked }"
|
||||||
|
as="template"
|
||||||
|
:value="option.value"
|
||||||
|
>
|
||||||
|
<div class="cursor-pointer w-49% flex items-center gap-22px">
|
||||||
|
<div
|
||||||
|
rounded-full
|
||||||
|
p-6px
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
justify-centerě
|
||||||
|
:class="checked ? 'bg-app-white text-app-black' : 'outline outline-2px outline-offset--2 outline-app-white text-app-white'"
|
||||||
|
>
|
||||||
|
<UnoIcon
|
||||||
|
v-if="checked"
|
||||||
|
i-heroicons-solid-check
|
||||||
|
text-20px
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
w-20px
|
||||||
|
h-20px
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<HeadlessRadioGroupLabel
|
||||||
|
as="p"
|
||||||
|
:class="checked ? 'text-app-white' : 'text-app-white/50'"
|
||||||
|
class="font-medium"
|
||||||
|
>
|
||||||
|
{{ option.label }}
|
||||||
|
</HeadlessRadioGroupLabel>
|
||||||
|
</div>
|
||||||
|
</HeadlessRadioGroupOption>
|
||||||
|
</div>
|
||||||
|
</HeadlessRadioGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
107
components/Project/Create/Components/Select.vue
Normal file
107
components/Project/Create/Components/Select.vue
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { InputOption } from '~/types'
|
||||||
|
|
||||||
|
const props = defineProps<SelectProps>()
|
||||||
|
const emits = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
interface SelectProps {
|
||||||
|
options: InputOption[]
|
||||||
|
label?: string
|
||||||
|
modelValue: string
|
||||||
|
placeholder?: string
|
||||||
|
required?: boolean
|
||||||
|
hint?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedValue = useVModel(props, 'modelValue', emits)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
lg="flex flex-row gap-24px"
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<div lg="w-1/2">
|
||||||
|
<HeadlessListbox
|
||||||
|
v-model="selectedValue"
|
||||||
|
as="div"
|
||||||
|
>
|
||||||
|
<HeadlessListboxLabel
|
||||||
|
v-if="label"
|
||||||
|
font-400
|
||||||
|
text-14px
|
||||||
|
lg:text-16px
|
||||||
|
text-app-white
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
<span
|
||||||
|
v-if="required"
|
||||||
|
text-app-danger
|
||||||
|
text-16px
|
||||||
|
>*</span>
|
||||||
|
</HeadlessListboxLabel>
|
||||||
|
<div
|
||||||
|
class="relative font-700 mt-2 bg-app-black"
|
||||||
|
>
|
||||||
|
<HeadlessListboxButton
|
||||||
|
as="div"
|
||||||
|
class="relative w-full cursor-pointer p-8px text-left border-2px text-app-white bg-black border-white/30 sm:text-sm sm:leading-6"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="block truncate mr-8px"
|
||||||
|
:class="[selectedValue ? 'text-app-white' : 'font-400 text-white/50']"
|
||||||
|
>
|
||||||
|
{{ props.options.find(option => option.value === selectedValue)?.label || props.placeholder }}
|
||||||
|
</span>
|
||||||
|
<span class="absolute inset-y-0 right-0 flex items-center pr-2">
|
||||||
|
<UnoIcon
|
||||||
|
i-heroicons-solid-chevron-down
|
||||||
|
class="text-app-white"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</HeadlessListboxButton>
|
||||||
|
|
||||||
|
<transition
|
||||||
|
leave-active-class="transition ease-in duration-100"
|
||||||
|
leave-from-class="opacity-100"
|
||||||
|
leave-to-class="opacity-0"
|
||||||
|
>
|
||||||
|
<HeadlessListboxOptions
|
||||||
|
class="absolute z-100 max-h-60 w-full divide-y-2px border-2px border-t-0 overflow-auto bg-app-black text-app-white focus:outline-none sm:text-sm border-white/30"
|
||||||
|
>
|
||||||
|
<HeadlessListboxOption
|
||||||
|
v-for="option in props.options"
|
||||||
|
:key="option.value"
|
||||||
|
v-slot="{ selected }"
|
||||||
|
as="template"
|
||||||
|
:value="option.value"
|
||||||
|
class="w-full relative cursor-pointer select-none py-8px p-16px border-white/30"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="block truncate"
|
||||||
|
:class="[selected ? 'font-semibold' : 'font-normal']"
|
||||||
|
>{{ option.label }}</span>
|
||||||
|
</HeadlessListboxOption>
|
||||||
|
</HeadlessListboxOptions>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</HeadlessListbox>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
v-if="hint"
|
||||||
|
lg="mt-28px left-1/2 self-center"
|
||||||
|
font-400
|
||||||
|
italic
|
||||||
|
lg:text-14px
|
||||||
|
text-12px
|
||||||
|
text-app-white
|
||||||
|
opacity-50
|
||||||
|
>
|
||||||
|
{{ hint }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
213
components/Project/Create/Components/SelectChips.vue
Normal file
213
components/Project/Create/Components/SelectChips.vue
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface OptionItem<T> {
|
||||||
|
label: string
|
||||||
|
value: T
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SelectProps {
|
||||||
|
options: OptionItem<any>[]
|
||||||
|
label?: string
|
||||||
|
hint?: string
|
||||||
|
placeholder?: string
|
||||||
|
required?: boolean
|
||||||
|
multiple?: boolean
|
||||||
|
canAddNew?: boolean
|
||||||
|
modelValue?: any
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<SelectProps>(), {
|
||||||
|
multiple: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const modelValue = useVModel(props, 'modelValue', emits)
|
||||||
|
|
||||||
|
const query = ref('')
|
||||||
|
const newOptions = ref<OptionItem<any>[]>([])
|
||||||
|
|
||||||
|
const options = computed(() => {
|
||||||
|
return [...props.options, ...newOptions.value]
|
||||||
|
})
|
||||||
|
|
||||||
|
const filteredOptions = computed(() =>
|
||||||
|
query.value === ''
|
||||||
|
? options.value
|
||||||
|
: options.value.filter(o => o.label.toLowerCase().includes(query.value.toLowerCase())),
|
||||||
|
)
|
||||||
|
|
||||||
|
// const modelValue = ref(props.modelValue || (props.multiple ? [] : null))
|
||||||
|
|
||||||
|
const selectedOptions = computed(() => props.multiple ? options.value.filter(o => modelValue.value?.includes(o.value)) : [])
|
||||||
|
|
||||||
|
function deleteOption(value: string) {
|
||||||
|
const index = modelValue.value.indexOf(value)
|
||||||
|
if (index !== -1)
|
||||||
|
modelValue.value.splice(index, 1)
|
||||||
|
|
||||||
|
newOptions.value = newOptions.value.filter((o: any) => o.value !== value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addOption() {
|
||||||
|
if (query.value === '' || !props.canAddNew) return
|
||||||
|
|
||||||
|
if (!options.value.some(o => o.value === query.value)) {
|
||||||
|
newOptions.value.push({ label: query.value, value: query.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.multiple) {
|
||||||
|
if (!modelValue.value) modelValue.value = []
|
||||||
|
modelValue.value.push(query.value)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
modelValue.value = query.value
|
||||||
|
}
|
||||||
|
|
||||||
|
query.value = ''
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
lg="flex flex-row gap-24px"
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<div lg="w-1/2">
|
||||||
|
<HeadlessCombobox
|
||||||
|
v-model="modelValue"
|
||||||
|
:multiple="props.multiple"
|
||||||
|
>
|
||||||
|
<HeadlessComboboxLabel
|
||||||
|
v-if="label"
|
||||||
|
font-400
|
||||||
|
text-14px
|
||||||
|
lg:text-16px
|
||||||
|
text-app-white
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
<span
|
||||||
|
v-if="required"
|
||||||
|
text-app-danger
|
||||||
|
text-16px
|
||||||
|
>*</span>
|
||||||
|
</HeadlessComboboxLabel>
|
||||||
|
<div class="relative font-700 mt-2 bg-app-black">
|
||||||
|
<HeadlessComboboxButton
|
||||||
|
as="div"
|
||||||
|
class="relative w-full cursor-pointer p-8px text-left border-2px text-app-white bg-black sm:text-sm sm:leading-6"
|
||||||
|
:class="error ? 'border-app-danger/50' : 'border-white/30'"
|
||||||
|
>
|
||||||
|
<div class="flex flex-wrap gap-8px">
|
||||||
|
<span
|
||||||
|
v-for="option in selectedOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="font-700 text-14px leading-20px flex gap-8px items-center bg-app-white text-black px-8px py-4px"
|
||||||
|
lg="text-16px"
|
||||||
|
>
|
||||||
|
{{ option.label }}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="ml-1 text-black"
|
||||||
|
@click.stop="deleteOption(option.value)"
|
||||||
|
>
|
||||||
|
<UnoIcon
|
||||||
|
i-heroicons-solid-x
|
||||||
|
text-16px
|
||||||
|
text-black
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<HeadlessComboboxInput
|
||||||
|
class="text-14px font-400 leading-20px ml-8px w-fit bg-transparent border-none focus:ring-0 focus:outline-none"
|
||||||
|
lg="16px"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
@keyup.enter="addOption"
|
||||||
|
@change="query = $event.target.value"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="absolute inset-y-0 right-0 flex items-center pr-2">
|
||||||
|
<UnoIcon
|
||||||
|
i-heroicons-solid-chevron-down
|
||||||
|
class="text-app-white"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</HeadlessComboboxButton>
|
||||||
|
</div>
|
||||||
|
<Transition
|
||||||
|
leave-active-class="transition ease-in duration-100"
|
||||||
|
leave-from-class="opacity-100"
|
||||||
|
leave-to-class="opacity-0"
|
||||||
|
@after-leave="query = ''"
|
||||||
|
>
|
||||||
|
<HeadlessComboboxOptions
|
||||||
|
lg="w-1/2"
|
||||||
|
class="w-full absolute z-100 max-h-60 divide-y-2px border-2px border-t-0 overflow-auto bg-app-black text-app-white focus:outline-none sm:text-sm border-white/30"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="filteredOptions.length === 0 && query !== '' && props.canAddNew"
|
||||||
|
class="gap-4px flex items-center relative cursor-default select-none px-4 py-2 text-app-white"
|
||||||
|
@click="addOption"
|
||||||
|
>
|
||||||
|
<UnoIcon
|
||||||
|
i-heroicons-solid-plus
|
||||||
|
class="text-app-white"
|
||||||
|
/>
|
||||||
|
<span>Add</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="filteredOptions.length === 0 && query !== '' && !props.canAddNew"
|
||||||
|
class="relative cursor-default select-none px-4 py-2 text-app-white opacity-50"
|
||||||
|
>
|
||||||
|
Nothing found.
|
||||||
|
</div>
|
||||||
|
<HeadlessComboboxOption
|
||||||
|
v-for="option in filteredOptions"
|
||||||
|
:key="option.value"
|
||||||
|
v-slot="{ selected, active }"
|
||||||
|
class="border-white/30"
|
||||||
|
as="template"
|
||||||
|
:value="option.value"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="w-full relative cursor-pointer select-none py-8px p-16px"
|
||||||
|
:class="[active ? 'bg-#ffffff1a' : 'text-white']"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="block truncate"
|
||||||
|
:class="[selected ? 'font-semibold' : 'font-normal']"
|
||||||
|
>{{ option.label }}</span>
|
||||||
|
<span
|
||||||
|
v-if="selected"
|
||||||
|
class="absolute inset-y-0 right-0 flex items-center pr-3 text-white"
|
||||||
|
>
|
||||||
|
<UnoIcon
|
||||||
|
i-heroicons-solid-check
|
||||||
|
text-20px
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</HeadlessComboboxOption>
|
||||||
|
</HeadlessComboboxOptions>
|
||||||
|
</Transition>
|
||||||
|
</HeadlessCombobox>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
v-if="hint"
|
||||||
|
lg="mt-28px left-1/2 self-center"
|
||||||
|
font-400
|
||||||
|
italic
|
||||||
|
lg:text-14px
|
||||||
|
text-12px
|
||||||
|
text-app-white
|
||||||
|
opacity-50
|
||||||
|
>
|
||||||
|
{{ hint }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
81
components/Project/Create/Components/Toggle.vue
Normal file
81
components/Project/Create/Components/Toggle.vue
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
label?: string
|
||||||
|
hint?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const enabled = defineModel<boolean>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
lg="flex flex-row gap-24px"
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
gap-24px
|
||||||
|
lg="w-1/2"
|
||||||
|
>
|
||||||
|
<HeadlessSwitch
|
||||||
|
v-model="enabled"
|
||||||
|
:class="enabled ? 'bg-white/10' : 'bg-white/10'"
|
||||||
|
class="relative inline-flex h-[28px] w-[68px] shrink-0 cursor-pointer transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
:class="enabled ? 'translate-x-9 bg-app-white' : 'translate-x-0 bg-app-black border-2 border-app-white'"
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
class="pointer-events-none inline-block h-[28px] w-[32px] transform shadow-lg ring-0 transition duration-200 ease-in-out"
|
||||||
|
>
|
||||||
|
<UnoIcon
|
||||||
|
v-if="enabled"
|
||||||
|
transition
|
||||||
|
duration-200
|
||||||
|
ease-in-out
|
||||||
|
i-heroicons-solid-check
|
||||||
|
w-full
|
||||||
|
text-20px
|
||||||
|
text-app-black
|
||||||
|
/>
|
||||||
|
<UnoIcon
|
||||||
|
v-else
|
||||||
|
transition
|
||||||
|
duration-200
|
||||||
|
ease-in-out
|
||||||
|
i-heroicons-solid-x
|
||||||
|
w-full
|
||||||
|
text-20px
|
||||||
|
text-app-white
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</HeadlessSwitch>
|
||||||
|
<span
|
||||||
|
v-if="label"
|
||||||
|
text-14px
|
||||||
|
font-400
|
||||||
|
lg="text-16px"
|
||||||
|
:class="enabled ? 'text-app-white' : 'text-app-white/50'"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
v-if="hint"
|
||||||
|
lg="left-1/2 self-center"
|
||||||
|
font-400
|
||||||
|
italic
|
||||||
|
lg:text-14px
|
||||||
|
text-12px
|
||||||
|
text-app-white
|
||||||
|
opacity-50
|
||||||
|
>
|
||||||
|
{{ hint }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -23,11 +23,12 @@ defineProps<{
|
||||||
>
|
>
|
||||||
<div mt-32px>
|
<div mt-32px>
|
||||||
<ProjectActivityLaunch
|
<ProjectActivityLaunch
|
||||||
v-if="project.history"
|
v-for="launch in project.history"
|
||||||
:network="project.history?.title"
|
:key="launch.title"
|
||||||
:date="project.history?.time"
|
:network="launch.title"
|
||||||
:launch-type="project.history?.description"
|
:date="launch.time"
|
||||||
:to="project.history?.link"
|
:launch-type="launch.description"
|
||||||
|
:to="launch.link"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -25,12 +25,12 @@ defineProps<{
|
||||||
gap-y-16px
|
gap-y-16px
|
||||||
lg:grid-cols-4
|
lg:grid-cols-4
|
||||||
>
|
>
|
||||||
<ProjectInfoItem
|
<!-- <ProjectInfoItem
|
||||||
:check-undefined="project.history?.time"
|
:check-undefined="project.history?.time"
|
||||||
title="Date of creation"
|
title="Date of creation"
|
||||||
>
|
>
|
||||||
{{ formatDate(project.history!.time!) }}
|
{{ formatDate(project.history!.time!) }}
|
||||||
</ProjectInfoItem>
|
</ProjectInfoItem> -->
|
||||||
</div>
|
</div>
|
||||||
</ProjectDetailContainer>
|
</ProjectDetailContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,9 +3,9 @@ import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const githubProjectUrl = computed(() => {
|
// const githubProjectUrl = computed(() => {
|
||||||
return `https://github.com/web3privacy/explorer-data/blob/main/src/projects/${route.params.id}/index.yaml`
|
// return `https://github.com/web3privacy/explorer-data/blob/main/src/projects/${route.params.id}/index.yaml`
|
||||||
})
|
// })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -20,7 +20,7 @@ const githubProjectUrl = computed(() => {
|
||||||
>
|
>
|
||||||
<NavigationButton
|
<NavigationButton
|
||||||
w-230px
|
w-230px
|
||||||
@click="$router.back()"
|
@click="$router.push('/')"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
block
|
block
|
||||||
|
@ -39,9 +39,8 @@ const githubProjectUrl = computed(() => {
|
||||||
<EditButton
|
<EditButton
|
||||||
px-16px
|
px-16px
|
||||||
py-8px
|
py-8px
|
||||||
hover:bg-white
|
hover="cursor-pointer bg-white text-black"
|
||||||
hover:text-black
|
@click="$router.push('/project/' + route.params.id + '/edit')"
|
||||||
:to="githubProjectUrl"
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
text-16px
|
text-16px
|
||||||
|
|
|
@ -301,8 +301,8 @@ defineProps<{
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ProjectOpenessTeamMembers
|
<ProjectOpenessTeamMembers
|
||||||
v-if="project?.team"
|
v-if="project?.team?.teammembers"
|
||||||
:members="project.team"
|
:members="project.team?.teammembers"
|
||||||
mt-24px
|
mt-24px
|
||||||
/>
|
/>
|
||||||
<div mt-32px>
|
<div mt-32px>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
members: {
|
members: {
|
||||||
name: string
|
name?: string
|
||||||
role?: string
|
role?: string
|
||||||
link?: string
|
link?: string
|
||||||
}[] | undefined
|
}[] | undefined
|
||||||
|
|
|
@ -39,7 +39,7 @@ defineProps<{
|
||||||
:color="project.blockchain_features?.asset_custody_type === 'non-custody' ? '#18FF2F' : project.blockchain_features?.asset_custody_type === 'multisig' ? '#FFB800' : '#FF0000'"
|
:color="project.blockchain_features?.asset_custody_type === 'non-custody' ? '#18FF2F' : project.blockchain_features?.asset_custody_type === 'multisig' ? '#FFB800' : '#FF0000'"
|
||||||
bold
|
bold
|
||||||
>
|
>
|
||||||
{{ project.blockchain_features?.asset_custody_type.toUpperCase() }}
|
{{ project.blockchain_features?.asset_custody_type?.toUpperCase() }}
|
||||||
</ProjectInfoItem>
|
</ProjectInfoItem>
|
||||||
<ProjectInfoItem
|
<ProjectInfoItem
|
||||||
title="Upgradability"
|
title="Upgradability"
|
||||||
|
|
|
@ -4,14 +4,18 @@ import type { InputOption } from '~/types'
|
||||||
const props = withDefaults(defineProps<SelectProps>(), {
|
const props = withDefaults(defineProps<SelectProps>(), {
|
||||||
isMarginTop: true,
|
isMarginTop: true,
|
||||||
blackAndWhite: true,
|
blackAndWhite: true,
|
||||||
|
borderOpacity: 100,
|
||||||
})
|
})
|
||||||
const emits = defineEmits(['update:modelValue'])
|
const emits = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
interface SelectProps {
|
interface SelectProps {
|
||||||
options: InputOption[]
|
options: InputOption[]
|
||||||
modelValue: string
|
label?: string
|
||||||
|
modelValue: any
|
||||||
isMarginTop?: boolean
|
isMarginTop?: boolean
|
||||||
blackAndWhite?: boolean
|
blackAndWhite?: boolean
|
||||||
|
borderOpacity?: number
|
||||||
|
placeholder?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedValue = useVModel(props, 'modelValue', emits)
|
const selectedValue = useVModel(props, 'modelValue', emits)
|
||||||
|
@ -28,9 +32,14 @@ const selectedValue = useVModel(props, 'modelValue', emits)
|
||||||
>
|
>
|
||||||
<HeadlessListboxButton
|
<HeadlessListboxButton
|
||||||
class="relative w-full cursor-pointer py-8px p-16px text-left border-2px sm:text-sm sm:leading-6"
|
class="relative w-full cursor-pointer py-8px p-16px text-left border-2px sm:text-sm sm:leading-6"
|
||||||
:class="[blackAndWhite ? ' text-app-white' : 'text-app-black']"
|
:class="[blackAndWhite ? 'text-app-white' : 'text-app-black', `border-white/${borderOpacity}`]"
|
||||||
>
|
>
|
||||||
<span class="block truncate mr-8px">{{ props.options.find(option => option.value === selectedValue)?.label }}</span>
|
<span
|
||||||
|
class="block truncate mr-8px"
|
||||||
|
:class="[selectedValue ? 'text-app-white' : 'font-400 text-white/50']"
|
||||||
|
>
|
||||||
|
{{ props.options.find(option => option.value === selectedValue)?.label || props.placeholder }}
|
||||||
|
</span>
|
||||||
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||||
<UnoIcon
|
<UnoIcon
|
||||||
i-ic-baseline-arrow-drop-down
|
i-ic-baseline-arrow-drop-down
|
||||||
|
@ -45,24 +54,22 @@ const selectedValue = useVModel(props, 'modelValue', emits)
|
||||||
leave-to-class="opacity-0"
|
leave-to-class="opacity-0"
|
||||||
>
|
>
|
||||||
<HeadlessListboxOptions
|
<HeadlessListboxOptions
|
||||||
|
:class="`border-white/${borderOpacity}`"
|
||||||
class="absolute z-100 max-h-60 w-full divide-y-2px border-2px border-t-0 overflow-auto bg-app-black text-app-white focus:outline-none sm:text-sm"
|
class="absolute z-100 max-h-60 w-full divide-y-2px border-2px border-t-0 overflow-auto bg-app-black text-app-white focus:outline-none sm:text-sm"
|
||||||
>
|
>
|
||||||
<HeadlessListboxOption
|
<HeadlessListboxOption
|
||||||
v-for="option in props.options"
|
v-for="option in props.options"
|
||||||
:key="option.value"
|
:key="option.value"
|
||||||
v-slot="{ active, selected }"
|
v-slot="{ selected }"
|
||||||
as="template"
|
as="template"
|
||||||
:value="option.value"
|
:value="option.value"
|
||||||
>
|
class="py-8px p-16px cursor-pointer"
|
||||||
<li
|
:class="`border-white/${borderOpacity}`"
|
||||||
class="w-full relative cursor-pointer select-none py-8px p-16px"
|
|
||||||
:class="[active ? 'bg-#ffffff1a' : 'text-white']"
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="block truncate"
|
class="block truncate"
|
||||||
:class="[selected ? 'font-semibold' : 'font-normal']"
|
:class="[selected ? 'font-semibold' : 'font-normal']"
|
||||||
>{{ option.label }}</span>
|
>{{ option.label }}</span>
|
||||||
</li>
|
|
||||||
</HeadlessListboxOption>
|
</HeadlessListboxOption>
|
||||||
</HeadlessListboxOptions>
|
</HeadlessListboxOptions>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { InputOption } from '~/types'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
options: InputOption[]
|
options: InputOption[]
|
||||||
modelValue: string
|
modelValue: string | number
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emits = defineEmits(['update:modelValue'])
|
const emits = defineEmits(['update:modelValue'])
|
||||||
|
|
|
@ -6,6 +6,10 @@ import type { Rank } from '~/types/rank'
|
||||||
import type { Usecase } from '~/types/usecase'
|
import type { Usecase } from '~/types/usecase'
|
||||||
|
|
||||||
export const useData = defineStore('data', () => {
|
export const useData = defineStore('data', () => {
|
||||||
|
const projectPhase = useState<{ id: string, name: string }[]>('projectPhase')
|
||||||
|
const assetCustody = useState<{ id: string, name: string }[]>('assetCustody')
|
||||||
|
const signInRequirments = useState<{ id: string, name: string }[]>('signInRequirmenets')
|
||||||
|
|
||||||
const categories = useState<Category[]>('categories')
|
const categories = useState<Category[]>('categories')
|
||||||
const usecases = useState<Usecase[]>('usecases')
|
const usecases = useState<Usecase[]>('usecases')
|
||||||
const features = useState<Feature[]>('features')
|
const features = useState<Feature[]>('features')
|
||||||
|
@ -47,6 +51,9 @@ export const useData = defineStore('data', () => {
|
||||||
const data = await $fetch<{
|
const data = await $fetch<{
|
||||||
categories: Category[]
|
categories: Category[]
|
||||||
projects: Project[]
|
projects: Project[]
|
||||||
|
project_phase: { id: string, name: string }[]
|
||||||
|
asset_custody_type: { id: string, name: string }[]
|
||||||
|
sign_in_type_requirments: { id: string, name: string }[]
|
||||||
usecases: Usecase[]
|
usecases: Usecase[]
|
||||||
ecosystems: Ecosystem[]
|
ecosystems: Ecosystem[]
|
||||||
assets: Asset[]
|
assets: Asset[]
|
||||||
|
@ -57,17 +64,17 @@ export const useData = defineStore('data', () => {
|
||||||
...project,
|
...project,
|
||||||
ratings: generateProjectRating(project),
|
ratings: generateProjectRating(project),
|
||||||
})).filter(p => p.name)
|
})).filter(p => p.name)
|
||||||
categories.value = data.categories.map((c) => {
|
|
||||||
c.projectsCount = projects.value.filter(p =>
|
categories.value = data.categories
|
||||||
p.categories?.includes(c.id),
|
|
||||||
).length
|
|
||||||
return c
|
|
||||||
}).filter(c => c.projectsCount > 0)
|
|
||||||
usecases.value = data.usecases
|
usecases.value = data.usecases
|
||||||
ecosystems.value = data.ecosystems
|
ecosystems.value = data.ecosystems
|
||||||
assets.value = data.assets
|
assets.value = data.assets
|
||||||
features.value = data.features
|
features.value = data.features
|
||||||
ranks.value = data.ranks
|
ranks.value = data.ranks
|
||||||
|
|
||||||
|
projectPhase.value = data.project_phase.map(p => ({ id: p.id.toLowerCase(), name: p.name }))
|
||||||
|
assetCustody.value = data.asset_custody_type.map(a => ({ id: a.id.toLowerCase(), name: a.name }))
|
||||||
|
signInRequirments.value = data.sign_in_type_requirments.map(s => ({ id: s.id.toLowerCase(), name: s.name }))
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
@ -267,6 +274,9 @@ export const useData = defineStore('data', () => {
|
||||||
filter,
|
filter,
|
||||||
switcher,
|
switcher,
|
||||||
categories,
|
categories,
|
||||||
|
projectPhase,
|
||||||
|
assetCustody,
|
||||||
|
signInRequirments,
|
||||||
usecases,
|
usecases,
|
||||||
features,
|
features,
|
||||||
ecosystems,
|
ecosystems,
|
||||||
|
|
71
composables/useProject.ts
Normal file
71
composables/useProject.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { Buffer } from 'buffer'
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
export const useProject = defineStore('project', () => {
|
||||||
|
const project = ref<Partial<Project>>()
|
||||||
|
const projectImage = ref<File>()
|
||||||
|
const isPublishing = ref(false)
|
||||||
|
|
||||||
|
const { getProjectById } = useData()
|
||||||
|
|
||||||
|
function setProject(id: string) {
|
||||||
|
project.value = getProjectById(id, { shallow: false }) as Project
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearProject() {
|
||||||
|
project.value = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveProject(data: Partial<Project>) {
|
||||||
|
project.value = {
|
||||||
|
...project.value,
|
||||||
|
...data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveProjectImage(image: File) {
|
||||||
|
projectImage.value = image
|
||||||
|
}
|
||||||
|
|
||||||
|
async function publishProject() {
|
||||||
|
isPublishing.value = true
|
||||||
|
try {
|
||||||
|
const imageArrayBuffer = await projectImage.value?.arrayBuffer()
|
||||||
|
let imageBuffer: Buffer | undefined
|
||||||
|
let base64Image: string | undefined
|
||||||
|
|
||||||
|
if (imageArrayBuffer) {
|
||||||
|
imageBuffer = Buffer.from(imageArrayBuffer)
|
||||||
|
const base64String = imageBuffer.toString('base64')
|
||||||
|
base64Image = base64String
|
||||||
|
}
|
||||||
|
|
||||||
|
await $fetch(`/api/data`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: {
|
||||||
|
project: project.value,
|
||||||
|
image: {
|
||||||
|
type: projectImage.value?.type,
|
||||||
|
data: base64Image,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
isPublishing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
project,
|
||||||
|
isPublishing,
|
||||||
|
setProject,
|
||||||
|
clearProject,
|
||||||
|
saveProject,
|
||||||
|
saveProjectImage,
|
||||||
|
publishProject,
|
||||||
|
}
|
||||||
|
})
|
6
layouts/create.vue
Normal file
6
layouts/create.vue
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<template>
|
||||||
|
<div h-full w-full>
|
||||||
|
<Navigation />
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -10,6 +10,7 @@ export default defineNuxtConfig({
|
||||||
'nuxt-lodash',
|
'nuxt-lodash',
|
||||||
'nuxt-headlessui',
|
'nuxt-headlessui',
|
||||||
'@nuxt/image',
|
'@nuxt/image',
|
||||||
|
'@vee-validate/nuxt',
|
||||||
],
|
],
|
||||||
sourcemap: {
|
sourcemap: {
|
||||||
server: true,
|
server: true,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
"@iconify-json/bi": "^1.2.0",
|
"@iconify-json/bi": "^1.2.0",
|
||||||
"@iconify-json/heroicons-outline": "^1.2.0",
|
"@iconify-json/heroicons-outline": "^1.2.0",
|
||||||
"@iconify-json/heroicons-solid": "^1.2.0",
|
"@iconify-json/heroicons-solid": "^1.2.0",
|
||||||
|
"@iconify-json/eos-icons": "^1.1.10",
|
||||||
"@iconify-json/ic": "^1.2.0",
|
"@iconify-json/ic": "^1.2.0",
|
||||||
"@iconify-json/iconoir": "^1.2.0",
|
"@iconify-json/iconoir": "^1.2.0",
|
||||||
"@iconify-json/material-symbols": "^1.2.1",
|
"@iconify-json/material-symbols": "^1.2.1",
|
||||||
|
@ -32,16 +33,20 @@
|
||||||
"@nuxtjs/color-mode": "^3.4.4",
|
"@nuxtjs/color-mode": "^3.4.4",
|
||||||
"@pinia/nuxt": "^0.5.4",
|
"@pinia/nuxt": "^0.5.4",
|
||||||
"@unocss/nuxt": "^0.62.3",
|
"@unocss/nuxt": "^0.62.3",
|
||||||
|
"@vee-validate/nuxt": "^4.13.2",
|
||||||
"@vueuse/nuxt": "^11.0.3",
|
"@vueuse/nuxt": "^11.0.3",
|
||||||
"eslint": "^9.9.1",
|
"eslint": "^9.9.1",
|
||||||
"nuxt": "^3.13.0",
|
"nuxt": "^3.13.0",
|
||||||
"nuxt-headlessui": "^1.2.0",
|
"nuxt-headlessui": "^1.2.0",
|
||||||
"nuxt-lodash": "^2.5.3",
|
"nuxt-lodash": "^2.5.3",
|
||||||
|
"octokit": "^4.0.2",
|
||||||
"pinia": "^2.2.2",
|
"pinia": "^2.2.2",
|
||||||
"taze": "^0.16.7",
|
"taze": "^0.16.7",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"vitest": "^2.0.5",
|
"vitest": "^2.0.5",
|
||||||
"vue-tsc": "^2.1.4"
|
"vue-tsc": "^2.1.4",
|
||||||
|
"yaml": "^2.5.1",
|
||||||
|
"yup": "^1.4.0"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"vue": "latest"
|
"vue": "latest"
|
||||||
|
|
421
pages/project/[id]/edit.vue
Normal file
421
pages/project/[id]/edit.vue
Normal file
|
@ -0,0 +1,421 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as yup from 'yup'
|
||||||
|
import ProjectCreateCategoriesBasicInfo from '~/components/Project/Create/Categories/BasicInfo.vue'
|
||||||
|
import ProjectCreateCategoriesAssets from '~/components/Project/Create/Categories/Assets.vue'
|
||||||
|
import ProjectCreateCategoriesLinks from '~/components/Project/Create/Categories/Links.vue'
|
||||||
|
import ProjectCreateCategoriesTechnology from '~/components/Project/Create/Categories/Technology.vue'
|
||||||
|
import ProjectCreateCategoriesPrivacy from '~/components/Project/Create/Categories/Privacy.vue'
|
||||||
|
import ProjectCreateCategoriesSecurity from '~/components/Project/Create/Categories/Security.vue'
|
||||||
|
import ProjectCreateCategoriesTeam from '~/components/Project/Create/Categories/Team.vue'
|
||||||
|
import ProjectCreateCategoriesFunding from '~/components/Project/Create/Categories/Funding.vue'
|
||||||
|
import ProjectCreateCategoriesHistory from '~/components/Project/Create/Categories/History.vue'
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: 'create',
|
||||||
|
})
|
||||||
|
|
||||||
|
const { projects } = useData()
|
||||||
|
const { saveProject, setProject, publishProject, saveProjectImage } = useProject()
|
||||||
|
const { project, isPublishing } = storeToRefs(useProject())
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
await until(projects).toMatch(p => p?.length > 0)
|
||||||
|
setProject(route.params.id as string)
|
||||||
|
|
||||||
|
if (!project.value) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 404,
|
||||||
|
message: 'Project not found',
|
||||||
|
fatal: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = reactive([
|
||||||
|
{ label: 'Basic Info', value: 'basic_info', component: markRaw(ProjectCreateCategoriesBasicInfo) },
|
||||||
|
{ label: 'Assets', value: 'assets', component: markRaw(ProjectCreateCategoriesAssets) },
|
||||||
|
{ label: 'Links', value: 'links', component: markRaw(ProjectCreateCategoriesLinks) },
|
||||||
|
{ label: 'Technology', value: 'technology', component: markRaw(ProjectCreateCategoriesTechnology) },
|
||||||
|
{ label: 'Privacy', value: 'privacy', component: markRaw(ProjectCreateCategoriesPrivacy) },
|
||||||
|
{ label: 'Security', value: 'security', component: markRaw(ProjectCreateCategoriesSecurity) },
|
||||||
|
{ label: 'Team', value: 'team', component: markRaw(ProjectCreateCategoriesTeam) },
|
||||||
|
{ label: 'Funding', value: 'funding', component: markRaw(ProjectCreateCategoriesFunding) },
|
||||||
|
{ label: 'History', value: 'history', component: markRaw(ProjectCreateCategoriesHistory) },
|
||||||
|
])
|
||||||
|
|
||||||
|
const selectedTab = ref(tabs[0].value)
|
||||||
|
|
||||||
|
function getCurrentComponent() {
|
||||||
|
const tab = tabs.find(t => t.value === selectedTab.value) || tabs[0]
|
||||||
|
return tab.component || null
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentComponent = ref()
|
||||||
|
|
||||||
|
const { open, onChange } = useFileDialog({
|
||||||
|
accept: 'image/*', // Set to accept only image files
|
||||||
|
})
|
||||||
|
|
||||||
|
const logoSrc = ref(project.value?.logos?.[0].url || '/no-image-1-1.svg')
|
||||||
|
|
||||||
|
onChange((files) => {
|
||||||
|
if (!files?.[0]) return
|
||||||
|
const file = files[0]
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = (e) => {
|
||||||
|
logoSrc.value = e.target?.result as string
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
|
||||||
|
saveProjectImage(file)
|
||||||
|
})
|
||||||
|
|
||||||
|
const projectNameInput = ref<HTMLInputElement | null>(null)
|
||||||
|
function useProjectName() {
|
||||||
|
const isEditing = ref(false)
|
||||||
|
// const name = ref('Untitled')
|
||||||
|
const { value: name, errorMessage: nameError } = useField<string>('name', yup.string().required().notOneOf(['Untitled', 'Undefined', 'Create', 'create']))
|
||||||
|
name.value = project.value?.name || 'Untitled'
|
||||||
|
|
||||||
|
function toggleEdit() {
|
||||||
|
isEditing.value = !isEditing.value
|
||||||
|
if (isEditing.value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
projectNameInput.value?.focus()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isEditing,
|
||||||
|
name,
|
||||||
|
nameError,
|
||||||
|
toggleEdit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { isEditing, name, nameError, toggleEdit } = useProjectName()
|
||||||
|
name.value = project.value?.name || 'Untitled'
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
name: name.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function next() {
|
||||||
|
if (nameError.value)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (selectedTab.value === 'basic_info') {
|
||||||
|
if (!currentComponent.value.isFormValid())
|
||||||
|
return
|
||||||
|
else save()
|
||||||
|
}
|
||||||
|
|
||||||
|
currentComponent.value.save()
|
||||||
|
|
||||||
|
const currentIndex = tabs.findIndex(tab => tab.value === selectedTab.value)
|
||||||
|
const nextTab = tabs[currentIndex + 1] || tabs[0]
|
||||||
|
selectedTab.value = nextTab.value
|
||||||
|
}
|
||||||
|
|
||||||
|
async function publish() {
|
||||||
|
if (selectedTab.value === 'basic_info') {
|
||||||
|
if (!currentComponent.value.isFormValid())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if (isPublishing) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await publishProject()
|
||||||
|
navigateTo(`/project/${project.value?.id || project.value?.name?.toLowerCase().replace(/\s+/g, '-')}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function jumpTo(tab: string) {
|
||||||
|
if (selectedTab.value === 'basic_info') {
|
||||||
|
if (!currentComponent.value.isFormValid())
|
||||||
|
return
|
||||||
|
else save()
|
||||||
|
}
|
||||||
|
|
||||||
|
currentComponent.value.save()
|
||||||
|
|
||||||
|
selectedTab.value = tab
|
||||||
|
}
|
||||||
|
const transitionDone = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div w-full>
|
||||||
|
<div
|
||||||
|
bg-app-bg-dark_grey
|
||||||
|
px-16px
|
||||||
|
py-24px
|
||||||
|
lg="pb-0px mb--1px"
|
||||||
|
>
|
||||||
|
<div app-container>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
gap-16px
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
relative
|
||||||
|
class="parent"
|
||||||
|
>
|
||||||
|
<NuxtImg
|
||||||
|
lg="w-100px h-100px"
|
||||||
|
w-64px
|
||||||
|
h-64px
|
||||||
|
bg-app-bg-grey
|
||||||
|
object-cover
|
||||||
|
border-2
|
||||||
|
class="border-app-white/30"
|
||||||
|
:src="logoSrc ?? '/no-image-1-1.svg'"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
h-24px
|
||||||
|
hidden
|
||||||
|
parent-hover:flex
|
||||||
|
absolute
|
||||||
|
bottom-0
|
||||||
|
w-full
|
||||||
|
border-t-0
|
||||||
|
border-2
|
||||||
|
border-black
|
||||||
|
border-opacity-50
|
||||||
|
h-fit
|
||||||
|
justify-center
|
||||||
|
text="12px"
|
||||||
|
font-700
|
||||||
|
bg-app-white
|
||||||
|
text-app-black
|
||||||
|
@click="open()"
|
||||||
|
>
|
||||||
|
Upload Logo
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
font-400
|
||||||
|
text="14px app-white/50"
|
||||||
|
leading-20px
|
||||||
|
>
|
||||||
|
{{ 'Project Name' }}
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
gap-12px
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="isEditing"
|
||||||
|
ref="projectNameInput"
|
||||||
|
v-model="name"
|
||||||
|
w-fit
|
||||||
|
onkeydown="this.style.width = 0; this.style.width = this.scrollWidth + 2 + 'px';"
|
||||||
|
type="text"
|
||||||
|
font-700
|
||||||
|
text-20px
|
||||||
|
leading-28px
|
||||||
|
bg-app-bg-dark_grey
|
||||||
|
onfocus="this.style.width = 0; this.style.width = this.scrollWidth + 2 + 'px';"
|
||||||
|
>
|
||||||
|
<h2
|
||||||
|
v-else
|
||||||
|
font-700
|
||||||
|
text-20px
|
||||||
|
leading-28px
|
||||||
|
>
|
||||||
|
{{ name }}
|
||||||
|
</h2>
|
||||||
|
<button @click="toggleEdit()">
|
||||||
|
<UnoIcon
|
||||||
|
v-if="isEditing"
|
||||||
|
text-24px
|
||||||
|
class="text-app-white/30"
|
||||||
|
hover:text-app-white
|
||||||
|
i-heroicons-solid-check
|
||||||
|
/>
|
||||||
|
<UnoIcon
|
||||||
|
v-else
|
||||||
|
text-20px
|
||||||
|
class="text-app-white/30"
|
||||||
|
hover:text-app-white
|
||||||
|
i-heroicons-solid-pencil
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<span
|
||||||
|
v-if="nameError"
|
||||||
|
text-nowrap
|
||||||
|
text-app-danger
|
||||||
|
text-12px
|
||||||
|
absolute
|
||||||
|
lg:bottom--24px
|
||||||
|
bottom--16px
|
||||||
|
select-none
|
||||||
|
>Invalid project name</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
w-full
|
||||||
|
gap-46px
|
||||||
|
lg="mt-24px"
|
||||||
|
>
|
||||||
|
<SelectBox
|
||||||
|
:model-value="selectedTab"
|
||||||
|
label="Choose category"
|
||||||
|
:options="tabs.map(t => ({ label: t.label, value: t.value }))"
|
||||||
|
:border-opacity="30"
|
||||||
|
w-full
|
||||||
|
lg:hidden
|
||||||
|
block
|
||||||
|
mt-16px
|
||||||
|
@update:model-value="$event => jumpTo($event)"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.value"
|
||||||
|
lg:block
|
||||||
|
hidden
|
||||||
|
pb-8px
|
||||||
|
leading-40px
|
||||||
|
:class="selectedTab === tab.value ? 'font-bold border-b-4 border-app-white' : ''"
|
||||||
|
@click="jumpTo(tab.value)"
|
||||||
|
>
|
||||||
|
{{ tab.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
border-t-2
|
||||||
|
class="border-app-white/30"
|
||||||
|
px-16px
|
||||||
|
py-24px
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
app-container
|
||||||
|
mb-170px
|
||||||
|
lg="mb-55px"
|
||||||
|
>
|
||||||
|
<ClientOnly>
|
||||||
|
<Transition
|
||||||
|
v-if="!transitionDone"
|
||||||
|
name="fade"
|
||||||
|
mode="out-in"
|
||||||
|
appear
|
||||||
|
@after-enter="transitionDone = true"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="getCurrentComponent()"
|
||||||
|
ref="currentComponent"
|
||||||
|
:project="project"
|
||||||
|
w-full
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
/>
|
||||||
|
</Transition>
|
||||||
|
<component
|
||||||
|
:is="getCurrentComponent()"
|
||||||
|
ref="currentComponent"
|
||||||
|
:project="project"
|
||||||
|
w-full
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-if="selectedTab !== tabs[tabs.length - 1].value"
|
||||||
|
class="hidden!"
|
||||||
|
mt-48px
|
||||||
|
lg="w-fit flex!"
|
||||||
|
border
|
||||||
|
@click="next()"
|
||||||
|
>
|
||||||
|
<span px-24px>NEXT SECTION</span>
|
||||||
|
</Button>
|
||||||
|
</ClientOnly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
justify-center
|
||||||
|
text-center
|
||||||
|
fixed
|
||||||
|
bottom-0
|
||||||
|
w-full
|
||||||
|
bg-app-bg-dark_grey
|
||||||
|
class="border-app-white/30"
|
||||||
|
lg="bg-app-black w-fit border-l-2 border-t-2 right-0 border-app-white"
|
||||||
|
p-12px
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
v-if="selectedTab !== tabs[tabs.length - 1].value"
|
||||||
|
flex
|
||||||
|
lg="w-fit hidden!"
|
||||||
|
border
|
||||||
|
@click="next()"
|
||||||
|
>
|
||||||
|
<span px-24px>NEXT SECTION</span>
|
||||||
|
</Button>
|
||||||
|
<span
|
||||||
|
v-if="selectedTab !== tabs[tabs.length - 1].value"
|
||||||
|
lg="hidden"
|
||||||
|
block
|
||||||
|
text="12px italic app-white/50"
|
||||||
|
>or you can submit changes by publishing them</span>
|
||||||
|
<div flex>
|
||||||
|
<Button
|
||||||
|
w-full
|
||||||
|
lg="w-fit"
|
||||||
|
border
|
||||||
|
@click="navigateTo(`/project/${route.params.id}`)"
|
||||||
|
>
|
||||||
|
<span px-24px>CANCEL</span>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
w-full
|
||||||
|
lg="w-fit"
|
||||||
|
inverted-color
|
||||||
|
@click="publish()"
|
||||||
|
>
|
||||||
|
<UnoIcon
|
||||||
|
v-if="isPublishing"
|
||||||
|
w-108px
|
||||||
|
i-eos-icons-loading
|
||||||
|
text-black
|
||||||
|
text-18px
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
px-24px
|
||||||
|
>PUBLISH</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
407
pages/project/create.vue
Normal file
407
pages/project/create.vue
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as yup from 'yup'
|
||||||
|
import ProjectCreateCategoriesBasicInfo from '~/components/Project/Create/Categories/BasicInfo.vue'
|
||||||
|
import ProjectCreateCategoriesAssets from '~/components/Project/Create/Categories/Assets.vue'
|
||||||
|
import ProjectCreateCategoriesLinks from '~/components/Project/Create/Categories/Links.vue'
|
||||||
|
import ProjectCreateCategoriesTechnology from '~/components/Project/Create/Categories/Technology.vue'
|
||||||
|
import ProjectCreateCategoriesPrivacy from '~/components/Project/Create/Categories/Privacy.vue'
|
||||||
|
import ProjectCreateCategoriesSecurity from '~/components/Project/Create/Categories/Security.vue'
|
||||||
|
import ProjectCreateCategoriesTeam from '~/components/Project/Create/Categories/Team.vue'
|
||||||
|
import ProjectCreateCategoriesFunding from '~/components/Project/Create/Categories/Funding.vue'
|
||||||
|
import ProjectCreateCategoriesHistory from '~/components/Project/Create/Categories/History.vue'
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: 'create',
|
||||||
|
})
|
||||||
|
|
||||||
|
const { saveProject, publishProject, saveProjectImage } = useProject()
|
||||||
|
const { project, isPublishing } = storeToRefs(useProject())
|
||||||
|
|
||||||
|
const tabs = reactive([
|
||||||
|
{ label: 'Basic Info', value: 'basic_info', component: markRaw(ProjectCreateCategoriesBasicInfo) },
|
||||||
|
{ label: 'Assets', value: 'assets', component: markRaw(ProjectCreateCategoriesAssets) },
|
||||||
|
{ label: 'Links', value: 'links', component: markRaw(ProjectCreateCategoriesLinks) },
|
||||||
|
{ label: 'Technology', value: 'technology', component: markRaw(ProjectCreateCategoriesTechnology) },
|
||||||
|
{ label: 'Privacy', value: 'privacy', component: markRaw(ProjectCreateCategoriesPrivacy) },
|
||||||
|
{ label: 'Security', value: 'security', component: markRaw(ProjectCreateCategoriesSecurity) },
|
||||||
|
{ label: 'Team', value: 'team', component: markRaw(ProjectCreateCategoriesTeam) },
|
||||||
|
{ label: 'Funding', value: 'funding', component: markRaw(ProjectCreateCategoriesFunding) },
|
||||||
|
{ label: 'History', value: 'history', component: markRaw(ProjectCreateCategoriesHistory) },
|
||||||
|
])
|
||||||
|
|
||||||
|
const selectedTab = ref(tabs[0].value)
|
||||||
|
|
||||||
|
function getCurrentComponent() {
|
||||||
|
const tab = tabs.find(t => t.value === selectedTab.value) || tabs[0]
|
||||||
|
return tab.component || null
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentComponent = ref()
|
||||||
|
|
||||||
|
const { open, onChange } = useFileDialog({
|
||||||
|
accept: 'image/*', // Set to accept only image files
|
||||||
|
})
|
||||||
|
|
||||||
|
const logoSrc = ref('/no-image-1-1.svg')
|
||||||
|
|
||||||
|
onChange((files) => {
|
||||||
|
if (!files?.[0]) return
|
||||||
|
const file = files[0]
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = (e) => {
|
||||||
|
logoSrc.value = e.target?.result as string
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(file)
|
||||||
|
|
||||||
|
saveProjectImage(file)
|
||||||
|
})
|
||||||
|
|
||||||
|
const projectNameInput = ref<HTMLInputElement | null>(null)
|
||||||
|
function useProjectName() {
|
||||||
|
const isEditing = ref(false)
|
||||||
|
// const name = ref('Untitled')
|
||||||
|
const { value: name, errorMessage: nameError } = useField<string>('name', yup.string().required().notOneOf(['Untitled', 'Undefined', 'Create', 'create']))
|
||||||
|
name.value = project.value?.name || 'Untitled'
|
||||||
|
|
||||||
|
function toggleEdit() {
|
||||||
|
isEditing.value = !isEditing.value
|
||||||
|
if (isEditing.value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
projectNameInput.value?.focus()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isEditing,
|
||||||
|
name,
|
||||||
|
nameError,
|
||||||
|
toggleEdit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { isEditing, name, nameError, toggleEdit } = useProjectName()
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
saveProject({
|
||||||
|
...project.value,
|
||||||
|
name: name.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
if (selectedTab.value === 'basic_info') {
|
||||||
|
if (!currentComponent.value.isFormValid())
|
||||||
|
return
|
||||||
|
else save()
|
||||||
|
}
|
||||||
|
|
||||||
|
currentComponent.value.save()
|
||||||
|
|
||||||
|
const currentIndex = tabs.findIndex(tab => tab.value === selectedTab.value)
|
||||||
|
const nextTab = tabs[currentIndex + 1] || tabs[0]
|
||||||
|
selectedTab.value = nextTab.value
|
||||||
|
}
|
||||||
|
|
||||||
|
async function publish() {
|
||||||
|
if (selectedTab.value === 'basic_info') {
|
||||||
|
if (!currentComponent.value.isFormValid())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if (isPublishing) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await publishProject()
|
||||||
|
navigateTo(`/project/${project.value?.id || project.value?.name?.toLowerCase().replace(/\s+/g, '-')}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function jumpTo(tab: string) {
|
||||||
|
if (selectedTab.value === 'basic_info') {
|
||||||
|
if (!currentComponent.value.isFormValid())
|
||||||
|
return
|
||||||
|
else save()
|
||||||
|
}
|
||||||
|
|
||||||
|
currentComponent.value.save()
|
||||||
|
|
||||||
|
selectedTab.value = tab
|
||||||
|
}
|
||||||
|
const transitionDone = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div w-full>
|
||||||
|
<div
|
||||||
|
bg-app-bg-dark_grey
|
||||||
|
px-16px
|
||||||
|
py-24px
|
||||||
|
lg="pb-0px mb--1px"
|
||||||
|
>
|
||||||
|
<div app-container>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
gap-16px
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
relative
|
||||||
|
class="parent"
|
||||||
|
>
|
||||||
|
<NuxtImg
|
||||||
|
lg="w-100px h-100px"
|
||||||
|
w-64px
|
||||||
|
h-64px
|
||||||
|
bg-app-bg-grey
|
||||||
|
object-cover
|
||||||
|
border-2
|
||||||
|
class="border-app-white/30"
|
||||||
|
opacity-30
|
||||||
|
:src="logoSrc ?? '/no-image-1-1.svg'"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
h-24px
|
||||||
|
hidden
|
||||||
|
parent-hover:flex
|
||||||
|
absolute
|
||||||
|
bottom-0
|
||||||
|
w-full
|
||||||
|
border-t-0
|
||||||
|
border-2
|
||||||
|
border-black
|
||||||
|
border-opacity-80
|
||||||
|
h-fit
|
||||||
|
justify-center
|
||||||
|
text="12px"
|
||||||
|
font-700
|
||||||
|
bg-app-white
|
||||||
|
text-app-black
|
||||||
|
@click="open()"
|
||||||
|
>
|
||||||
|
Upload Logo
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-8px
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
font-400
|
||||||
|
text="14px app-white/50"
|
||||||
|
leading-20px
|
||||||
|
>
|
||||||
|
{{ 'Project Name' }}
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
items-center
|
||||||
|
gap-12px
|
||||||
|
relative
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="isEditing"
|
||||||
|
ref="projectNameInput"
|
||||||
|
v-model="name"
|
||||||
|
w-fit
|
||||||
|
onkeydown="this.style.width = 0; this.style.width = this.scrollWidth + 2 + 'px';"
|
||||||
|
type="text"
|
||||||
|
font-700
|
||||||
|
text-20px
|
||||||
|
leading-28px
|
||||||
|
bg-app-bg-dark_grey
|
||||||
|
onfocus="this.style.width = 0; this.style.width = this.scrollWidth + 2 + 'px';"
|
||||||
|
>
|
||||||
|
<h2
|
||||||
|
v-else
|
||||||
|
font-700
|
||||||
|
text-20px
|
||||||
|
leading-28px
|
||||||
|
>
|
||||||
|
{{ name }}
|
||||||
|
</h2>
|
||||||
|
<button @click="toggleEdit()">
|
||||||
|
<UnoIcon
|
||||||
|
v-if="isEditing"
|
||||||
|
text-24px
|
||||||
|
class="text-app-white/30"
|
||||||
|
hover:text-app-white
|
||||||
|
i-heroicons-solid-check
|
||||||
|
/>
|
||||||
|
<UnoIcon
|
||||||
|
v-else
|
||||||
|
text-20px
|
||||||
|
class="text-app-white/30"
|
||||||
|
hover:text-app-white
|
||||||
|
i-heroicons-solid-pencil
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<span
|
||||||
|
v-if="nameError"
|
||||||
|
text-nowrap
|
||||||
|
text-app-danger
|
||||||
|
text-12px
|
||||||
|
absolute
|
||||||
|
lg:bottom--24px
|
||||||
|
bottom--16px
|
||||||
|
select-none
|
||||||
|
>Invalid project name</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
w-full
|
||||||
|
gap-46px
|
||||||
|
lg="mt-24px"
|
||||||
|
>
|
||||||
|
<SelectBox
|
||||||
|
:model-value="selectedTab"
|
||||||
|
label="Choose category"
|
||||||
|
:options="tabs.map(t => ({ label: t.label, value: t.value }))"
|
||||||
|
:border-opacity="30"
|
||||||
|
w-full
|
||||||
|
lg:hidden
|
||||||
|
block
|
||||||
|
mt-16px
|
||||||
|
@update:model-value="$event => jumpTo($event)"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.value"
|
||||||
|
lg:block
|
||||||
|
hidden
|
||||||
|
pb-8px
|
||||||
|
leading-40px
|
||||||
|
:class="selectedTab === tab.value ? 'font-bold border-b-4 border-app-white' : ''"
|
||||||
|
@click="selectedTab = tab.value"
|
||||||
|
>
|
||||||
|
{{ tab.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
border-t-2
|
||||||
|
class="border-app-white/30"
|
||||||
|
px-16px
|
||||||
|
py-24px
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
app-container
|
||||||
|
mb-170px
|
||||||
|
lg="mb-55px"
|
||||||
|
>
|
||||||
|
<ClientOnly>
|
||||||
|
<Transition
|
||||||
|
v-if="!transitionDone"
|
||||||
|
name="fade"
|
||||||
|
mode="out-in"
|
||||||
|
appear
|
||||||
|
@after-enter="transitionDone = true"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="getCurrentComponent()"
|
||||||
|
ref="currentComponent"
|
||||||
|
:project="project"
|
||||||
|
w-full
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
/>
|
||||||
|
</Transition>
|
||||||
|
<component
|
||||||
|
:is="getCurrentComponent()"
|
||||||
|
v-else
|
||||||
|
ref="currentComponent"
|
||||||
|
:project="project"
|
||||||
|
w-full
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-24px
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-if="selectedTab !== tabs[tabs.length - 1].value"
|
||||||
|
class="hidden!"
|
||||||
|
mt-48px
|
||||||
|
lg="w-fit flex!"
|
||||||
|
border
|
||||||
|
@click="next()"
|
||||||
|
>
|
||||||
|
<span px-24px>NEXT SECTION</span>
|
||||||
|
</Button>
|
||||||
|
</ClientOnly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
flex
|
||||||
|
flex-col
|
||||||
|
gap-16px
|
||||||
|
justify-center
|
||||||
|
text-center
|
||||||
|
fixed
|
||||||
|
bottom-0
|
||||||
|
w-full
|
||||||
|
bg-app-bg-dark_grey
|
||||||
|
class="border-app-white/30"
|
||||||
|
lg="bg-app-black w-fit border-l-2 border-t-2 right-0 border-app-white"
|
||||||
|
p-12px
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
v-if="selectedTab !== tabs[tabs.length - 1].value"
|
||||||
|
flex
|
||||||
|
lg="w-fit hidden!"
|
||||||
|
border
|
||||||
|
@click="next()"
|
||||||
|
>
|
||||||
|
<span px-24px>NEXT SECTION</span>
|
||||||
|
</Button>
|
||||||
|
<span
|
||||||
|
v-if="selectedTab !== tabs[tabs.length - 1].value"
|
||||||
|
lg="hidden"
|
||||||
|
block
|
||||||
|
text="12px italic app-white/50"
|
||||||
|
>or you can submit changes by publishing them</span>
|
||||||
|
<div flex>
|
||||||
|
<Button
|
||||||
|
w-full
|
||||||
|
lg="w-fit"
|
||||||
|
border
|
||||||
|
@click="navigateTo('/')"
|
||||||
|
>
|
||||||
|
<span px-24px>CANCEL</span>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
w-full
|
||||||
|
lg="w-fit"
|
||||||
|
inverted-color
|
||||||
|
@click="publish()"
|
||||||
|
>
|
||||||
|
<UnoIcon
|
||||||
|
v-if="isPublishing"
|
||||||
|
w-108px
|
||||||
|
i-eos-icons-loading
|
||||||
|
text-black
|
||||||
|
text-18px
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
px-24px
|
||||||
|
>PUBLISH</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
443
pnpm-lock.yaml
443
pnpm-lock.yaml
|
@ -18,6 +18,9 @@ importers:
|
||||||
'@iconify-json/bi':
|
'@iconify-json/bi':
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.0
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
|
'@iconify-json/eos-icons':
|
||||||
|
specifier: ^1.1.10
|
||||||
|
version: 1.2.0
|
||||||
'@iconify-json/heroicons-outline':
|
'@iconify-json/heroicons-outline':
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.0
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
|
@ -29,7 +32,7 @@ importers:
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
'@iconify-json/iconoir':
|
'@iconify-json/iconoir':
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.0
|
||||||
version: 1.2.0
|
version: 1.2.1
|
||||||
'@iconify-json/material-symbols':
|
'@iconify-json/material-symbols':
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
|
@ -38,7 +41,7 @@ importers:
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
'@iconify-json/simple-icons':
|
'@iconify-json/simple-icons':
|
||||||
specifier: ^1.2.2
|
specifier: ^1.2.2
|
||||||
version: 1.2.2
|
version: 1.2.3
|
||||||
'@nuxt/devtools':
|
'@nuxt/devtools':
|
||||||
specifier: ^1.4.1
|
specifier: ^1.4.1
|
||||||
version: 1.4.1(rollup@4.21.2)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0))
|
version: 1.4.1(rollup@4.21.2)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0))
|
||||||
|
@ -60,6 +63,9 @@ importers:
|
||||||
'@unocss/nuxt':
|
'@unocss/nuxt':
|
||||||
specifier: ^0.62.3
|
specifier: ^0.62.3
|
||||||
version: 0.62.3(magicast@0.3.5)(postcss@8.4.44)(rollup@4.21.2)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0))(webpack@5.89.0(esbuild@0.23.1))
|
version: 0.62.3(magicast@0.3.5)(postcss@8.4.44)(rollup@4.21.2)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0))(webpack@5.89.0(esbuild@0.23.1))
|
||||||
|
'@vee-validate/nuxt':
|
||||||
|
specifier: ^4.13.2
|
||||||
|
version: 4.13.2(magicast@0.3.5)(rollup@4.21.2)(vue@3.4.38(typescript@5.5.4))
|
||||||
'@vueuse/nuxt':
|
'@vueuse/nuxt':
|
||||||
specifier: ^11.0.3
|
specifier: ^11.0.3
|
||||||
version: 11.0.3(magicast@0.3.5)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@20.8.7)(encoding@0.1.13)(eslint@9.9.1(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.3)(rollup@4.21.2)(terser@5.22.0)(typescript@5.5.4)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0))(vue-tsc@2.1.4(typescript@5.5.4)))(rollup@4.21.2)(vue@3.4.38(typescript@5.5.4))
|
version: 11.0.3(magicast@0.3.5)(nuxt@3.13.0(@parcel/watcher@2.4.1)(@types/node@20.8.7)(encoding@0.1.13)(eslint@9.9.1(jiti@1.21.6))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.3)(rollup@4.21.2)(terser@5.22.0)(typescript@5.5.4)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0))(vue-tsc@2.1.4(typescript@5.5.4)))(rollup@4.21.2)(vue@3.4.38(typescript@5.5.4))
|
||||||
|
@ -75,6 +81,9 @@ importers:
|
||||||
nuxt-lodash:
|
nuxt-lodash:
|
||||||
specifier: ^2.5.3
|
specifier: ^2.5.3
|
||||||
version: 2.5.3(rollup@4.21.2)
|
version: 2.5.3(rollup@4.21.2)
|
||||||
|
octokit:
|
||||||
|
specifier: ^4.0.2
|
||||||
|
version: 4.0.2
|
||||||
pinia:
|
pinia:
|
||||||
specifier: ^2.2.2
|
specifier: ^2.2.2
|
||||||
version: 2.2.2(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4))
|
version: 2.2.2(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4))
|
||||||
|
@ -90,6 +99,12 @@ importers:
|
||||||
vue-tsc:
|
vue-tsc:
|
||||||
specifier: ^2.1.4
|
specifier: ^2.1.4
|
||||||
version: 2.1.4(typescript@5.5.4)
|
version: 2.1.4(typescript@5.5.4)
|
||||||
|
yaml:
|
||||||
|
specifier: ^2.5.1
|
||||||
|
version: 2.5.1
|
||||||
|
yup:
|
||||||
|
specifier: ^1.4.0
|
||||||
|
version: 1.4.0
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
@ -1113,6 +1128,9 @@ packages:
|
||||||
'@iconify-json/bi@1.2.0':
|
'@iconify-json/bi@1.2.0':
|
||||||
resolution: {integrity: sha512-kaBV87cQlyeMkBBiMqsf3b43Nsxdk/rYKvR29dnktht57WUyHCnBAuH+ca/bscX856CzRpVX+sYs7arjrJD0qA==}
|
resolution: {integrity: sha512-kaBV87cQlyeMkBBiMqsf3b43Nsxdk/rYKvR29dnktht57WUyHCnBAuH+ca/bscX856CzRpVX+sYs7arjrJD0qA==}
|
||||||
|
|
||||||
|
'@iconify-json/eos-icons@1.2.0':
|
||||||
|
resolution: {integrity: sha512-grdfoS20Z4gWAzNPza7ytguNBWeTOkx4Y6aZHs149t2Z6AhW7zG3VWkkq6M+YuL2G8ugHnBw7ZxgazZ6oiMnIQ==}
|
||||||
|
|
||||||
'@iconify-json/heroicons-outline@1.2.0':
|
'@iconify-json/heroicons-outline@1.2.0':
|
||||||
resolution: {integrity: sha512-Qy1sRmQYqih6xRxwCtnX0hXJ4252t83C0CnNWAP3gF0fH0Qmp9RY66LMB0moYGxQxUhsTFIl2nNceSVSBUo8Tg==}
|
resolution: {integrity: sha512-Qy1sRmQYqih6xRxwCtnX0hXJ4252t83C0CnNWAP3gF0fH0Qmp9RY66LMB0moYGxQxUhsTFIl2nNceSVSBUo8Tg==}
|
||||||
|
|
||||||
|
@ -1122,8 +1140,8 @@ packages:
|
||||||
'@iconify-json/ic@1.2.0':
|
'@iconify-json/ic@1.2.0':
|
||||||
resolution: {integrity: sha512-L4+m77xTQB08X3I+3xs1+IrvK+aNcuN/7ODu5aUPznHKLU+/8UYcsjUgNHze6vPOGPQ0AG+kCwvy91EYPXSRxw==}
|
resolution: {integrity: sha512-L4+m77xTQB08X3I+3xs1+IrvK+aNcuN/7ODu5aUPznHKLU+/8UYcsjUgNHze6vPOGPQ0AG+kCwvy91EYPXSRxw==}
|
||||||
|
|
||||||
'@iconify-json/iconoir@1.2.0':
|
'@iconify-json/iconoir@1.2.1':
|
||||||
resolution: {integrity: sha512-GbYAERFy9c1laIo1QZon9sBjRkX9rksirehmLIvvohn+W++fpPlvQnzVl0VpY/v2GCvs1pZ42spTKDj0AcofvA==}
|
resolution: {integrity: sha512-x55gpORwMGkmmT9UO11rzfMOp40k0ggQnPiOoh9axbyuHrkFMN7pdoCbaXkzqAdShcoI1dLzARbdqXi2sAPJXQ==}
|
||||||
|
|
||||||
'@iconify-json/material-symbols@1.2.1':
|
'@iconify-json/material-symbols@1.2.1':
|
||||||
resolution: {integrity: sha512-r9yaBzlUmN87aCTSoCNtDCd7R9F0iVDjNPL9QHHhm1WglFJvTUKx9iBC5xcZpP0qN0bg9R5FkM90CndWxEBAnw==}
|
resolution: {integrity: sha512-r9yaBzlUmN87aCTSoCNtDCd7R9F0iVDjNPL9QHHhm1WglFJvTUKx9iBC5xcZpP0qN0bg9R5FkM90CndWxEBAnw==}
|
||||||
|
@ -1131,8 +1149,8 @@ packages:
|
||||||
'@iconify-json/mdi@1.2.0':
|
'@iconify-json/mdi@1.2.0':
|
||||||
resolution: {integrity: sha512-E9/3l5Syg3wfuarorFodhn4s8YorxhH3U3U20LaNBNiqw1kFNIDWhF6HymuzAD35k7RH0OBasJ+ZUyFtVVV6eg==}
|
resolution: {integrity: sha512-E9/3l5Syg3wfuarorFodhn4s8YorxhH3U3U20LaNBNiqw1kFNIDWhF6HymuzAD35k7RH0OBasJ+ZUyFtVVV6eg==}
|
||||||
|
|
||||||
'@iconify-json/simple-icons@1.2.2':
|
'@iconify-json/simple-icons@1.2.3':
|
||||||
resolution: {integrity: sha512-VMgCoMnpvcCJ5b3rTOGPzW5j6959nIdRCk+8FGzK/vAaDd6f9sx65OcKOqP3C75llpybH/iQhk5yrJ/TOdQKeg==}
|
resolution: {integrity: sha512-KZpqyPkDdyAvrpMz9/FYovwFsr3xrHf9esJeBng3iqNInhuZhF33XO1k6Yf8g2p10ynUW7AYEiGJkYzDi4DENQ==}
|
||||||
|
|
||||||
'@iconify/types@2.0.0':
|
'@iconify/types@2.0.0':
|
||||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||||
|
@ -1360,6 +1378,113 @@ packages:
|
||||||
'@nuxtjs/color-mode@3.4.4':
|
'@nuxtjs/color-mode@3.4.4':
|
||||||
resolution: {integrity: sha512-VSNJVGnRIjiGmfbMa0cN+rwNRowDRTL/wku/z5MpKSanVo3khIRitBNqNviso1l3T+LW0pLHeXBNp6L8g/l1EA==}
|
resolution: {integrity: sha512-VSNJVGnRIjiGmfbMa0cN+rwNRowDRTL/wku/z5MpKSanVo3khIRitBNqNviso1l3T+LW0pLHeXBNp6L8g/l1EA==}
|
||||||
|
|
||||||
|
'@octokit/app@15.1.0':
|
||||||
|
resolution: {integrity: sha512-TkBr7QgOmE6ORxvIAhDbZsqPkF7RSqTY4pLTtUQCvr6dTXqvi2fFo46q3h1lxlk/sGMQjqyZ0kEahkD/NyzOHg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/auth-app@7.1.1':
|
||||||
|
resolution: {integrity: sha512-kRAd6yelV9OgvlEJE88H0VLlQdZcag9UlLr7dV0YYP37X8PPDvhgiTy66QVhDXdyoT0AleFN2w/qXkPdrSzINg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/auth-oauth-app@8.1.1':
|
||||||
|
resolution: {integrity: sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/auth-oauth-device@7.1.1':
|
||||||
|
resolution: {integrity: sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/auth-oauth-user@5.1.1':
|
||||||
|
resolution: {integrity: sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/auth-token@5.1.1':
|
||||||
|
resolution: {integrity: sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/auth-unauthenticated@6.1.0':
|
||||||
|
resolution: {integrity: sha512-zPSmfrUAcspZH/lOFQnVnvjQZsIvmfApQH6GzJrkIunDooU1Su2qt2FfMTSVPRp7WLTQyC20Kd55lF+mIYaohQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/core@6.1.2':
|
||||||
|
resolution: {integrity: sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/endpoint@10.1.1':
|
||||||
|
resolution: {integrity: sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/graphql@8.1.1':
|
||||||
|
resolution: {integrity: sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/oauth-app@7.1.3':
|
||||||
|
resolution: {integrity: sha512-EHXbOpBkSGVVGF1W+NLMmsnSsJRkcrnVmDKt0TQYRBb6xWfWzoi9sBD4DIqZ8jGhOWO/V8t4fqFyJ4vDQDn9bg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/oauth-authorization-url@7.1.1':
|
||||||
|
resolution: {integrity: sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/oauth-methods@5.1.2':
|
||||||
|
resolution: {integrity: sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/openapi-types@22.2.0':
|
||||||
|
resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==}
|
||||||
|
|
||||||
|
'@octokit/openapi-webhooks-types@8.3.0':
|
||||||
|
resolution: {integrity: sha512-vKLsoR4xQxg4Z+6rU/F65ItTUz/EXbD+j/d4mlq2GW8TsA4Tc8Kdma2JTAAJ5hrKWUQzkR/Esn2fjsqiVRYaQg==}
|
||||||
|
|
||||||
|
'@octokit/plugin-paginate-graphql@5.2.2':
|
||||||
|
resolution: {integrity: sha512-7znSVvlNAOJisCqAnjN1FtEziweOHSjPGAuc5W58NeGNAr/ZB57yCsjQbXDlWsVryA7hHQaEQPcBbJYFawlkyg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@octokit/core': '>=6'
|
||||||
|
|
||||||
|
'@octokit/plugin-paginate-rest@11.3.3':
|
||||||
|
resolution: {integrity: sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@octokit/core': '>=6'
|
||||||
|
|
||||||
|
'@octokit/plugin-rest-endpoint-methods@13.2.4':
|
||||||
|
resolution: {integrity: sha512-gusyAVgTrPiuXOdfqOySMDztQHv6928PQ3E4dqVGEtOvRXAKRbJR4b1zQyniIT9waqaWk/UDaoJ2dyPr7Bk7Iw==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@octokit/core': '>=6'
|
||||||
|
|
||||||
|
'@octokit/plugin-retry@7.1.1':
|
||||||
|
resolution: {integrity: sha512-G9Ue+x2odcb8E1XIPhaFBnTTIrrUDfXN05iFXiqhR+SeeeDMMILcAnysOsxUpEWcQp2e5Ft397FCXTcPkiPkLw==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@octokit/core': '>=6'
|
||||||
|
|
||||||
|
'@octokit/plugin-throttling@9.3.1':
|
||||||
|
resolution: {integrity: sha512-Qd91H4liUBhwLB2h6jZ99bsxoQdhgPk6TdwnClPyTBSDAdviGPceViEgUwj+pcQDmB/rfAXAXK7MTochpHM3yQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@octokit/core': ^6.0.0
|
||||||
|
|
||||||
|
'@octokit/request-error@6.1.4':
|
||||||
|
resolution: {integrity: sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/request@9.1.3':
|
||||||
|
resolution: {integrity: sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/types@13.5.0':
|
||||||
|
resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==}
|
||||||
|
|
||||||
|
'@octokit/webhooks-methods@5.1.0':
|
||||||
|
resolution: {integrity: sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@octokit/webhooks@13.3.0':
|
||||||
|
resolution: {integrity: sha512-TUkJLtI163Bz5+JK0O+zDkQpn4gKwN+BovclUvCj6pI/6RXrFqQvUMRS2M+Rt8Rv0qR3wjoMoOPmpJKeOh0nBg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.4.1':
|
'@parcel/watcher-android-arm64@2.4.1':
|
||||||
resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==}
|
resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
@ -1708,6 +1833,9 @@ packages:
|
||||||
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
'@types/aws-lambda@8.10.145':
|
||||||
|
resolution: {integrity: sha512-dtByW6WiFk5W5Jfgz1VM+YPA21xMXTuSFoLYIDY0L44jDLLflVPtZkYuu3/YxpGcvjzKFBZLU+GyKjR0HOYtyw==}
|
||||||
|
|
||||||
'@types/eslint-scope@3.7.6':
|
'@types/eslint-scope@3.7.6':
|
||||||
resolution: {integrity: sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==}
|
resolution: {integrity: sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==}
|
||||||
|
|
||||||
|
@ -1915,6 +2043,9 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
webpack: ^4 || ^5
|
webpack: ^4 || ^5
|
||||||
|
|
||||||
|
'@vee-validate/nuxt@4.13.2':
|
||||||
|
resolution: {integrity: sha512-rpYYO2isCrgHRdJnKRXGPn8aqhyZvCPUJgNubftPum1txbngkO/LNiFsZdFDO7auGprDAQf7axpszRfeKoCGVg==}
|
||||||
|
|
||||||
'@vercel/nft@0.26.5':
|
'@vercel/nft@0.26.5':
|
||||||
resolution: {integrity: sha512-NHxohEqad6Ra/r4lGknO52uc/GrWILXAMs1BB4401GTqww0fw1bAqzpG1XHuDO+dprg4GvsD9ZLLSsdo78p9hQ==}
|
resolution: {integrity: sha512-NHxohEqad6Ra/r4lGknO52uc/GrWILXAMs1BB4401GTqww0fw1bAqzpG1XHuDO+dprg4GvsD9ZLLSsdo78p9hQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
@ -2272,6 +2403,9 @@ packages:
|
||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
|
before-after-hook@3.0.2:
|
||||||
|
resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==}
|
||||||
|
|
||||||
binary-extensions@2.2.0:
|
binary-extensions@2.2.0:
|
||||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -2288,6 +2422,9 @@ packages:
|
||||||
boolbase@1.0.0:
|
boolbase@1.0.0:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
|
||||||
|
bottleneck@2.19.5:
|
||||||
|
resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==}
|
||||||
|
|
||||||
brace-expansion@1.1.11:
|
brace-expansion@1.1.11:
|
||||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||||
|
|
||||||
|
@ -3594,9 +3731,6 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
jsonc-parser@3.2.0:
|
|
||||||
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
|
|
||||||
|
|
||||||
jsonfile@6.1.0:
|
jsonfile@6.1.0:
|
||||||
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
||||||
|
|
||||||
|
@ -3855,9 +3989,6 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
mlly@1.4.2:
|
|
||||||
resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==}
|
|
||||||
|
|
||||||
mlly@1.7.1:
|
mlly@1.7.1:
|
||||||
resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==}
|
resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==}
|
||||||
|
|
||||||
|
@ -4031,6 +4162,10 @@ packages:
|
||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
octokit@4.0.2:
|
||||||
|
resolution: {integrity: sha512-wbqF4uc1YbcldtiBFfkSnquHtECEIpYD78YUXI6ri1Im5OO2NLo6ZVpRdbJpdnpZ05zMrVPssNiEo6JQtea+Qg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
ofetch@1.3.3:
|
ofetch@1.3.3:
|
||||||
resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==}
|
resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==}
|
||||||
|
|
||||||
|
@ -4205,9 +4340,6 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
pkg-types@1.0.3:
|
|
||||||
resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
|
|
||||||
|
|
||||||
pkg-types@1.2.0:
|
pkg-types@1.2.0:
|
||||||
resolution: {integrity: sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==}
|
resolution: {integrity: sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==}
|
||||||
|
|
||||||
|
@ -4431,6 +4563,9 @@ packages:
|
||||||
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
property-expr@2.0.6:
|
||||||
|
resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==}
|
||||||
|
|
||||||
protocols@2.0.1:
|
protocols@2.0.1:
|
||||||
resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==}
|
resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==}
|
||||||
|
|
||||||
|
@ -4920,6 +5055,9 @@ packages:
|
||||||
text-table@0.2.0:
|
text-table@0.2.0:
|
||||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||||
|
|
||||||
|
tiny-case@1.0.3:
|
||||||
|
resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==}
|
||||||
|
|
||||||
tiny-invariant@1.3.1:
|
tiny-invariant@1.3.1:
|
||||||
resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
|
resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
|
||||||
|
|
||||||
|
@ -4957,6 +5095,9 @@ packages:
|
||||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
|
toposort@2.0.2:
|
||||||
|
resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==}
|
||||||
|
|
||||||
totalist@3.0.1:
|
totalist@3.0.1:
|
||||||
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
@ -5001,10 +5142,18 @@ packages:
|
||||||
resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
|
resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
type-fest@2.19.0:
|
||||||
|
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
|
||||||
|
engines: {node: '>=12.20'}
|
||||||
|
|
||||||
type-fest@3.13.1:
|
type-fest@3.13.1:
|
||||||
resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==}
|
resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==}
|
||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
|
|
||||||
|
type-fest@4.26.1:
|
||||||
|
resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
typescript@5.5.4:
|
typescript@5.5.4:
|
||||||
resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
|
resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
|
@ -5059,6 +5208,12 @@ packages:
|
||||||
resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
|
resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
|
||||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||||
|
|
||||||
|
universal-github-app-jwt@2.2.0:
|
||||||
|
resolution: {integrity: sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==}
|
||||||
|
|
||||||
|
universal-user-agent@7.0.2:
|
||||||
|
resolution: {integrity: sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==}
|
||||||
|
|
||||||
universalify@2.0.0:
|
universalify@2.0.0:
|
||||||
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
|
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
@ -5221,6 +5376,11 @@ packages:
|
||||||
resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==}
|
resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==}
|
||||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||||
|
|
||||||
|
vee-validate@4.13.2:
|
||||||
|
resolution: {integrity: sha512-HlpR/6MJ92TW9f135umMZKUqdd/tFQTxLNSf2ImbU4Y/MlLVAUpF1l64VdjTOhbClAqPjCb5p/SqHDxLpUHXrw==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.4.26
|
||||||
|
|
||||||
vite-hot-client@0.2.3:
|
vite-hot-client@0.2.3:
|
||||||
resolution: {integrity: sha512-rOGAV7rUlUHX89fP2p2v0A2WWvV3QMX2UYq0fRqsWSvFvev4atHWqjwGoKaZT1VTKyLGk533ecu3eyd0o59CAg==}
|
resolution: {integrity: sha512-rOGAV7rUlUHX89fP2p2v0A2WWvV3QMX2UYq0fRqsWSvFvev4atHWqjwGoKaZT1VTKyLGk533ecu3eyd0o59CAg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -5523,8 +5683,8 @@ packages:
|
||||||
yallist@4.0.0:
|
yallist@4.0.0:
|
||||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||||
|
|
||||||
yaml@2.5.0:
|
yaml@2.5.1:
|
||||||
resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==}
|
resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
@ -5544,6 +5704,9 @@ packages:
|
||||||
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
|
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
|
||||||
engines: {node: '>=12.20'}
|
engines: {node: '>=12.20'}
|
||||||
|
|
||||||
|
yup@1.4.0:
|
||||||
|
resolution: {integrity: sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==}
|
||||||
|
|
||||||
zhead@2.2.4:
|
zhead@2.2.4:
|
||||||
resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==}
|
resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==}
|
||||||
|
|
||||||
|
@ -6466,6 +6629,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
|
'@iconify-json/eos-icons@1.2.0':
|
||||||
|
dependencies:
|
||||||
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
'@iconify-json/heroicons-outline@1.2.0':
|
'@iconify-json/heroicons-outline@1.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
|
@ -6478,7 +6645,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
'@iconify-json/iconoir@1.2.0':
|
'@iconify-json/iconoir@1.2.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
|
@ -6490,7 +6657,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
'@iconify-json/simple-icons@1.2.2':
|
'@iconify-json/simple-icons@1.2.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
|
|
||||||
|
@ -6832,9 +6999,9 @@ snapshots:
|
||||||
ignore: 5.2.4
|
ignore: 5.2.4
|
||||||
jiti: 1.20.0
|
jiti: 1.20.0
|
||||||
knitwork: 1.0.0
|
knitwork: 1.0.0
|
||||||
mlly: 1.4.2
|
mlly: 1.7.1
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
pkg-types: 1.0.3
|
pkg-types: 1.2.0
|
||||||
scule: 1.0.0
|
scule: 1.0.0
|
||||||
semver: 7.5.4
|
semver: 7.5.4
|
||||||
ufo: 1.3.1
|
ufo: 1.3.1
|
||||||
|
@ -6870,7 +7037,7 @@ snapshots:
|
||||||
defu: 6.1.2
|
defu: 6.1.2
|
||||||
hookable: 5.5.3
|
hookable: 5.5.3
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
pkg-types: 1.0.3
|
pkg-types: 1.2.0
|
||||||
postcss-import-resolver: 2.0.0
|
postcss-import-resolver: 2.0.0
|
||||||
std-env: 3.4.3
|
std-env: 3.4.3
|
||||||
ufo: 1.3.1
|
ufo: 1.3.1
|
||||||
|
@ -7013,6 +7180,152 @@ snapshots:
|
||||||
- rollup
|
- rollup
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@octokit/app@15.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/auth-app': 7.1.1
|
||||||
|
'@octokit/auth-unauthenticated': 6.1.0
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
'@octokit/oauth-app': 7.1.3
|
||||||
|
'@octokit/plugin-paginate-rest': 11.3.3(@octokit/core@6.1.2)
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
'@octokit/webhooks': 13.3.0
|
||||||
|
|
||||||
|
'@octokit/auth-app@7.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/auth-oauth-app': 8.1.1
|
||||||
|
'@octokit/auth-oauth-user': 5.1.1
|
||||||
|
'@octokit/request': 9.1.3
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
lru-cache: 10.4.3
|
||||||
|
universal-github-app-jwt: 2.2.0
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/auth-oauth-app@8.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/auth-oauth-device': 7.1.1
|
||||||
|
'@octokit/auth-oauth-user': 5.1.1
|
||||||
|
'@octokit/request': 9.1.3
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/auth-oauth-device@7.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/oauth-methods': 5.1.2
|
||||||
|
'@octokit/request': 9.1.3
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/auth-oauth-user@5.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/auth-oauth-device': 7.1.1
|
||||||
|
'@octokit/oauth-methods': 5.1.2
|
||||||
|
'@octokit/request': 9.1.3
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/auth-token@5.1.1': {}
|
||||||
|
|
||||||
|
'@octokit/auth-unauthenticated@6.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
|
||||||
|
'@octokit/core@6.1.2':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/auth-token': 5.1.1
|
||||||
|
'@octokit/graphql': 8.1.1
|
||||||
|
'@octokit/request': 9.1.3
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
before-after-hook: 3.0.2
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/endpoint@10.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/graphql@8.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/request': 9.1.3
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/oauth-app@7.1.3':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/auth-oauth-app': 8.1.1
|
||||||
|
'@octokit/auth-oauth-user': 5.1.1
|
||||||
|
'@octokit/auth-unauthenticated': 6.1.0
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
'@octokit/oauth-authorization-url': 7.1.1
|
||||||
|
'@octokit/oauth-methods': 5.1.2
|
||||||
|
'@types/aws-lambda': 8.10.145
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/oauth-authorization-url@7.1.1': {}
|
||||||
|
|
||||||
|
'@octokit/oauth-methods@5.1.2':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/oauth-authorization-url': 7.1.1
|
||||||
|
'@octokit/request': 9.1.3
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
|
||||||
|
'@octokit/openapi-types@22.2.0': {}
|
||||||
|
|
||||||
|
'@octokit/openapi-webhooks-types@8.3.0': {}
|
||||||
|
|
||||||
|
'@octokit/plugin-paginate-graphql@5.2.2(@octokit/core@6.1.2)':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
|
||||||
|
'@octokit/plugin-paginate-rest@11.3.3(@octokit/core@6.1.2)':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
|
||||||
|
'@octokit/plugin-rest-endpoint-methods@13.2.4(@octokit/core@6.1.2)':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
|
||||||
|
'@octokit/plugin-retry@7.1.1(@octokit/core@6.1.2)':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
bottleneck: 2.19.5
|
||||||
|
|
||||||
|
'@octokit/plugin-throttling@9.3.1(@octokit/core@6.1.2)':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
bottleneck: 2.19.5
|
||||||
|
|
||||||
|
'@octokit/request-error@6.1.4':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
|
||||||
|
'@octokit/request@9.1.3':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/endpoint': 10.1.1
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
universal-user-agent: 7.0.2
|
||||||
|
|
||||||
|
'@octokit/types@13.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/openapi-types': 22.2.0
|
||||||
|
|
||||||
|
'@octokit/webhooks-methods@5.1.0': {}
|
||||||
|
|
||||||
|
'@octokit/webhooks@13.3.0':
|
||||||
|
dependencies:
|
||||||
|
'@octokit/openapi-webhooks-types': 8.3.0
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/webhooks-methods': 5.1.0
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.4.1':
|
'@parcel/watcher-android-arm64@2.4.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
@ -7282,6 +7595,8 @@ snapshots:
|
||||||
|
|
||||||
'@trysound/sax@0.2.0': {}
|
'@trysound/sax@0.2.0': {}
|
||||||
|
|
||||||
|
'@types/aws-lambda@8.10.145': {}
|
||||||
|
|
||||||
'@types/eslint-scope@3.7.6':
|
'@types/eslint-scope@3.7.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/eslint': 9.6.1
|
'@types/eslint': 9.6.1
|
||||||
|
@ -7628,6 +7943,17 @@ snapshots:
|
||||||
- rollup
|
- rollup
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@vee-validate/nuxt@4.13.2(magicast@0.3.5)(rollup@4.21.2)(vue@3.4.38(typescript@5.5.4))':
|
||||||
|
dependencies:
|
||||||
|
'@nuxt/kit': 3.13.0(magicast@0.3.5)(rollup@4.21.2)
|
||||||
|
local-pkg: 0.5.0
|
||||||
|
vee-validate: 4.13.2(vue@3.4.38(typescript@5.5.4))
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- magicast
|
||||||
|
- rollup
|
||||||
|
- supports-color
|
||||||
|
- vue
|
||||||
|
|
||||||
'@vercel/nft@0.26.5(encoding@0.1.13)':
|
'@vercel/nft@0.26.5(encoding@0.1.13)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@mapbox/node-pre-gyp': 1.0.11(encoding@0.1.13)
|
'@mapbox/node-pre-gyp': 1.0.11(encoding@0.1.13)
|
||||||
|
@ -8141,6 +8467,8 @@ snapshots:
|
||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
|
before-after-hook@3.0.2: {}
|
||||||
|
|
||||||
binary-extensions@2.2.0: {}
|
binary-extensions@2.2.0: {}
|
||||||
|
|
||||||
bindings@1.5.0:
|
bindings@1.5.0:
|
||||||
|
@ -8158,6 +8486,8 @@ snapshots:
|
||||||
|
|
||||||
boolbase@1.0.0: {}
|
boolbase@1.0.0: {}
|
||||||
|
|
||||||
|
bottleneck@2.19.5: {}
|
||||||
|
|
||||||
brace-expansion@1.1.11:
|
brace-expansion@1.1.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
|
@ -8251,11 +8581,11 @@ snapshots:
|
||||||
dotenv: 16.3.1
|
dotenv: 16.3.1
|
||||||
giget: 1.1.3
|
giget: 1.1.3
|
||||||
jiti: 1.20.0
|
jiti: 1.20.0
|
||||||
mlly: 1.4.2
|
mlly: 1.7.1
|
||||||
ohash: 1.1.3
|
ohash: 1.1.3
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
perfect-debounce: 1.0.0
|
perfect-debounce: 1.0.0
|
||||||
pkg-types: 1.0.3
|
pkg-types: 1.2.0
|
||||||
rc9: 2.1.1
|
rc9: 2.1.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -9649,8 +9979,6 @@ snapshots:
|
||||||
|
|
||||||
json5@2.2.3: {}
|
json5@2.2.3: {}
|
||||||
|
|
||||||
jsonc-parser@3.2.0: {}
|
|
||||||
|
|
||||||
jsonfile@6.1.0:
|
jsonfile@6.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
universalify: 2.0.0
|
universalify: 2.0.0
|
||||||
|
@ -9722,7 +10050,7 @@ snapshots:
|
||||||
|
|
||||||
local-pkg@0.5.0:
|
local-pkg@0.5.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
mlly: 1.4.2
|
mlly: 1.7.1
|
||||||
pkg-types: 1.2.0
|
pkg-types: 1.2.0
|
||||||
|
|
||||||
locate-path@5.0.0:
|
locate-path@5.0.0:
|
||||||
|
@ -9905,13 +10233,6 @@ snapshots:
|
||||||
|
|
||||||
mkdirp@1.0.4: {}
|
mkdirp@1.0.4: {}
|
||||||
|
|
||||||
mlly@1.4.2:
|
|
||||||
dependencies:
|
|
||||||
acorn: 8.10.0
|
|
||||||
pathe: 1.1.1
|
|
||||||
pkg-types: 1.0.3
|
|
||||||
ufo: 1.3.1
|
|
||||||
|
|
||||||
mlly@1.7.1:
|
mlly@1.7.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.12.1
|
acorn: 8.12.1
|
||||||
|
@ -10261,6 +10582,19 @@ snapshots:
|
||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
|
octokit@4.0.2:
|
||||||
|
dependencies:
|
||||||
|
'@octokit/app': 15.1.0
|
||||||
|
'@octokit/core': 6.1.2
|
||||||
|
'@octokit/oauth-app': 7.1.3
|
||||||
|
'@octokit/plugin-paginate-graphql': 5.2.2(@octokit/core@6.1.2)
|
||||||
|
'@octokit/plugin-paginate-rest': 11.3.3(@octokit/core@6.1.2)
|
||||||
|
'@octokit/plugin-rest-endpoint-methods': 13.2.4(@octokit/core@6.1.2)
|
||||||
|
'@octokit/plugin-retry': 7.1.1(@octokit/core@6.1.2)
|
||||||
|
'@octokit/plugin-throttling': 9.3.1(@octokit/core@6.1.2)
|
||||||
|
'@octokit/request-error': 6.1.4
|
||||||
|
'@octokit/types': 13.5.0
|
||||||
|
|
||||||
ofetch@1.3.3:
|
ofetch@1.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
destr: 2.0.2
|
destr: 2.0.2
|
||||||
|
@ -10429,12 +10763,6 @@ snapshots:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.5.4
|
typescript: 5.5.4
|
||||||
|
|
||||||
pkg-types@1.0.3:
|
|
||||||
dependencies:
|
|
||||||
jsonc-parser: 3.2.0
|
|
||||||
mlly: 1.4.2
|
|
||||||
pathe: 1.1.1
|
|
||||||
|
|
||||||
pkg-types@1.2.0:
|
pkg-types@1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
confbox: 0.1.7
|
confbox: 0.1.7
|
||||||
|
@ -10653,6 +10981,8 @@ snapshots:
|
||||||
kleur: 3.0.3
|
kleur: 3.0.3
|
||||||
sisteransi: 1.0.5
|
sisteransi: 1.0.5
|
||||||
|
|
||||||
|
property-expr@2.0.6: {}
|
||||||
|
|
||||||
protocols@2.0.1: {}
|
protocols@2.0.1: {}
|
||||||
|
|
||||||
prr@1.0.1: {}
|
prr@1.0.1: {}
|
||||||
|
@ -11215,6 +11545,8 @@ snapshots:
|
||||||
|
|
||||||
text-table@0.2.0: {}
|
text-table@0.2.0: {}
|
||||||
|
|
||||||
|
tiny-case@1.0.3: {}
|
||||||
|
|
||||||
tiny-invariant@1.3.1: {}
|
tiny-invariant@1.3.1: {}
|
||||||
|
|
||||||
tinybench@2.9.0: {}
|
tinybench@2.9.0: {}
|
||||||
|
@ -11240,6 +11572,8 @@ snapshots:
|
||||||
|
|
||||||
toidentifier@1.0.1: {}
|
toidentifier@1.0.1: {}
|
||||||
|
|
||||||
|
toposort@2.0.2: {}
|
||||||
|
|
||||||
totalist@3.0.1: {}
|
totalist@3.0.1: {}
|
||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
@ -11274,8 +11608,12 @@ snapshots:
|
||||||
|
|
||||||
type-fest@0.8.1: {}
|
type-fest@0.8.1: {}
|
||||||
|
|
||||||
|
type-fest@2.19.0: {}
|
||||||
|
|
||||||
type-fest@3.13.1: {}
|
type-fest@3.13.1: {}
|
||||||
|
|
||||||
|
type-fest@4.26.1: {}
|
||||||
|
|
||||||
typescript@5.5.4: {}
|
typescript@5.5.4: {}
|
||||||
|
|
||||||
ufo@1.3.1: {}
|
ufo@1.3.1: {}
|
||||||
|
@ -11349,9 +11687,9 @@ snapshots:
|
||||||
fast-glob: 3.3.1
|
fast-glob: 3.3.1
|
||||||
local-pkg: 0.4.3
|
local-pkg: 0.4.3
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
mlly: 1.4.2
|
mlly: 1.7.1
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
pkg-types: 1.0.3
|
pkg-types: 1.2.0
|
||||||
scule: 1.0.0
|
scule: 1.0.0
|
||||||
strip-literal: 1.3.0
|
strip-literal: 1.3.0
|
||||||
unplugin: 1.5.0
|
unplugin: 1.5.0
|
||||||
|
@ -11366,6 +11704,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
imurmurhash: 0.1.4
|
imurmurhash: 0.1.4
|
||||||
|
|
||||||
|
universal-github-app-jwt@2.2.0: {}
|
||||||
|
|
||||||
|
universal-user-agent@7.0.2: {}
|
||||||
|
|
||||||
universalify@2.0.0: {}
|
universalify@2.0.0: {}
|
||||||
|
|
||||||
unocss@0.62.3(@unocss/webpack@0.62.3(rollup@4.21.2)(webpack@5.89.0(esbuild@0.23.1)))(postcss@8.4.44)(rollup@4.21.2)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0)):
|
unocss@0.62.3(@unocss/webpack@0.62.3(rollup@4.21.2)(webpack@5.89.0(esbuild@0.23.1)))(postcss@8.4.44)(rollup@4.21.2)(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0)):
|
||||||
|
@ -11413,7 +11755,7 @@ snapshots:
|
||||||
pathe: 1.1.2
|
pathe: 1.1.2
|
||||||
scule: 1.3.0
|
scule: 1.3.0
|
||||||
unplugin: 1.12.3
|
unplugin: 1.12.3
|
||||||
yaml: 2.5.0
|
yaml: 2.5.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vue-router: 4.4.3(vue@3.4.38(typescript@5.5.4))
|
vue-router: 4.4.3(vue@3.4.38(typescript@5.5.4))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -11544,6 +11886,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
builtins: 5.0.1
|
builtins: 5.0.1
|
||||||
|
|
||||||
|
vee-validate@4.13.2(vue@3.4.38(typescript@5.5.4)):
|
||||||
|
dependencies:
|
||||||
|
'@vue/devtools-api': 6.6.3
|
||||||
|
type-fest: 4.26.1
|
||||||
|
vue: 3.4.38(typescript@5.5.4)
|
||||||
|
|
||||||
vite-hot-client@0.2.3(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0)):
|
vite-hot-client@0.2.3(vite@5.4.2(@types/node@20.8.7)(terser@5.22.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 5.4.2(@types/node@20.8.7)(terser@5.22.0)
|
vite: 5.4.2(@types/node@20.8.7)(terser@5.22.0)
|
||||||
|
@ -11860,7 +12208,7 @@ snapshots:
|
||||||
|
|
||||||
yallist@4.0.0: {}
|
yallist@4.0.0: {}
|
||||||
|
|
||||||
yaml@2.5.0: {}
|
yaml@2.5.1: {}
|
||||||
|
|
||||||
yargs-parser@21.1.1: {}
|
yargs-parser@21.1.1: {}
|
||||||
|
|
||||||
|
@ -11878,6 +12226,13 @@ snapshots:
|
||||||
|
|
||||||
yocto-queue@1.0.0: {}
|
yocto-queue@1.0.0: {}
|
||||||
|
|
||||||
|
yup@1.4.0:
|
||||||
|
dependencies:
|
||||||
|
property-expr: 2.0.6
|
||||||
|
tiny-case: 1.0.3
|
||||||
|
toposort: 2.0.2
|
||||||
|
type-fest: 2.19.0
|
||||||
|
|
||||||
zhead@2.2.4: {}
|
zhead@2.2.4: {}
|
||||||
|
|
||||||
zip-stream@6.0.1:
|
zip-stream@6.0.1:
|
||||||
|
|
135
server/api/data.post.ts
Normal file
135
server/api/data.post.ts
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
import { App } from 'octokit'
|
||||||
|
import yaml from 'yaml'
|
||||||
|
import type { Project } from '~/types'
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody<{ project: Project, image?: { type: string, data: string } }>(event)
|
||||||
|
const yamlProject = yaml.stringify(body.project)
|
||||||
|
const { appId, privateKey, installationId } = useAppConfig().github
|
||||||
|
|
||||||
|
const id = body.project.id || body.project.name.toLowerCase().replace(/\s+/g, '-')
|
||||||
|
|
||||||
|
const app = new App({
|
||||||
|
appId,
|
||||||
|
privateKey,
|
||||||
|
})
|
||||||
|
await app.octokit.rest.apps.getAuthenticated()
|
||||||
|
const octokit = await app.getInstallationOctokit(installationId)
|
||||||
|
|
||||||
|
const owner = 'develit-io'
|
||||||
|
const repo = 'test-repo'
|
||||||
|
const baseBranch = 'main'
|
||||||
|
const newBranchName = `${id}-project-update-${Date.now()}`
|
||||||
|
const commitMessage = `${body.project.id ? `Updating the project: ${body.project.name}` : `Initiating the creation of project: ${body.project.name}`}`
|
||||||
|
|
||||||
|
const files = [
|
||||||
|
{
|
||||||
|
path: `src/projects/${id}/index.yaml`,
|
||||||
|
content: yamlProject,
|
||||||
|
encoding: 'utf-8',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
if (body.image?.data && body.image?.type) {
|
||||||
|
files.push(
|
||||||
|
{
|
||||||
|
path: `src/projects/${id}/logo.${body.image.type.split('/')[1]}`,
|
||||||
|
content: body.image.data,
|
||||||
|
encoding: 'base64',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createBranch(owner: string, repo: string, newBranchName: string, baseBranch: string) {
|
||||||
|
const { data: baseBranchData } = await octokit.rest.git.getRef({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
ref: `heads/${baseBranch}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
await octokit.rest.git.createRef({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
ref: `refs/heads/${newBranchName}`,
|
||||||
|
sha: baseBranchData.object.sha,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function commitChangesToNewBranch(owner: string, repo: string, newBranch: string, message: string, files: { path: string, content: string, encoding: string }[]) {
|
||||||
|
const { data: latestCommit } = await octokit.rest.repos.getCommit({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
ref: newBranch,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { data: baseTree } = await octokit.rest.git.getTree({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
tree_sha: latestCommit.commit.tree.sha,
|
||||||
|
})
|
||||||
|
|
||||||
|
const blobs = await Promise.all(files.map(async (file) => {
|
||||||
|
const { data: blob } = await octokit.rest.git.createBlob({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
content: file.content,
|
||||||
|
encoding: file.encoding,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
path: file.path,
|
||||||
|
mode: '100644' as const,
|
||||||
|
type: 'blob' as const,
|
||||||
|
sha: blob.sha,
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { data: newTree } = await octokit.rest.git.createTree({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
base_tree: baseTree.sha,
|
||||||
|
tree: blobs,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { data: newCommit } = await octokit.rest.git.createCommit({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
message,
|
||||||
|
tree: newTree.sha,
|
||||||
|
parents: [latestCommit.sha],
|
||||||
|
})
|
||||||
|
|
||||||
|
await octokit.rest.git.updateRef({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
ref: `heads/${newBranch}`,
|
||||||
|
sha: newCommit.sha,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createPullRequest(owner: string, repo: string, head: string, base: string, title: string, body: string) {
|
||||||
|
const { data: pullRequest } = await octokit.rest.pulls.create({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
title,
|
||||||
|
head,
|
||||||
|
base,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
|
||||||
|
return pullRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await createBranch(owner, repo, newBranchName, baseBranch)
|
||||||
|
console.log(`Branch ${newBranchName} created successfully!`)
|
||||||
|
|
||||||
|
await commitChangesToNewBranch(owner, repo, newBranchName, commitMessage, files)
|
||||||
|
console.log(`Changes committed to branch ${newBranchName} successfully!`)
|
||||||
|
|
||||||
|
const pullRequestData = await createPullRequest(owner, repo, newBranchName, baseBranch, `${body.project.id ? `Update project: ${body.project.name}` : `Create project: ${body.project.name}`}`, `${body.project.id ? `Updating the project: ${body.project.name}` : `Initiating the creation of project: ${body.project.name}`}`)
|
||||||
|
console.log('Pull request created:', pullRequestData)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Error during GitHub operations:', error)
|
||||||
|
}
|
||||||
|
})
|
|
@ -16084,6 +16084,48 @@
|
||||||
"name": "Other"
|
"name": "Other"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"project_phase": [
|
||||||
|
{
|
||||||
|
"id": "mainnet",
|
||||||
|
"name": "Mainnet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "testnet",
|
||||||
|
"name": "Testnet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "alpha",
|
||||||
|
"name": "Alpha"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "beta",
|
||||||
|
"name": "Beta"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mvp",
|
||||||
|
"name": "MVP"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"asset_custody_type": [
|
||||||
|
{
|
||||||
|
"id": "non-custody",
|
||||||
|
"name": "Non-custody"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sign_in_type_requirments": [
|
||||||
|
{
|
||||||
|
"id": "wallet",
|
||||||
|
"name": "Wallet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "email",
|
||||||
|
"name": "Email"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "seed",
|
||||||
|
"name": "Seed"
|
||||||
|
}
|
||||||
|
],
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"id": "eth",
|
"id": "eth",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export interface Category {
|
export interface Category {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
|
usecases: string[]
|
||||||
projectsCount: number
|
projectsCount: number
|
||||||
usecases?: string[]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export interface InputOption {
|
export interface InputOption {
|
||||||
label: string
|
label: string
|
||||||
value: string
|
value: string | number
|
||||||
count?: number
|
count?: number
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ export interface Member {
|
||||||
role?: string
|
role?: string
|
||||||
link?: string
|
link?: string
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}
|
}[]
|
||||||
company?: {
|
company?: {
|
||||||
name?: string
|
name?: string
|
||||||
link?: string
|
link?: string
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Member } from './member'
|
import type { Team } from './team'
|
||||||
import type { Fund } from './fund'
|
import type { Fund } from './fund'
|
||||||
import type { ClientDiversability } from './clientDiversability'
|
import type { ClientDiversability } from './clientDiversability'
|
||||||
import type { Audit } from './audit'
|
import type { Audit } from './audit'
|
||||||
|
@ -16,15 +16,17 @@ export interface Project {
|
||||||
assets_used?: string[]
|
assets_used?: string[]
|
||||||
tokens?: {
|
tokens?: {
|
||||||
name?: string
|
name?: string
|
||||||
symbol: string
|
symbol?: string
|
||||||
network?: string
|
network?: string
|
||||||
contract_address?: string
|
contract_address?: string
|
||||||
link?: string
|
token_link?: string
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}[]
|
}[]
|
||||||
description?: string
|
description?: string
|
||||||
project_type?: string
|
project_type?: string
|
||||||
product_launch_day?: string
|
product_launch_day?: string
|
||||||
|
project_phase?: string
|
||||||
|
sunset: boolean
|
||||||
technology?: {
|
technology?: {
|
||||||
type: string
|
type: string
|
||||||
name?: string
|
name?: string
|
||||||
|
@ -65,17 +67,17 @@ export interface Project {
|
||||||
}
|
}
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
opensource: boolean
|
opensource: boolean
|
||||||
viewing_key: boolean
|
viewing_key?: boolean
|
||||||
dissapearing_tx: boolean
|
dissapearing_tx?: boolean
|
||||||
frontend_anonymity: string
|
frontend_anonymity?: string
|
||||||
identity_integration: null
|
identity_integration?: null
|
||||||
connected_tx: boolean
|
connected_tx?: boolean
|
||||||
revealed_recipient: boolean
|
revealed_recipient?: boolean
|
||||||
revealed_sender: boolean
|
revealed_sender?: boolean
|
||||||
revealed_ammount: boolean
|
revealed_ammount?: boolean
|
||||||
reversability_condition: string
|
reversability_condition?: string
|
||||||
data_masking: string
|
data_masking?: string
|
||||||
asset_custody_type: string
|
asset_custody_type?: string
|
||||||
}
|
}
|
||||||
licences?: string
|
licences?: string
|
||||||
privacy_policy?: {
|
privacy_policy?: {
|
||||||
|
@ -84,7 +86,7 @@ export interface Project {
|
||||||
data_usage?: string
|
data_usage?: string
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}
|
}
|
||||||
team?: Member[]
|
team?: Team
|
||||||
storage?: {
|
storage?: {
|
||||||
decentralized?: boolean
|
decentralized?: boolean
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
|
@ -92,7 +94,7 @@ export interface Project {
|
||||||
tracebility?: {
|
tracebility?: {
|
||||||
tracked_data?: string
|
tracked_data?: string
|
||||||
kyc?: boolean
|
kyc?: boolean
|
||||||
sign_in_type_requirments?: string
|
sign_in_type_requirments?: string[]
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}
|
}
|
||||||
third_party_dependency?: string
|
third_party_dependency?: string
|
||||||
|
@ -107,7 +109,7 @@ export interface Project {
|
||||||
time?: string
|
time?: string
|
||||||
link?: string
|
link?: string
|
||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}
|
}[]
|
||||||
client_diversability?: ClientDiversability[]
|
client_diversability?: ClientDiversability[]
|
||||||
default_privacy?: boolean
|
default_privacy?: boolean
|
||||||
funding?: Fund[]
|
funding?: Fund[]
|
||||||
|
@ -133,23 +135,23 @@ export interface ProjectShallow {
|
||||||
title1: string
|
title1: string
|
||||||
description: string
|
description: string
|
||||||
percentage: number
|
percentage: number
|
||||||
|
forum?: string
|
||||||
|
github?: string
|
||||||
|
website?: string
|
||||||
|
twitter?: string
|
||||||
|
coingecko?: string
|
||||||
|
explorer?: string
|
||||||
|
newsletter?: string
|
||||||
|
readyness?: string
|
||||||
|
team?: Team
|
||||||
|
docs?: string
|
||||||
|
audits?: Audit[]
|
||||||
|
support?: number
|
||||||
|
anonymity?: boolean
|
||||||
categories: string[]
|
categories: string[]
|
||||||
usecases?: string[]
|
usecases?: string[]
|
||||||
ecosystem?: string[]
|
ecosystem?: string[]
|
||||||
assets_used?: string []
|
assets_used?: string []
|
||||||
forum?: string | undefined
|
|
||||||
github?: string | undefined
|
|
||||||
website?: string | undefined
|
|
||||||
twitter?: string | undefined
|
|
||||||
coingecko?: string | undefined
|
|
||||||
explorer?: string | undefined
|
|
||||||
newsletter?: string | undefined
|
|
||||||
readyness?: string | undefined
|
|
||||||
team: Member[] | undefined
|
|
||||||
docs: string | undefined
|
|
||||||
audits?: Audit[] | undefined
|
|
||||||
support?: number | undefined
|
|
||||||
anonymity?: boolean | undefined
|
|
||||||
ratings?: ProjectRating[]
|
ratings?: ProjectRating[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
types/team.ts
Normal file
19
types/team.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
export interface Team {
|
||||||
|
name?: string
|
||||||
|
role?: string
|
||||||
|
link?: string
|
||||||
|
avatar?: string
|
||||||
|
anonymous?: boolean
|
||||||
|
teammembers?: {
|
||||||
|
name?: string
|
||||||
|
role?: string
|
||||||
|
link?: string
|
||||||
|
[k: string]: unknown
|
||||||
|
}[]
|
||||||
|
company?: {
|
||||||
|
name?: string
|
||||||
|
link?: string
|
||||||
|
contacts?: string
|
||||||
|
[k: string]: unknown
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ export default defineConfig({
|
||||||
black: '#000',
|
black: '#000',
|
||||||
green: '#B5E26B',
|
green: '#B5E26B',
|
||||||
red: '#FF5252',
|
red: '#FF5252',
|
||||||
|
danger: '#FF0000',
|
||||||
bg: {
|
bg: {
|
||||||
grey: '#ffffff33',
|
grey: '#ffffff33',
|
||||||
dark_grey: '#161616',
|
dark_grey: '#161616',
|
||||||
|
|
Loading…
Reference in a new issue