Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 58 additions & 5 deletions docs/content/3.features.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,70 @@ definePageMeta({

::

## Components
## Ionic Framework components

All Ionic Vue components should be auto-imported throughout your app. (If you find one that isn't, please open an issue.) Although your IDE should be aware of these everywhere, they are not globally registered and are only imported within the components that use them.
All Ionic Vue components should be auto-imported throughout your app. (If you find one that isn't, please open an issue.) Although your IDE should be aware of these everywhere, they are not globally registered and are only imported within the components that use them. For more on how component imports work, see the [Nuxt documentation](https://v3.nuxtjs.org/guide/directory-structure/components#components-directory).

For more on how component imports work, see the [Nuxt documentation](https://v3.nuxtjs.org/guide/directory-structure/components#components-directory).
## Module utility components

Module also offers few components made for easier and more seamless way to integrate Ionic's composables or functions into your Nuxt app.

### `IonAnimation` component

Component made specifically to make usage of Ionic's `createAnimation` easier. It has almost 1 to 1 props matching as your usual animation object. For more see [official Ionic docs](https://ionicframework.com/docs/utilities/animations) or check out [playground examples](https://github.com/danielroe/nuxt-ionic/blob/main/playground/pages/tabs/tab4.vue)

Instead of using the function manually:

```vue
<script setup lang="ts">
// Template ref of your element
const squareRef = ref()

// Your animation object
const animation = createAnimation()
.addElement(squareRef.value)
.duration(3000)
.iterations(Infinity)
.keyframes([
{ offset: 0, background: 'red' },
{ offset: 0.72, background: 'var(--background)' },
{ offset: 1, background: 'green' },
])

onMounted(() => {
animation.play()
})
</script>
```

You can delegate all that logic to the component:

```vue
<template>
<IonAnimation
:duration="3000"
:iterations="Infinity"
:keyframes="[
{ offset: 0, background: 'red' },
{ offset: 0.72, background: 'var(--background)' },
{ offset: 1, background: 'green' },
]"
playOnMount
>
<!-- Content to animate -->
</IonAnimation>
</template>
```

::alert{type=info}
Currently component doesn't support grouped and chained animations. For that usage we still recommend using `createAnimation` by itself
::

## Icons

Icons are auto-imported from `ionicons/icons` by default, following the pattern of camel case naming with `ionicons` in front of the original icon name from the [official icons website](https://ionic.io/ionicons).

For example, instead of this
For example, instead of this:

```vue [component.vue]
<script setup lang="ts">
Expand All @@ -47,7 +100,7 @@ import { image, squareSharp, triangleOutline } from 'ionicons/icons'
</template>
```

You would write this
You would write this:

```vue [component.vue]
<template>
Expand Down
28 changes: 14 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@
"postpublish": "pinst --enable"
},
"dependencies": {
"@capacitor/cli": "^4.0.1",
"@capacitor/core": "^4.0.1",
"@capacitor/cli": "^4.1.0",
"@capacitor/core": "^4.1.0",
"@ionic/cli": "^6.20.1",
"@ionic/vue": "^6.2.2",
"@ionic/vue-router": "^6.2.2",
"@ionic/vue": "^6.2.4",
"@ionic/vue-router": "^6.2.4",
"@kevinmarrec/nuxt-pwa": "^0.4.2",
"@nuxt/kit": "^3.0.0-rc.8",
"ionicons": "^6.0.2",
"pathe": "^0.3.4",
"pkg-types": "^0.3.3",
"ionicons": "^6.0.3",
"pathe": "^0.3.5",
"pkg-types": "^0.3.4",
"ufo": "^0.8.5",
"unimport": "^0.6.7"
},
Expand All @@ -71,12 +71,12 @@
"@nuxt/schema": "3.0.0-rc.8",
"@nuxt/test-utils": "3.0.0-rc.8",
"@nuxtjs/eslint-config-typescript": "^10.0.0",
"@release-it/conventional-changelog": "^5.0.0",
"@types/node": "^18.7.2",
"@vitest/coverage-c8": "^0.22.0",
"@release-it/conventional-changelog": "^5.1.0",
"@types/node": "^18.7.14",
"@vitest/coverage-c8": "^0.22.1",
"c8": "^7.12.0",
"conventional-changelog-conventionalcommits": "^5.0.0",
"eslint": "^8.22.0",
"eslint": "^8.23.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"expect-type": "^0.13.0",
Expand All @@ -85,9 +85,9 @@
"nuxt": "^3.0.0-rc.8",
"pinst": "^3.0.0",
"prettier": "^2.7.1",
"release-it": "^15.3.0",
"typescript": "^4.7.4",
"vitest": "^0.22.0",
"release-it": "^15.4.0",
"typescript": "^4.8.2",
"vitest": "^0.22.1",
"vue": "^3.2.37"
},
"resolutions": {
Expand Down
5 changes: 5 additions & 0 deletions playground/pages/tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ useHead({
<ion-icon :icon="ioniconsBulbOutline" />
<ion-label>Tab 3</ion-label>
</ion-tab-button>

<ion-tab-button tab="tab4" href="/tabs/tab4">
<ion-icon :icon="ioniconsAccessibilityOutline" />
<ion-label>Animation examples</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
</ion-content>
Expand Down
2 changes: 0 additions & 2 deletions playground/pages/tabs/tab3.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
<ion-title size="large">Tab 3</ion-title>
</ion-toolbar>
</ion-header>

<ExploreContainer name="Tab 3 page" />
</ion-content>
</ion-page>
</template>

233 changes: 233 additions & 0 deletions playground/pages/tabs/tab4.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
<template>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Tab 3</ion-title>
</ion-toolbar>
</ion-header>
<ion-content :fullscreen="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Tab 3</ion-title>
</ion-toolbar>
</ion-header>

<div class="animations-grid">
<section>
<IonLabel color="primary">
<strong>Basic animation</strong>
</IonLabel>
<IonAnimation
ref="animation1"
v-slot="{ animation }"
:duration="2000"
:fromTo="[
{ property: 'opacity', fromValue: '1', toValue: '0.2' },
{ property: 'transform', fromValue: 'translateX(0px)', toValue: 'translateX(-50px)' },
]"
fill="forwards"
>
<div class="red-square"></div>

<div class="buttons">
<IonButton @click="animation.play()">Play</IonButton>
<IonButton @click="animation.pause()">Pause</IonButton>
<IonButton @click="animation.stop()">Stop</IonButton>
</div>
</IonAnimation>
</section>

<section>
<IonLabel color="primary">
<strong>Keyframes animation</strong>
</IonLabel>
<IonAnimation
v-slot="{ animation }"
:duration="3000"
:keyframes="[
{ offset: 0, transform: 'scale(1) translate(0, 0)' },
{ offset: 0.4, transform: 'scale(1.05) translate(15px, 15px)' },
{ offset: 0.6, transform: 'scale(1.05) translate(-30px, 15px)' },
{ offset: 1, transform: 'scale(1) translate(0, 0)' },
]"
fill="none"
>
<div class="blue-square"></div>

<div class="buttons">
<IonButton @click="animation.play()">Play</IonButton>
<IonButton @click="animation.pause()">Pause</IonButton>
<IonButton @click="animation.stop()">Stop</IonButton>
</div>
</IonAnimation>
</section>

<section>
<IonLabel color="primary">
<strong>Animation that repeats forever</strong>
</IonLabel>
<IonAnimation
v-slot="{ animation }"
:duration="1000"
:keyframes="[
{ offset: 0, transform: 'scale(1)' },
{ offset: 0.75, transform: 'scale(1.05)' },
{ offset: 1, transform: 'scale(1)' },
]"
:iterations="Infinity"
>
<div class="green-square"></div>

<div class="buttons">
<IonButton @click="animation.play()">Play</IonButton>
<IonButton @click="animation.pause()">Pause</IonButton>
<IonButton @click="animation.stop()">Stop</IonButton>
</div>
</IonAnimation>
</section>

<section>
<IonLabel color="primary">
<strong>Animation with style hooks</strong>
</IonLabel>
<IonAnimation
v-slot="{ animation }"
:duration="2000"
:keyframes="[
{ offset: 0, transform: 'scale(1)' },
{ offset: 0.75, transform: 'scale(1.1)' },
{ offset: 1, transform: 'scale(1)' },
]"
:beforeStyles="{
opacity: 0.5,
}"
:afterClearStyles="['opacity']"
:afterStyles="{
transform: 'scale(0.9)',
}"
:beforeClearStyles="['transform']"
fill="none"
>
<div class="red-square"></div>

<div class="buttons">
<IonButton @click="animation.play()">Play</IonButton>
<IonButton @click="animation.pause()">Pause</IonButton>
<IonButton @click="animation.stop()">Stop</IonButton>
</div>
</IonAnimation>
</section>

<section>
<IonLabel color="primary">
<strong>Animation with specific easing</strong>
</IonLabel>
<IonAnimation
v-slot="{ animation }"
:duration="2000"
:keyframes="[
{
offset: 0,
transform: 'rotate(0)',
},
{
offset: 0.5,
transform: 'rotate(60deg)',
},
{
offset: 1,
transform: 'rotate(0)',
},
]"
easing="cubic-bezier(.7,.55,0,1.15)"
>
<div class="blue-square"></div>

<div class="buttons">
<IonButton @click="animation.play()">Play</IonButton>
<IonButton @click="animation.pause()">Pause</IonButton>
<IonButton @click="animation.stop()">Stop</IonButton>
</div>
</IonAnimation>
</section>

<section>
<IonLabel color="primary">
<strong>Reversed animation direction</strong>
</IonLabel>
<IonAnimation
v-slot="{ animation }"
:duration="3000"
:keyframes="[
{ offset: 0, transform: 'scale(1)' },
{ offset: 0.3, transform: 'scale(1.2)' },
{ offset: 0.6, transform: 'scale(1.05)' },
{ offset: 0.9, transform: 'scale(0.8)' },
{ offset: 1, transform: 'scale(1)' },
]"
direction="reverse"
easing="ease-in"
>
<div class="green-square"></div>

<div class="buttons">
<IonButton @click="animation.play()">Play</IonButton>
<IonButton @click="animation.pause()">Pause</IonButton>
<IonButton @click="animation.stop()">Stop</IonButton>
</div>
</IonAnimation>
</section>
</div>
</ion-content>
</ion-page>
</template>

<style scoped>
:root {
--animation-color: purple;
}

.animations-grid {
padding: 3em;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(460px, 1fr));
grid-auto-flow: row;
row-gap: 4em;
align-items: center;
justify-items: center;
text-align: center;
}

.animations-grid > *:nth-child(2) {
margin-left: auto;
margin-right: auto;
}

.buttons {
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
}

.red-square {
width: 250px;
height: 250px;
background-color: red;
border-radius: 1em;
}

.blue-square {
width: 250px;
height: 250px;
background-color: blue;
border-radius: 1em;
}

.green-square {
width: 250px;
height: 250px;
background-color: green;
border-radius: 1em;
}
</style>
Loading