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
134 changes: 134 additions & 0 deletions contributed/vue-starter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Vue Starter - Adobe Express Add-on

A sample Adobe Express Add-on that demonstrates how to build an add-on using Vue.js and properly access the Adobe Express Add-on SDK.

## What This App Does

This starter sample demonstrates a best practice approach for integrating Vue.js with the Adobe Express Add-on SDK:

1. **SDK Integration via Dependency Injection**: The app uses Vue's provide/inject pattern to make the Adobe Express SDK available throughout the component tree.

2. **Asynchronous SDK Loading**: The Add-on UI SDK is loaded asynchronously and initialized before the Vue app is mounted, ensuring that the SDK is ready for use when components need it.

3. **Simple Interactive UI**: A single button demonstrates reactive UI updates when clicked, displaying information about the loaded SDK.

4. **Component Structure**: Follows Vue.js best practices with a clean separation of concerns between template, logic, and styling using Single-File Components.

## Key Implementation Details

The application implements the following pattern:

1. **index.js**: Loads the SDK asynchronously using dynamic imports, makes it available via Vue's provide/inject system, and mounts the app.

2. **App.vue**: Injects the SDK and uses it to display details in response to user interaction.

## Overview

This project showcases:

- Vue.js integration with Adobe Express Add-ons
- Single-file component (SFC) architecture
- Proper SDK injection pattern using Vue's dependency injection
- Asynchronous SDK initialization
- Webpack build configuration for Vue.js
- ES modules with proper import/export syntax

## Technologies Used

- HTML
- CSS
- JavaScript
- Vue.js 3.x (Composition API)
- Adobe Express Add-on SDK
- Webpack 5
- ES Modules

## Features

- Reactive UI components with Vue.js
- Adobe Express Add-on SDK integration via dependency injection
- Button component that displays SDK information when clicked
- Fully commented code for beginners to understand Vue.js concepts

## Project Structure

- `src/`: Source code
- `App.vue`: Main Vue component with detailed comments explaining Vue concepts
- `index.js`: Entry point that loads the SDK and mounts the Vue app
- `index.html`: HTML template with the Vue mounting point
- `manifest.json`: Add-on manifest defining the add-on properties

## Getting Started

### Prerequisites

- Node.js 18.x or higher
- npm 9.x or higher
- Adobe Express account

### Installation

1. Clone the repository
2. Install dependencies:
```
npm install
```

### Development

Start the development server:
```
npm run start
```

This will launch a development server and open the add-on in your browser.

### Building

Build the add-on for production:
```
npm run build
```

### Packaging

Create a distributable package:
```
npm run package
```

## Working with the Add-on

1. After starting the development server, the add-on will appear in your browser
2. Click the "Click me" button to see information about the Adobe Express Add-on SDK
3. The button text will change to "Clicked" and the SDK details will be logged to the console

## Learning from this Example

This project is heavily commented to help beginners understand:

1. **Vue.js Fundamentals**: Component structure, reactive data, event handling
2. **Composition API**: Using `ref`, `onMounted`, and `inject`
3. **SDK Integration**: Proper patterns for initializing and using the Adobe Express Add-on SDK
4. **ES Module Usage**: Modern JavaScript import/export syntax

## Customization

You can use this sample as a starting point for your own Adobe Express Add-ons with Vue.js:

1. Modify `App.vue` to create your own components and UI
2. Add additional Vue components as needed
3. Update the manifest.json to change your add-on's metadata

## Troubleshooting

- If you encounter module resolution issues, check that "type": "module" is correctly set in package.json
- For webpack configuration issues, review webpack.config.js
- If the SDK isn't available in your components, ensure you're using the inject pattern correctly

## Resources

