feat(ui): [WIP] Layout section component
This commit is contained in:
parent
4a62f05d1e
commit
860f12512c
|
@ -158,6 +158,16 @@ const sortedFiles = computed(() => {
|
|||
|
||||
const hasActiveUploads = computed(() => files.value.some(file => file.active))
|
||||
|
||||
// const isOpen = computed({
|
||||
// get() {
|
||||
// return store.state.ui.modalsOpen.has(modalName);
|
||||
// },
|
||||
// set(value) {
|
||||
// store.commit('ui/setModal', [modalName, value]);
|
||||
// }
|
||||
// })
|
||||
|
||||
|
||||
//
|
||||
// Quota status
|
||||
//
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import type { RouterLinkProps } from 'vue-router';
|
||||
import { type ColorProps, type DefaultProps, type PastelProps, type RaisedProps, type VariantProps, color } from '~/composables/color'
|
||||
import { type WidthProps, width } from '~/composables/width'
|
||||
|
||||
const props = defineProps<{
|
||||
columnWidth?: string,
|
||||
noGap?: true,
|
||||
noRule?: true,
|
||||
noWrap?: true
|
||||
}
|
||||
& { [P in "stack" | "grid" | "flex" | "columns" | "row" | "page"]?: true | string }
|
||||
noWrap?: true,
|
||||
} & { [P in "stack" | "grid" | "flex" | "columns" | "row" | "page"]?: true | string }
|
||||
& { [C in "nav" | "aside" | "header" | "footer" | "main" | "label" | "form" | "h1" | "h2" | "h3" | "h4" | "h5"]?: true }
|
||||
& { [G in 'no-gap' | 'gap-16' | 'gap-12' | 'gap-8' | 'gap-auto' ]?: true }
|
||||
& (PastelProps | ColorProps | DefaultProps)
|
||||
& RaisedProps
|
||||
& VariantProps
|
||||
|
@ -18,6 +18,10 @@ const props = defineProps<{
|
|||
|
||||
const columnWidth = props.columnWidth ?? '46px'
|
||||
|
||||
const maybeGap = Object.entries(props).find(
|
||||
([key, value]) => value===true && key.startsWith('gap'))
|
||||
const gapWidth = maybeGap ? `${maybeGap[0].replace('gap', '')}px` : '32px'
|
||||
|
||||
const attributes = computed(() => ({
|
||||
...color(props)(width(props)()),
|
||||
layout:
|
||||
|
@ -27,6 +31,8 @@ const attributes = computed(() => ({
|
|||
props.columns ? 'columns' :
|
||||
'stack'
|
||||
}))
|
||||
|
||||
console.log("GRID", props.grid, props.grid ? 'grid-custom' : 'none')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -34,7 +40,7 @@ const attributes = computed(() => ({
|
|||
:is="props.nav ? 'nav' : props.aside ? 'aside' : props.header ? 'header' : props.footer ? 'footer' : props.main ? 'main' : props.label ? 'label' : props.form ? 'form' : props.h1 ? 'h1' : props.h2 ? 'h2' : props.h3 ? 'h3' : props.h4 ? 'h4' : props.h5 ? 'h5' : 'div'"
|
||||
:class="[
|
||||
$style.layout,
|
||||
noGap || $style.gap,
|
||||
('noGap' in props && props.noGap === true) || $style.gap,
|
||||
noWrap || $style.wrap,
|
||||
]" v-bind="attributes">
|
||||
<slot />
|
||||
|
@ -47,7 +53,7 @@ const attributes = computed(() => ({
|
|||
|
||||
/* Override --gap with your preferred value */
|
||||
|
||||
gap: var(--gap, 32px);
|
||||
gap: var(--gap, v-bind(gapWidth));
|
||||
&:not(.gap) {
|
||||
gap: 0;
|
||||
}
|
||||
|
@ -80,7 +86,7 @@ const attributes = computed(() => ({
|
|||
|
||||
&[layout=grid-custom] {
|
||||
display: grid;
|
||||
grid: v-bind(grid);
|
||||
grid: v-bind("props.grid");
|
||||
grid-auto-flow: row dense;
|
||||
place-content: center;
|
||||
/* If the grid has a fixed size smaller than its container, center it */
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import type { RouterLinkProps } from 'vue-router';
|
||||
|
||||
import Card from '~/components/ui/Card.vue'
|
||||
import Layout from '~/components/ui/Layout.vue'
|
||||
import Toggle from '~/components/ui/Toggle.vue'
|
||||
import Spacer from '~/components/ui/layout/Spacer.vue'
|
||||
import Button from '~/components/ui/Button.vue'
|
||||
import Link from '~/components/ui/Link.vue'
|
||||
import Activity from '~/components/ui/Activity.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
[M in 'tiny-items' | 'small-items' | 'medium-items']?: true }
|
||||
& { [H in 'h1' | 'h2' | 'h3']?: string }
|
||||
& { action?: { text: string } & (RouterLinkProps | { onClick: (...args: any[]) => void | Promise<void> }) }>()
|
||||
|
||||
const [headingLevel, title] =
|
||||
props.h1 ? ['h1', props.h1]
|
||||
: props.h2 ? ['h2', props.h2]
|
||||
: ['h3', props.h3]
|
||||
|
||||
const headerGrid =
|
||||
`auto / repeat(auto-fit, calc(46px * ${props['tiny-items'] ? 2 : props['small-items'] ? 3 : 4} + 32px * 2))`
|
||||
|
||||
console.log(headerGrid);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section>
|
||||
<Layout header :grid="headerGrid">
|
||||
|
||||
<!-- The title row's width is a multiple of the expected items' column span -->
|
||||
<Layout flex no-gap
|
||||
style="grid-column: 1 / -1; align-self: baseline;"
|
||||
>
|
||||
<!-- Set distance between baseline and previous row -->
|
||||
<Spacer v
|
||||
:size="64"
|
||||
style="outline:1px solid red; align-self: baseline;"
|
||||
/>
|
||||
<!-- Flexible row content -->
|
||||
<!-- Note that the `h3` uses its padding to create the 24px bottom gap -->
|
||||
<component :is="headingLevel" style="align-self: baseline; padding:0 0 24px 10px; margin:0;">
|
||||
{{ title }}
|
||||
</component>
|
||||
<Spacer grow />
|
||||
<!-- Action! You can either specify `to` or `onClick`. -->
|
||||
<Button v-if="props.action && 'onClick' in props.action"
|
||||
ghost thin auto align-self="baseline"
|
||||
style="grid-column:-1;"
|
||||
:onClick="props.action.onClick"
|
||||
>
|
||||
{{ props.action.text }}
|
||||
</Button>
|
||||
<Link v-if="props.action && 'to' in props.action"
|
||||
ghost thin auto align-self="baseline"
|
||||
:to="props.action.to"
|
||||
>
|
||||
{{ props.action.text }}
|
||||
</Link>
|
||||
</Layout>
|
||||
</Layout>
|
||||
<Layout main
|
||||
grid="auto / repeat(auto-fit, 46px)"
|
||||
>
|
||||
<slot />
|
||||
</Layout>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style module>
|
||||
.layout {
|
||||
transition: all .15s;
|
||||
|
||||
/* Override --gap with your preferred value */
|
||||
|
||||
gap: var(--gap, v-bind(gapWidth));
|
||||
|
||||
&:not(.gap) {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
/* Growth */
|
||||
|
||||
&:has(:global(>.grow)) {
|
||||
>:not(:global(.grow)) {
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Layout strategy */
|
||||
|
||||
&[layout=columns] {
|
||||
column-count: auto;
|
||||
column-width: v-bind(columnWidth);
|
||||
display: block;
|
||||
column-rule: 1px solid v-bind("noRule ? 'transparent' : 'var(--border-color)'");
|
||||
}
|
||||
|
||||
&[layout=grid] {
|
||||
display: grid;
|
||||
grid-template-columns:
|
||||
repeat(auto-fit, v-bind(columnWidth));
|
||||
grid-auto-flow: row dense;
|
||||
place-content: center;
|
||||
/* If the grid has a fixed size smaller than its container, center it */
|
||||
}
|
||||
|
||||
&[layout=grid-custom] {
|
||||
display: grid;
|
||||
grid: v-bind(grid);
|
||||
grid-auto-flow: row dense;
|
||||
place-content: center;
|
||||
/* If the grid has a fixed size smaller than its container, center it */
|
||||
}
|
||||
|
||||
&[layout=stack] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&[layout=flex] {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: v-bind('props.noWrap ? "nowrap" : "wrap"');
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -26,11 +26,13 @@ const styles = {
|
|||
const getStyle = (props: Partial<WidthProps>) => (key: Key): string =>
|
||||
// @ts-ignore
|
||||
typeof styles[key] === 'function' && key in props ?
|
||||
// @ts-ignore
|
||||
styles[key](
|
||||
// TODO: Make the typescript compiler understand `key in props`
|
||||
// @ts-ignore
|
||||
props[key]
|
||||
)
|
||||
|
||||
: styles[key]
|
||||
|
||||
// All keys are exclusive
|
||||
|
|
|
@ -5,6 +5,7 @@ import { color } from '~/composables/color';
|
|||
import Sidebar from '~/ui/components/Sidebar.vue'
|
||||
import ShortcutsModal from './modals/Shortcuts.vue'
|
||||
import LanguagesModal from './modals/Languages.vue'
|
||||
import UploadModal from './modals/Upload.vue';
|
||||
|
||||
// Fake content
|
||||
onMounted(async () => {
|
||||
|
@ -17,9 +18,10 @@ onMounted(async () => {
|
|||
<template>
|
||||
<div class="funkwhale grid">
|
||||
<Sidebar/>
|
||||
<RouterView v-bind="color({}, ['default', 'solid'])()" />
|
||||
<RouterView v-bind="color({}, ['default', 'solid'])" />
|
||||
<LanguagesModal />
|
||||
<ShortcutsModal />
|
||||
<UploadModal />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Layout aside :class="[$style.sidebar, $style['sticky-content']]" default solid raised>
|
||||
<Layout flex no-gap header style="justify-content:space-between; padding-right:8px;">
|
||||
<Layout aside default solid raised gap-12 :class="[$style.sidebar, $style['sticky-content']]">
|
||||
<Layout header flex no-gap style="justify-content:space-between; padding-right:8px;">
|
||||
<Link
|
||||
:to="{name: logoUrl}"
|
||||
:class="$style['logo']"
|
||||
|
@ -55,10 +55,13 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
|||
>
|
||||
</Link>
|
||||
|
||||
<Link to="/upload"
|
||||
<Button
|
||||
align-self="center"
|
||||
round icon="bi-upload"
|
||||
class="is-icon-only"
|
||||
ghost
|
||||
@click="store.commit('ui/toggleModal', 'upload')"
|
||||
:aria-pressed="store.state.ui.modalsOpen.has('languages') || undefined"
|
||||
>
|
||||
<Transition>
|
||||
<div
|
||||
|
@ -72,7 +75,7 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
|||
/>
|
||||
</div>
|
||||
</Transition>
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
<UserMenu/>
|
||||
|
||||
|
|
|
@ -3,10 +3,13 @@ import { computed, ref, reactive } from 'vue'
|
|||
import { useUploadsStore } from '~/ui/stores/upload'
|
||||
import { bytesToHumanSize } from '~/ui/composables/bytes'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useStore } from '~/store'
|
||||
import UploadList from '~/ui/components/UploadList.vue'
|
||||
import Alert from '~/components/ui/Alert.vue'
|
||||
import Button from '~/components/ui/Button.vue'
|
||||
import Modal from '~/components/ui/Modal.vue'
|
||||
import Input from '~/components/ui/Input.vue'
|
||||
import FileUploadWidget from '~/components/library/FileUploadWidget.vue'
|
||||
|
||||
const uploads = useUploadsStore()
|
||||
|
||||
|
@ -67,23 +70,35 @@ const sortItems = reactive([
|
|||
])
|
||||
const currentSort = ref(sortItems[0])
|
||||
|
||||
const store = useStore()
|
||||
|
||||
// Filtering
|
||||
const filterItems = reactive([
|
||||
{ label: 'All', value: 'all' }
|
||||
])
|
||||
const currentFilter = ref(filterItems[0])
|
||||
|
||||
const modalName = 'upload'
|
||||
|
||||
const isOpen = computed({
|
||||
get() {
|
||||
return store.state.ui.modalsOpen.has(modalName);
|
||||
},
|
||||
set(value) {
|
||||
store.commit('ui/setModal', [modalName, value]);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
v-model="libraryOpen"
|
||||
title="Upload music to library"
|
||||
v-model="isOpen"
|
||||
title="Upload..."
|
||||
>
|
||||
<template #alert="closeAlert">
|
||||
<Alert yellow>
|
||||
Before uploading, please ensure your files are tagged properly.
|
||||
We recommend using Picard for that purpose.
|
||||
|
||||
<template #actions>
|
||||
<Button @click="closeAlert">
|
||||
Got it
|
||||
|
@ -92,8 +107,9 @@ const currentFilter = ref(filterItems[0])
|
|||
</Alert>
|
||||
</template>
|
||||
|
||||
<FwFileInput
|
||||
:accept="['.flac', '.ogg', '.opus', '.mp3', '.aac', '.aif', '.aiff', '.m4a']"
|
||||
<Input
|
||||
type="file"
|
||||
:accept="['.flac', '.ogg', '.opus', '.mp3', '.aac', '.aif', '.aiff', '.m4a'].join(', ')"
|
||||
multiple
|
||||
auto-reset
|
||||
@files="processFiles"
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useStore } from '~/store'
|
||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut';
|
||||
|
||||
import Modal from '~/components/ui/Modal.vue'
|
||||
import Button from '~/components/ui/Button.vue'
|
||||
import Input from '~/components/ui/Input.vue'
|
||||
import Layout from '~/components/ui/Layout.vue'
|
||||
import Spacer from '~/components/ui/layout/Spacer.vue'
|
||||
import Alert from '~/components/ui/Alert.vue';
|
||||
import Card from '~/components/ui/Card.vue';
|
||||
import Pagination from '~/components/ui/Pagination.vue';
|
||||
|
||||
import type { Actor, Channel } from '~/types';
|
||||
import FileUploadWidget from '~/components/library/FileUploadWidget.vue';
|
||||
import type { VueUploadItem } from 'vue-upload-component';
|
||||
import UploadForm from '~/components/channels/UploadForm.vue';
|
||||
import FileUpload from '~/components/library/FileUpload.vue';
|
||||
|
||||
const { t } = useI18n()
|
||||
const store = useStore()
|
||||
|
||||
const modalName = 'upload'
|
||||
|
||||
const isOpen = computed({
|
||||
get() {
|
||||
return store.state.ui.modalsOpen.has(modalName);
|
||||
},
|
||||
set(value) {
|
||||
store.commit('ui/setModal', [modalName, value]);
|
||||
}
|
||||
})
|
||||
|
||||
onKeyboardShortcut('u', () => store.commit('ui/toggleModal', modalName))
|
||||
|
||||
const dummyActor = (number:number) : Actor => ({
|
||||
id: number,
|
||||
summary: "actor summary",
|
||||
preferred_username: `actor ${number}`,
|
||||
full_username: "actor full username",
|
||||
is_local: false,
|
||||
domain: "domain"
|
||||
})
|
||||
|
||||
const dummyChannel=(number:number) : Channel=>
|
||||
({
|
||||
id : number,
|
||||
uuid : 'uuid',
|
||||
actor: dummyActor(number),
|
||||
attributed_to: dummyActor(number),
|
||||
rss_url: "rss url string",
|
||||
subscriptions_count: 10,
|
||||
downloads_count: 10,
|
||||
content_category: 'music'
|
||||
})
|
||||
|
||||
type UploadDestination = 'channel' | 'library' | 'podcast'
|
||||
|
||||
type State =
|
||||
{ uploadDestination? : UploadDestination, page: typeof pages[number], files?: string[] }
|
||||
|
||||
// initial state
|
||||
const state = ref<State>({page : 'selectDestination'});
|
||||
|
||||
const pages = ['selectDestination', 'uploadFiles', 'uploadsInProgress'] as const
|
||||
|
||||
// Step 1
|
||||
const destinationSelected = (destination: UploadDestination) =>
|
||||
state.value = {...state.value, uploadDestination:destination, page:'uploadFiles' }
|
||||
|
||||
// Step 2
|
||||
const filesSelected = (e: InputEvent)=>{
|
||||
state.value = {...state.value, files: [] }
|
||||
}
|
||||
|
||||
const modalTitle = computed(()=>
|
||||
({ 'selectDestination' : 'Upload', 'uploadFiles' : 'Select files for upload', 'uploadsInProgress': 'Uploading...'}
|
||||
[state.value.page])
|
||||
)
|
||||
|
||||
// Upload input metadata
|
||||
|
||||
const values = reactive({
|
||||
channel: null,
|
||||
license: null,
|
||||
album: null
|
||||
})
|
||||
|
||||
|
||||
|
||||
const channels = [0,1,2,3,4].map(dummyChannel)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal overPopover
|
||||
:title="modalTitle"
|
||||
v-model="isOpen"
|
||||
>
|
||||
<template #alert v-if="state.page === 'selectDestination'">
|
||||
<Alert yellow>
|
||||
Before uploading, please ensure your files are tagged properly.
|
||||
We recommend using Picard for that purpose.
|
||||
</Alert>
|
||||
</template>
|
||||
|
||||
<Layout flex style="place-content:center" v-if="state.page === 'selectDestination'">
|
||||
<Card small solid secondary title="Music"
|
||||
@click="destinationSelected('channel')"
|
||||
icon="bi-upload"
|
||||
>
|
||||
<template #image>
|
||||
<i class="bi bi-music-note-beamed solid primary" :class="$style.icon"></i>
|
||||
</template>
|
||||
Publish music you make
|
||||
</Card>
|
||||
<Card small solid secondary title="Podcast"
|
||||
@click="destinationSelected('podcast')"
|
||||
icon="bi-upload"
|
||||
>
|
||||
<template #image>
|
||||
<i class="bi bi-mic-fill solid primary" :class="$style.icon"></i>
|
||||
</template>
|
||||
Publish podcasts you make
|
||||
</Card>
|
||||
<Card small solid secondary title="Mix & Share"
|
||||
@click="destinationSelected('library')"
|
||||
icon="bi-upload"
|
||||
>
|
||||
<template #image>
|
||||
<i class="bi bi-headphones solid secondary raised" :class="$style.icon"></i>
|
||||
</template>
|
||||
Host music you listen to
|
||||
</Card>
|
||||
</Layout>
|
||||
|
||||
<Layout stack v-if="state.page === 'uploadFiles'">
|
||||
UPLOAD FILES
|
||||
<!-- <Input
|
||||
type="file"
|
||||
:accept="['.flac', '.ogg', '.opus', '.mp3', '.aac', '.aif', '.aiff', '.m4a'].join(', ')"
|
||||
multiple
|
||||
auto-reset
|
||||
@input="filesSelected"
|
||||
/> -->
|
||||
|
||||
<!-- <UploadForm></UploadForm> -->
|
||||
<FileUpload :library="{ uuid: 'string'}"></FileUpload>
|
||||
{{ state.files }}
|
||||
</Layout>
|
||||
|
||||
<template #actions>
|
||||
<Button secondary
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button disabled v-if="state.page === 'selectDestination'">
|
||||
Continue in background' : 'Save and close'
|
||||
</Button>
|
||||
<Button primary v-if="state.page === 'uploadFiles'">
|
||||
Continue in background' : 'Save and close'
|
||||
</Button>
|
||||
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style module>
|
||||
.icon {
|
||||
font-size:100px;
|
||||
padding:28px;
|
||||
inset:0;
|
||||
display:block;
|
||||
}
|
||||
</style>
|
|
@ -49,6 +49,7 @@ export default defineConfig({
|
|||
text: 'Layout', link: '/components/ui/layout/',
|
||||
items: [
|
||||
{ text: "Spacer", link: "/components/ui/layout/spacer" },
|
||||
{ text: "Section", link: "/components/ui/layout/section" },
|
||||
{ text: "Using `flex`", link: "/components/ui/layout/flex" },
|
||||
{ text: "Using `stack`", link: "/components/ui/layout/stack" },
|
||||
{ text: "Using `grid`", link: "/components/ui/layout/grid" },
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { type Track, type User } from '~/types'
|
||||
|
||||
import Card from '~/components/ui/Card.vue'
|
||||
import Layout from '~/components/ui/Layout.vue'
|
||||
import Toggle from '~/components/ui/Toggle.vue'
|
||||
import Spacer from '~/components/ui/layout/Spacer.vue'
|
||||
import Button from '~/components/ui/Button.vue'
|
||||
import Activity from '~/components/ui/Activity.vue'
|
||||
import Section from '~/components/ui/layout/Section.vue'
|
||||
|
||||
const alignLeft = ref(false)
|
||||
|
||||
const attributes = computed(() => ({
|
||||
style: alignLeft.value ? 'justify-content: start' : ''
|
||||
}))
|
||||
|
||||
const track: Track = {
|
||||
id: 0,
|
||||
fid: "",
|
||||
|
||||
title: 'Some lovely track',
|
||||
description: {
|
||||
content_type: 'text/markdown',
|
||||
text: `**New:** Music for the eyes!`
|
||||
},
|
||||
cover: {
|
||||
uuid: "",
|
||||
urls: {
|
||||
original: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb',
|
||||
medium_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb',
|
||||
large_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb'
|
||||
}
|
||||
},
|
||||
tags: ["example"],
|
||||
uploads: [],
|
||||
downloads_count: 1927549377,
|
||||
artist_credit: [{
|
||||
artist: {
|
||||
id: 0,
|
||||
fid: "",
|
||||
|
||||
name: "The Artist",
|
||||
description: {
|
||||
content_type: 'text/markdown',
|
||||
text: `I'm a musician based on the internet.
|
||||
|
||||
Find all my music on [Funkwhale](https://funkwhale.audio)!`},
|
||||
tags: [],
|
||||
|
||||
content_category: 'music',
|
||||
albums: [],
|
||||
tracks_count: 1,
|
||||
attributed_to: {
|
||||
id: 0,
|
||||
summary: "",
|
||||
preferred_username: "User12345",
|
||||
full_username: "User12345",
|
||||
is_local: false,
|
||||
domain: "myDomain.io"
|
||||
},
|
||||
is_local: false,
|
||||
is_playable: true
|
||||
},
|
||||
credit: "",
|
||||
joinphrase: " and ",
|
||||
index: 22
|
||||
}],
|
||||
disc_number: 7,
|
||||
|
||||
listen_url: "https://funkwhale.audio",
|
||||
creation_date: "12345",
|
||||
attributed_to: {
|
||||
id: 0,
|
||||
summary: "",
|
||||
preferred_username: "User12345",
|
||||
full_username: "User12345",
|
||||
is_local: false,
|
||||
domain: "myDomain.io"
|
||||
},
|
||||
|
||||
is_playable: true,
|
||||
is_local: false
|
||||
}
|
||||
|
||||
const user: User = {
|
||||
id: 12,
|
||||
avatar: {
|
||||
uuid: "",
|
||||
urls: {
|
||||
original: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb',
|
||||
medium_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb',
|
||||
large_square_crop: 'https://images.unsplash.com/photo-1524650359799-842906ca1c06?ixlib=rb-1.2.1&dl=te-nguyen-Wt7XT1R6sjU-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb'
|
||||
}
|
||||
},
|
||||
email: "user12345@example.org",
|
||||
summary: { text: "Hi! I'm Example from The Internet.", content_type: "text" },
|
||||
username: "user12345",
|
||||
full_username: "user12345",
|
||||
instance_support_message_display_date: "?",
|
||||
funkwhale_support_message_display_date: "?",
|
||||
is_superuser: true,
|
||||
privacy_level: "everyone"
|
||||
}
|
||||
</script>
|
||||
|
||||
# Layout section
|
||||
|
||||
<Layout flex>
|
||||
<Toggle v-model="alignLeft" label="Left-align the layout"/>
|
||||
</Layout>
|
||||
|
||||
---
|
||||
|
||||
<div class="preview" style="margin: 0 -40px; padding: 0 25px;">
|
||||
|
||||
<Section small-items h1="Hello" :action="{ text:'more...', to:'/' }">
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
<Layout
|
||||
grid="auto / repeat(auto-fit, calc(46px _ 3 + 32px _ 2))"
|
||||
v-bind="attributes"
|
||||
|
||||
>
|
||||
|
||||
<!-- The title row's width is a multiple of 3 rows -->
|
||||
<Layout flex no-gap
|
||||
style="grid-column: 1 / -1; align-self: baseline;"
|
||||
>
|
||||
<!-- Set distance between baseline and previous row -->
|
||||
<Spacer v
|
||||
:size="64"
|
||||
style="outline:1px solid red; align-self: baseline;"
|
||||
/>
|
||||
<!-- Flexible row content -->
|
||||
<!-- Note that the `h3` uses its padding to create the 24px bottom gap -->
|
||||
<h3 style="align-self: baseline; padding:0 0 24px 10px; margin:0;">
|
||||
Albums
|
||||
</h3>
|
||||
<Spacer grow />
|
||||
<Button ghost thin auto align-self="baseline"
|
||||
style="grid-column:-1;"
|
||||
>
|
||||
Show all
|
||||
</Button>
|
||||
</Layout>
|
||||
|
||||
</Layout>
|
||||
<Layout solid default
|
||||
style="position:relative;"
|
||||
grid="auto / repeat(auto-fit, 46px)"
|
||||
v-bind="attributes"
|
||||
>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
<Card small title="Relatively Long Album Name">
|
||||
Artist Name
|
||||
13 tracks
|
||||
</Card>
|
||||
</Layout>
|
||||
|
||||
<Layout
|
||||
grid="auto / repeat(auto-fit, calc(46px _ 4 + 32px _ 3))"
|
||||
v-bind="attributes"
|
||||
|
||||
>
|
||||
|
||||
<Layout flex no-gap
|
||||
style="grid-column: 1 / -1; align-self: baseline;"
|
||||
>
|
||||
<!-- Set distance between baseline and previous row -->
|
||||
<Spacer v
|
||||
:size="64"
|
||||
style="outline:1px solid red; align-self: baseline;"
|
||||
/>
|
||||
<!-- Flexible row content -->
|
||||
<!-- Note that the `h3` uses its padding to create the 24px bottom gap -->
|
||||
<h3 style="align-self: baseline; padding:0 0 24px 10px; margin:0;">
|
||||
Tracks
|
||||
</h3>
|
||||
<Spacer grow />
|
||||
<Button ghost thin auto align-self="baseline"
|
||||
style="grid-column:-1;"
|
||||
>
|
||||
Show all
|
||||
</Button>
|
||||
</Layout>
|
||||
|
||||
</Layout>
|
||||
<Layout solid default
|
||||
style="position:relative;"
|
||||
grid="auto / repeat(auto-fit, 46px)"
|
||||
v-bind="attributes"
|
||||
>
|
||||
<Activity :track="track" :user="user" />
|
||||
<Activity :track="track" :user="user" />
|
||||
<Activity :track="track" :user="user" />
|
||||
</Layout>
|
||||
</div>
|
|
@ -14,23 +14,21 @@ You can align items inside `flex` and `grid` layouts.
|
|||
|
||||
<template
|
||||
v-for="alignment in ['start', 'center', 'end', 'auto', 'baseline', 'stretch']"
|
||||
:key="alignment"
|
||||
:key="alignment">
|
||||
|
||||
>
|
||||
|
||||
<div style="position:relative;place-self:stretch; grid-area: span 2 / span 2; min-height: 72px; border:.5px solid red; display:grid; grid: 1fr / 1fr; grid-auto-flow: column;"
|
||||
>
|
||||
<Button auto primary :align-self="alignment">🐌</Button>
|
||||
<div style="position:relative;place-self:stretch; grid-area: span 2 / span 2; min-height: 72px; border:.5px solid red; display:grid; grid: 1fr / 1fr; grid-auto-flow: column;"
|
||||
>
|
||||
<Button auto primary :align-self="alignment">🐌</Button>
|
||||
_
|
||||
|
||||
<span style="position:absolute; right: 0; margin-left:-20px; bottom:0;">align-self={{ alignment }}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-for="alignment in ['center', 'stretch']"
|
||||
:key="alignment"
|
||||
|
||||
>
|
||||
:key="alignment">
|
||||
|
||||
<div style="position:relative;place-self:stretch; grid-area: span 2 / span 2; min-height: 72px; border:.5px solid red; display:grid; grid: 1fr / 1fr; grid-auto-flow: column;"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"openapi-typescript": "^7.4.4",
|
||||
"typescript": "^5.7.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
lockfileVersion: "9.0"
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
.:
|
||||
devDependencies:
|
||||
openapi-typescript:
|
||||
specifier: ^7.4.4
|
||||
version: 7.4.4(typescript@5.7.2)
|
||||
typescript:
|
||||
specifier: ^5.7.2
|
||||
version: 5.7.2
|
||||
|
||||
packages:
|
||||
"@babel/code-frame@7.26.2":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==,
|
||||
}
|
||||
engines: { node: ">=6.9.0" }
|
||||
|
||||
"@babel/helper-validator-identifier@7.25.9":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==,
|
||||
}
|
||||
engines: { node: ">=6.9.0" }
|
||||
|
||||
"@redocly/ajv@8.11.2":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==,
|
||||
}
|
||||
|
||||
"@redocly/config@0.17.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-CEmvaJuG7pm2ylQg53emPmtgm4nW2nxBgwXzbVEHpGas/lGnMyN8Zlkgiz6rPw0unASg6VW3wlz27SOL5XFHYQ==,
|
||||
}
|
||||
|
||||
"@redocly/openapi-core@1.26.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-xRuVZqMVRFzqjbUCpOTra4tbnmQMWsya996omZMV3WgD084Z6OWB3FXflhAp93E/yAmbWlWZpddw758AyoaLSw==,
|
||||
}
|
||||
engines: { node: ">=14.19.0", npm: ">=7.0.0" }
|
||||
|
||||
agent-base@7.1.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==,
|
||||
}
|
||||
engines: { node: ">= 14" }
|
||||
|
||||
ansi-colors@4.1.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==,
|
||||
}
|
||||
engines: { node: ">=6" }
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==,
|
||||
}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==,
|
||||
}
|
||||
|
||||
brace-expansion@2.0.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==,
|
||||
}
|
||||
|
||||
change-case@5.4.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==,
|
||||
}
|
||||
|
||||
colorette@1.4.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==,
|
||||
}
|
||||
|
||||
debug@4.4.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==,
|
||||
}
|
||||
engines: { node: ">=6.0" }
|
||||
peerDependencies:
|
||||
supports-color: "*"
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
fast-deep-equal@3.1.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
|
||||
}
|
||||
|
||||
https-proxy-agent@7.0.6:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==,
|
||||
}
|
||||
engines: { node: ">= 14" }
|
||||
|
||||
index-to-position@0.1.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==,
|
||||
}
|
||||
engines: { node: ">=18" }
|
||||
|
||||
js-levenshtein@1.1.6:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==,
|
||||
}
|
||||
engines: { node: ">=0.10.0" }
|
||||
|
||||
js-tokens@4.0.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==,
|
||||
}
|
||||
|
||||
js-yaml@4.1.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==,
|
||||
}
|
||||
hasBin: true
|
||||
|
||||
json-schema-traverse@1.0.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==,
|
||||
}
|
||||
|
||||
minimatch@5.1.6:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==,
|
||||
}
|
||||
engines: { node: ">=10" }
|
||||
|
||||
ms@2.1.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==,
|
||||
}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==,
|
||||
}
|
||||
engines: { node: 4.x || >=6.0.0 }
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
|
||||
openapi-typescript@7.4.4:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-7j3nktnRzlQdlHnHsrcr6Gqz8f80/RhfA2I8s1clPI+jkY0hLNmnYVKBfuUEli5EEgK1B6M+ibdS5REasPlsUw==,
|
||||
}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: ^5.x
|
||||
|
||||
parse-json@8.1.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==,
|
||||
}
|
||||
engines: { node: ">=18" }
|
||||
|
||||
picocolors@1.1.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==,
|
||||
}
|
||||
|
||||
pluralize@8.0.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==,
|
||||
}
|
||||
engines: { node: ">=4" }
|
||||
|
||||
require-from-string@2.0.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==,
|
||||
}
|
||||
engines: { node: ">=0.10.0" }
|
||||
|
||||
supports-color@9.4.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==,
|
||||
}
|
||||
engines: { node: ">=12" }
|
||||
|
||||
tr46@0.0.3:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==,
|
||||
}
|
||||
|
||||
type-fest@4.31.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==,
|
||||
}
|
||||
engines: { node: ">=16" }
|
||||
|
||||
typescript@5.7.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==,
|
||||
}
|
||||
engines: { node: ">=14.17" }
|
||||
hasBin: true
|
||||
|
||||
uri-js-replace@1.0.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==,
|
||||
}
|
||||
|
||||
webidl-conversions@3.0.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==,
|
||||
}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==,
|
||||
}
|
||||
|
||||
yaml-ast-parser@0.0.43:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==,
|
||||
}
|
||||
|
||||
yargs-parser@21.1.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==,
|
||||
}
|
||||
engines: { node: ">=12" }
|
||||
|
||||
snapshots:
|
||||
"@babel/code-frame@7.26.2":
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier": 7.25.9
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
"@babel/helper-validator-identifier@7.25.9": {}
|
||||
|
||||
"@redocly/ajv@8.11.2":
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
uri-js-replace: 1.0.1
|
||||
|
||||
"@redocly/config@0.17.1": {}
|
||||
|
||||
"@redocly/openapi-core@1.26.1(supports-color@9.4.0)":
|
||||
dependencies:
|
||||
"@redocly/ajv": 8.11.2
|
||||
"@redocly/config": 0.17.1
|
||||
colorette: 1.4.0
|
||||
https-proxy-agent: 7.0.6(supports-color@9.4.0)
|
||||
js-levenshtein: 1.1.6
|
||||
js-yaml: 4.1.0
|
||||
minimatch: 5.1.6
|
||||
node-fetch: 2.7.0
|
||||
pluralize: 8.0.0
|
||||
yaml-ast-parser: 0.0.43
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
agent-base@7.1.3: {}
|
||||
|
||||
ansi-colors@4.1.3: {}
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
brace-expansion@2.0.1:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
change-case@5.4.4: {}
|
||||
|
||||
colorette@1.4.0: {}
|
||||
|
||||
debug@4.4.0(supports-color@9.4.0):
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
optionalDependencies:
|
||||
supports-color: 9.4.0
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
|
||||
https-proxy-agent@7.0.6(supports-color@9.4.0):
|
||||
dependencies:
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.0(supports-color@9.4.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
index-to-position@0.1.2: {}
|
||||
|
||||
js-levenshtein@1.1.6: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
js-yaml@4.1.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
||||
minimatch@5.1.6:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
openapi-typescript@7.4.4(typescript@5.7.2):
|
||||
dependencies:
|
||||
"@redocly/openapi-core": 1.26.1(supports-color@9.4.0)
|
||||
ansi-colors: 4.1.3
|
||||
change-case: 5.4.4
|
||||
parse-json: 8.1.0
|
||||
supports-color: 9.4.0
|
||||
typescript: 5.7.2
|
||||
yargs-parser: 21.1.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
parse-json@8.1.0:
|
||||
dependencies:
|
||||
"@babel/code-frame": 7.26.2
|
||||
index-to-position: 0.1.2
|
||||
type-fest: 4.31.0
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
pluralize@8.0.0: {}
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
supports-color@9.4.0: {}
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
type-fest@4.31.0: {}
|
||||
|
||||
typescript@5.7.2: {}
|
||||
|
||||
uri-js-replace@1.0.1: {}
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
dependencies:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
|
||||
yaml-ast-parser@0.0.43: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
Loading…
Reference in New Issue