feat(ui): allow custom width (via composable props)
This commit is contained in:
		
							parent
							
								
									a588726a54
								
							
						
					
					
						commit
						2ebda850c7
					
				|  | @ -105,7 +105,7 @@ const federationEnabled = computed(() => { | ||||||
| 
 | 
 | ||||||
|       <Card :title="t('components.About.header.signup')" |       <Card :title="t('components.About.header.signup')" | ||||||
|         v-if="!store.state.auth.authenticated" |         v-if="!store.state.auth.authenticated" | ||||||
|         style="--width:256px" |         width="256px" | ||||||
|       > |       > | ||||||
| 
 | 
 | ||||||
|         <template v-if="openRegistrations"> |         <template v-if="openRegistrations"> | ||||||
|  | @ -156,7 +156,7 @@ const federationEnabled = computed(() => { | ||||||
| 
 | 
 | ||||||
|       <Card :title="t('components.About.message.greeting', {username: store.state.auth.username})" |       <Card :title="t('components.About.message.greeting', {username: store.state.auth.username})" | ||||||
|         v-else |         v-else | ||||||
|         style="--width:256px" |         width= "256px" | ||||||
|       > |       > | ||||||
| 
 | 
 | ||||||
|         <p v-if="defaultUploadQuota"> |         <p v-if="defaultUploadQuota"> | ||||||
|  | @ -171,7 +171,7 @@ const federationEnabled = computed(() => { | ||||||
|         </Card> |         </Card> | ||||||
| 
 | 
 | ||||||
|       <Card :title="podName" |       <Card :title="podName" | ||||||
|         style="--width:256px" |         width="256px" | ||||||
|       > |       > | ||||||
|         <section |         <section | ||||||
|           :class="['ui', 'head', {'with-background': banner}, 'vertical', 'center', 'aligned', 'stripe', 'segment']" |           :class="['ui', 'head', {'with-background': banner}, 'vertical', 'center', 'aligned', 'stripe', 'segment']" | ||||||
|  | @ -234,7 +234,7 @@ const federationEnabled = computed(() => { | ||||||
| 
 | 
 | ||||||
|     <Layout flex style="justify-content: center;"> |     <Layout flex style="justify-content: center;"> | ||||||
| 
 | 
 | ||||||
|       <Card style="--width:256px" |       <Card width="256px" | ||||||
|         to="/" |         to="/" | ||||||
|         :title="t('components.About.header.publicContent')" |         :title="t('components.About.header.publicContent')" | ||||||
|         icon="bi-box-arrow-up-right" |         icon="bi-box-arrow-up-right" | ||||||
|  | @ -243,7 +243,7 @@ const federationEnabled = computed(() => { | ||||||
|         {{ t('components.About.description.publicContent') }} |         {{ t('components.About.description.publicContent') }} | ||||||
|       </Card> |       </Card> | ||||||
| 
 | 
 | ||||||
|       <Card style="--width:256px" |       <Card width="256px" | ||||||
|         :title="t('components.About.link.findOtherPod')" |         :title="t('components.About.link.findOtherPod')" | ||||||
|         to="https://funkwhale.audio/#get-started" |         to="https://funkwhale.audio/#get-started" | ||||||
|         icon="bi-box-arrow-up-right" |         icon="bi-box-arrow-up-right" | ||||||
|  | @ -251,7 +251,7 @@ const federationEnabled = computed(() => { | ||||||
|           {{ t('components.About.description.publicContent') }} |           {{ t('components.About.description.publicContent') }} | ||||||
|       </Card> |       </Card> | ||||||
| 
 | 
 | ||||||
|       <Card style="--width:256px" |       <Card width="256px" | ||||||
|         :title="t('components.About.header.findApp')" |         :title="t('components.About.header.findApp')" | ||||||
|         to="https://funkwhale.audio/apps" |         to="https://funkwhale.audio/apps" | ||||||
|         icon="bi-box-arrow-up-right" |         icon="bi-box-arrow-up-right" | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import type { KeysOfUnion } from "type-fest" | import type { Entries, KeysOfUnion } from "type-fest" | ||||||
| 
 | 
 | ||||||
| export type WidthProps = | export type WidthProps = | ||||||
|   | { minContent?: true } |   | { minContent?: true } | ||||||
|  | @ -8,9 +8,10 @@ export type WidthProps = | ||||||
|   | { medium?: true } |   | { medium?: true } | ||||||
|   | { auto?: true } |   | { auto?: true } | ||||||
|   | { full?: true } |   | { full?: true } | ||||||
|  |   | { width?: string } | ||||||
| export type Key = KeysOfUnion<WidthProps> | export type Key = KeysOfUnion<WidthProps> | ||||||
| 
 | 
 | ||||||
| const styles : Record<Key, string> = { | const styles = { | ||||||
|   minContent: 'width: min-content;', |   minContent: 'width: min-content;', | ||||||
|   tiny: "width: 124px; grid-column: span 2;", |   tiny: "width: 124px; grid-column: span 2;", | ||||||
|   buttonWidth: "width: 136px; grid-column: span 2; flex-grow:0;", |   buttonWidth: "width: 136px; grid-column: span 2; flex-grow:0;", | ||||||
|  | @ -18,7 +19,19 @@ const styles : Record<Key, string> = { | ||||||
|   medium: "width: 280px; grid-column: span 4;", |   medium: "width: 280px; grid-column: span 4;", | ||||||
|   auto: "width: auto;", |   auto: "width: auto;", | ||||||
|   full: "width: auto; grid-column: 1 / -1; align-self: auto; flex-grow:1;", |   full: "width: auto; grid-column: 1 / -1; align-self: auto; flex-grow:1;", | ||||||
| }; |   width: (w:string)=>`width: ${w}; flex-grow:0;`, | ||||||
|  | } as const satisfies Record<Key, string|((w:string)=>string)>; | ||||||
|  | 
 | ||||||
|  | const getStyle = (props : Partial<WidthProps>) => (key : Key) => | ||||||
|  |   (typeof styles[key] !== 'string' && key in props) ? | ||||||
|  |     styles[key]( | ||||||
|  |       // TODO: Make the typescript compiler understand `key in props`
 | ||||||
|  |       // @ts-ignore
 | ||||||
|  |       props[key] | ||||||
|  |   ) | ||||||
|  |   : styles[key] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| // All keys are exclusive
 | // All keys are exclusive
 | ||||||
| const conflicts: Set<Key>[] = [ | const conflicts: Set<Key>[] = [ | ||||||
|  | @ -30,22 +43,25 @@ const conflicts: Set<Key>[] = [ | ||||||
|  * Widths are designed to work both in a page-grid context and in a flex or normal context. |  * Widths are designed to work both in a page-grid context and in a flex or normal context. | ||||||
|  * |  * | ||||||
|  * (1) Add `& WidthProps` to your `Props` type |  * (1) Add `& WidthProps` to your `Props` type | ||||||
|  * (2) Call `v-bind="propsToWidth(props)"` on your component template |  * (2) Call `v-bind="width(props)"` on your component template | ||||||
|  * (3) Now your component accepts width props such as `small`, `medium`, `stretch`. |  * (3) Now your component accepts width props such as `small`, `medium`, `stretch`. | ||||||
|  * |  * | ||||||
|  * @param props Your component's props (or ...rest props if you have destructured them already) |  * @param props Your component's props (or ...rest props if you have destructured them already) | ||||||
|  * @returns the corresponding `style` object |  * @returns the corresponding `{ style }` object | ||||||
|  */ |  */ | ||||||
| export const width = (props: Partial<WidthProps>, defaults: Key[] = []) => ({ | export const width = <TProps extends Partial<WidthProps>>( | ||||||
|  |   props: TProps, | ||||||
|  |   defaults: Key[] = [] | ||||||
|  | ) => ({ | ||||||
|   style: |   style: | ||||||
|     Object.entries(props).reduce( |     (Object.entries(props) as Entries<TProps>).reduce( | ||||||
|       ((acc, [key, value]) => |       ((acc, [key, value]) => | ||||||
|         value && key in styles ? |         value && key in styles ? | ||||||
|           acc.filter(accKey => !conflicts.find(set => set.has(accKey) && set.has(key as Key))) |           acc.filter(accKey => !conflicts.find(set => set.has(accKey) && set.has(key))) | ||||||
|             .concat([key as Key]) |             .concat([key]) | ||||||
|           : acc |           : acc | ||||||
|       ), |       ), | ||||||
|       defaults |       defaults | ||||||
|     ).map(key => styles[key]) |     ).map(getStyle(props)) | ||||||
|      .join(' ') |      .join(' ') | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ const here = route.path | ||||||
| <Card small title='small' /> | <Card small title='small' /> | ||||||
| <Card medium title='medium' /> | <Card medium title='medium' /> | ||||||
| <Card auto title='auto' /> | <Card auto title='auto' /> | ||||||
|  | <Card width="170.5px" title='width=170.5px' /> | ||||||
| <Card full title='full' /> | <Card full title='full' /> | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | @ -35,5 +36,16 @@ const here = route.path | ||||||
|   <Card small title='small' /> |   <Card small title='small' /> | ||||||
|   <Card medium title='medium' /> |   <Card medium title='medium' /> | ||||||
|   <Card auto title='auto' /> |   <Card auto title='auto' /> | ||||||
|  |   <Card width="170.5px" title='width=170.5px' /> | ||||||
|   <Card full title='full' /> |   <Card full title='full' /> | ||||||
| </Layout> | </Layout> | ||||||
|  | 
 | ||||||
|  | ## Widths in the grid | ||||||
|  | 
 | ||||||
|  | ::: details Default widths | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | 
 | ||||||
|  | ::: | ||||||
|  | 
 | ||||||
|  | [Designing Pages — The grid](designing-pages#grid) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 upsiflu
						upsiflu