- [Adobe Express Add-ons Documentation](https://developer.adobe.com/express/add-ons/)
- [Vue.js Documentation](https://vuejs.org/guide/introduction.html)
- [Vue Composition API Guide](https://vuejs.org/guide/extras/composition-api-faq.html)
- [Webpack Documentation](https://webpack.js.org/concepts/)
42 changes: 42 additions & 0 deletions contributed/vue-starter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "vue-starter",
"version": "1.0.0",
"description": "Adobe Creative Cloud Web Add-on using Vue.js",
"type": "module",
"scripts": {
"clean": "ccweb-add-on-scripts clean",
"build": "ccweb-add-on-scripts build --use webpack",
"start": "ccweb-add-on-scripts start --use webpack",
"package": "ccweb-add-on-scripts package --use webpack"
},
"keywords": [
"Adobe",
"Creative Cloud Web",
"Add-on",
"panel",
"Vue.js"
],
"dependencies": {
"vue": "^3.4.21"
},
"devDependencies": {
"@adobe/ccweb-add-on-scripts": "^3.0.0",
"@types/adobe__ccweb-add-on-sdk": "^1.3.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/compiler-sfc": "^3.4.21",
"typescript": "^5.4.2",
"vite": "^5.1.6",
"babel-loader": "9.1.3",
"@babel/core": "7.23.3",
"@babel/preset-env": "7.23.3",
"@babel/preset-react": "7.23.3",
"copy-webpack-plugin": "11.0.0",
"css-loader": "6.8.1",
"html-webpack-plugin": "5.5.3",
"style-loader": "3.3.3",
"vue-loader": "^17.4.2",
"vue-style-loader": "^4.1.3",
"webpack": "5.89.0",
"webpack-cli": "5.1.4"
}
}
96 changes: 96 additions & 0 deletions contributed/vue-starter/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<template>
<!--
This is the template section where we define the HTML structure of our component.
In Vue, we use a single-file component (SFC) approach that combines template, logic, and styles.
-->
<!--
Please note that this document does not use the spectrum web components theme for Express.
You may use "addOnUISdk.app.ui.theme" to get the current theme and style accordingly.
-->

<div class="container">
<!--
Vue directives start with ':' or 'v-' and provide special functionality:
- :disabled is a shorthand for v-bind:disabled, which binds the disabled attribute to the isReady state
- @click is a shorthand for v-on:click, which attaches a click event handler
- {{ buttonText }} is a template expression that displays the value of buttonText reactive variable
-->
<button :disabled="!isReady" @click="handleClick">{{ buttonText }}</button>
</div>
</template>

<script>
// Import necessary functions from Vue's Composition API
import { ref, onMounted, readonly, inject } from 'vue'

export default {
// Name of the component for debugging purposes
name: 'App',

// The setup() function is the entry point for Vue's Composition API
setup() {
// Create reactive state variables using ref()
// These will automatically update the UI when their values change
const isReady = ref(false); // Controls button disabled state
const buttonText = ref('Click me');

// Inject the Adobe Express SDK that was provided in index.js
// This makes the SDK available only in this component without global variables
const addOnUISdk = inject('addOnUISdk');

// Define the function that runs when the button is clicked
const handleClick = async () => {
// Update the button text (UI will automatically update)
buttonText.value = 'Clicked'

// Log the SDK details to the console
console.table(JSON.stringify(addOnUISdk));
}

// onMounted lifecycle hook runs after the component is mounted to the DOM
onMounted(async () => {
console.log("App.vue is ready for use.")
// Enable the button once the component is mounted
isReady.value = true
});

// Values returned from setup() are exposed to the template
return {
isReady,
buttonText,
handleClick
}
}
}
</script>

<style>
/* CSS styles for the component */
.container {
margin: 24px;
display: flex;
flex-direction: column;
}

button {
background-color: rgb(82, 88, 228); /* Adobe blue color */
border-color: rgb(82, 88, 228);
border-radius: 16px;
border-style: solid;
color: rgb(255, 255, 255); /* White text */
font-family: sans-serif;
height: 32px;
}

/* Styles for the disabled button state */
button:disabled {
background-color: rgb(177, 177, 177); /* Gray color when disabled */
border-color: rgb(177, 177, 177);
}

/* Hover effect for the button (only when not disabled) */
button:not([disabled]):hover {
background-color: rgb(64, 70, 202); /* Darker blue on hover */
cursor: pointer;
}
</style>
33 changes: 33 additions & 0 deletions contributed/vue-starter/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Get started with Add-on development using Vue.js" />
<meta name="keywords" content="Adobe, Express, Add-On, Vue.js" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Get Started with Vue</title>
</head>
<body>
<!--
This is the mounting point for our Vue application.
The <div id="app"></div> element is where Vue will render everything.

When our index.js file runs app.mount('#app'), Vue attaches to this div
and replaces its contents with the rendered components.

In single-page applications (SPAs) like this one, Vue manages the entire UI
from this single mounting point.
-->
<div id="app"></div>

<!--
The main JavaScript entry point for our application.
This script is processed by webpack, which bundles all our JavaScript
including Vue components into a single file.

The "type="module"" attribute enables ES modules syntax (import/export)
in the browser.
-->
<script type="module" src="index.js"></script>
</body>
</html>
38 changes: 38 additions & 0 deletions contributed/vue-starter/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createApp } from 'vue'
import App from './App.vue'

// Create the app instance
const app = createApp(App)

/**
* Load the Adobe Express Add-on SDK and initialize the Vue app
*
* This function:
* 1. Imports the Add-on SDK
* 2. Waits for the SDK to be ready
* 3. Makes the SDK available to all components via provide/inject
* 4. Mounts the Vue app to the DOM
*/
const loadSdk = async () => {
// Dynamically import the SDK
// Using dynamic import (import()) allows loading the module at runtime
const sdkModule = await import('https://new.express.adobe.com/static/add-on-sdk/sdk.js')

// Extract the default export which is the SDK itself
const addOnUISdk = sdkModule.default

// Wait for the SDK to be ready before proceeding
// This ensures that all SDK features are available
await addOnUISdk.ready

// Use Vue's dependency injection system to make the SDK available to all components
// This is preferred over global variables as it's more maintainable and testable
app.provide('addOnUISdk', addOnUISdk)

// Mount the Vue app to the DOM element with id 'app'
// This connects our Vue app to the HTML <div id="app"></div> in index.html
app.mount('#app')
}

// Initialize the app
loadSdk()
21 changes: 21 additions & 0 deletions contributed/vue-starter/src/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"testId": "6c9f9198-6f36-47f0-9786-5f811002987e",
"name": "Vue Starter",
"version": "1.0.0",
"manifestVersion": 2,
"requirements": {
"apps": [
{
"name": "Express",
"apiVersion": 1
}
]
},
"entryPoints": [
{
"type": "panel",
"id": "panel1",
"main": "index.html"
}
]
}
14 changes: 14 additions & 0 deletions contributed/vue-starter/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"module": "ESNext",
"moduleResolution": "node",
"outDir": "dist",
"target": "ESNext",
"useDefineForClassFields": false
},
"exclude": ["node_modules"],
"include": ["src/**/*"]
}
Loading