Skip to content

Commit

Permalink
feat: Add sample with some more features using Next JS (React + TS) (#18
Browse files Browse the repository at this point in the history
)

* feat: Add sample with some more features using Next JS (React + TS)

* fix: update CPN to published version

* fix: respond to review feedback + prettier

* test: verify that deployment from this branch still works as expected

* fix: add licenses and rm branch-specific deployment

* docs: update root README to reference new sample

* fix: redeploy with terms, privacy, and support at site root

* fix: license and stop publishing
  • Loading branch information
teddyward committed Sep 9, 2024
1 parent d9f63f9 commit 9e106c7
Show file tree
Hide file tree
Showing 27 changed files with 689 additions and 57 deletions.
34 changes: 17 additions & 17 deletions .github/workflows/publish-sample-add-ons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Deploy sample Add-ons to GitHub Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
branches: ['main']

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -17,7 +17,7 @@ permissions:
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
group: 'pages'
cancel-in-progress: false

jobs:
Expand All @@ -29,21 +29,21 @@ jobs:
node-version: [22.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: addons-web-sdk/samples/package-lock.json
- run: npm run build
working-directory: addons-web-sdk/samples
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: page
path: addons-web-sdk/samples/dist
if-no-files-found: error
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: addons-web-sdk/samples/package-lock.json
- run: npm run build
working-directory: addons-web-sdk/samples
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: page
path: addons-web-sdk/samples/dist
if-no-files-found: error
deploy:
runs-on: ubuntu-latest
needs: build
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Build outputs for sample Meet Add-ons
**/dist
**/dist/*/
**/node_modules
**/.DS_Store
9 changes: 5 additions & 4 deletions addons-web-sdk/samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
This directory contains code for example add-ons, which you can fork to create
your own.

| Sample | Description |
| ------------ | ----------------------------------------------------- |
| hello-world | Vanilla JS; renders a hello world div. |
| hello-world-next-js | React + TS + NextJS; renders a hello world div. |
| Sample | Description |
| ------------------- | --------------------------------------------------------------------- |
| hello-world | Vanilla JS; renders a hello world div. |
| hello-world-next-js | React + TS + Next.js; renders a hello world div. |
| animation-next-js | React + TS + Next.js; uses more add-on features to show an animation. |
1 change: 1 addition & 0 deletions addons-web-sdk/samples/animation-next-js/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_DEBUG=1
5 changes: 5 additions & 0 deletions addons-web-sdk/samples/animation-next-js/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# next.js
/.next
out

certificates
5 changes: 5 additions & 0 deletions addons-web-sdk/samples/animation-next-js/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pretty Colors: Next.js Add-on

This is a [Meet Add-on](https://developers.google.com/meet/add-ons/guides/overview) built in [Next.js](https://nextjs.org/). This add-on displays an animation that is intended to create a simple "shimmer" effect based on the color that each call participant selects. This add-on only exists to show more features of Google Meet Add-ons than can be found at [googleworkspace/meet/addons-web-sdk/samples/hello-world-next-js](https://github.com/googleworkspace/meet/tree/main/addons-web-sdk/samples/hello-world-next-js). If you find anything about the configuration confusing, please see that more basic example.

This add-on is deployed with GitHub pages, so that you can view the live versions of its [Side Panel](https://googleworkspace.github.io/meet/animation-next-js/sidepanel), [Main Stage](https://googleworkspace.github.io/meet/animation-next-js/mainstage), and all other routes. The screensharing promotion at the [index.html](https://googleworkspace.github.io/meet/animation-next-js/) will not fully work
19 changes: 19 additions & 0 deletions addons-web-sdk/samples/animation-next-js/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
8 changes: 8 additions & 0 deletions addons-web-sdk/samples/animation-next-js/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: '/meet/animation-next-js',
distDir: '../dist/animation-next-js',
output: 'export',
};

export default nextConfig;
23 changes: 23 additions & 0 deletions addons-web-sdk/samples/animation-next-js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "animation-next-js",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --experimental-https",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@googleworkspace/meet-addons": "^0.12.0",
"next": "14.2.7",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use client';

import { useEffect, useState } from 'react';
import {
meet,
MeetSidePanelClient,
} from '@googleworkspace/meet-addons/meet.addons';
import { CLOUD_PROJECT_NUMBER } from '../../shared/constants';

/**
* This page displays in the Side Panel after the activity has started to allow
* each call participant to modify the base color of the main stage animation.
*/
export default function Page() {
const [sidePanelClient, setSidePanelClient] = useState<MeetSidePanelClient>();

/**
* Sends a newly chosen color to the main stage, using frame-to-frame
* messaging.
* @param newColor Hex code of the new color.
*/
async function updateColor(newColor: string) {
if (!sidePanelClient) {
throw new Error('Side Panel is not yet initialized!');
}

await sidePanelClient.notifyMainStage(newColor);
}

useEffect(() => {
/**
* Initializes the Add-on Side Panel Client.
* https://developers.google.com/meet/add-ons/reference/websdk/addon_sdk.meetsidepanelclient
*/
async function initializeSidePanelClient() {
const session = await meet.addon.createAddonSession({
cloudProjectNumber: CLOUD_PROJECT_NUMBER,
});
const client = await session.createSidePanelClient();
setSidePanelClient(client);
}
initializeSidePanelClient();
}, []);

return (
<>
<label htmlFor="pretty-color">
Change the color. Only you will see this:
</label>
<input
type="color"
id="pretty-color"
name="pretty-color"
defaultValue="#00ff00"
onChange={(e) => updateColor(e.target.value)}
/>
</>
);
}
18 changes: 18 additions & 0 deletions addons-web-sdk/samples/animation-next-js/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { type Metadata } from 'next';

export const metadata: Metadata = {
title: 'Pretty Colors',
description: 'Google Meet Add-on that shows an animation',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use client';

import { useEffect, useState } from 'react';
import {
meet,
FrameToFrameMessage,
MeetMainStageClient,
} from '@googleworkspace/meet-addons/meet.addons';
import { CLOUD_PROJECT_NUMBER } from '../../shared/constants';
import PrettyColors from '@/components/prettyColors';

/**
* @see {@link https://developers.google.com/meet/add-ons/guides/overview#main-stage}
*/
export default function Page() {
const [color, setColor] = useState('#00ff00');

/**
* Creates a MeetMainStageClient to control the main stage of the add-on.
* https://developers.google.com/meet/add-ons/reference/websdk/addon_sdk.meetmainstageclient
*/
async function initializeMainStageClient(): Promise<MeetMainStageClient> {
const session = await meet.addon.createAddonSession({
cloudProjectNumber: CLOUD_PROJECT_NUMBER,
});
return await session.createMainStageClient();
}

/**
* Parses the collaboration starting state from the side panel, and updates
* the color used for the main animation.
*/
async function setStartingState(mainStageClient: MeetMainStageClient) {
const startingState = await mainStageClient.getActivityStartingState();
const additionalData = JSON.parse(startingState.additionalData ?? '{}');
setColor(additionalData.startingColor);
}

/**
* Listens for new frame-to-frame messages from the side panel that update
* the color used for the main animation.
*/
function awaitNewColor(mainStageClient: MeetMainStageClient) {
mainStageClient.on(
'frameToFrameMessage',
(message: FrameToFrameMessage) => {
setColor(message.payload);
}
);
}

useEffect(() => {
/**
* Initialize the main stage by initializing the client, then using that
* client to get the starting state (color), and observe any new colors
* passed from the Side Panel.
*/
async function initializeMainStage() {
const client = await initializeMainStageClient();
setStartingState(client);
awaitNewColor(client);
}
initializeMainStage();
}, []);

return (
<>
<PrettyColors baseColor={color}></PrettyColors>
</>
);
}
29 changes: 29 additions & 0 deletions addons-web-sdk/samples/animation-next-js/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use client';

import { useEffect } from 'react';
import { meet } from '@googleworkspace/meet-addons/meet.addons.screenshare';
import { CLOUD_PROJECT_NUMBER, SIDE_PANEL_URL } from '../shared/constants';

export default function App() {
/**
* Screensharing this page will prompt you to install/open this add-on.
* When it is opened, it will prompt you to set up the add-on in the side
* panel before starting the activity for everyone.
* @see {@link https://developers.google.com/meet/add-ons/guides/screen-sharing}
*/
useEffect(() => {
meet.addon.screensharing.exposeToMeetWhenScreensharing({
cloudProjectNumber: CLOUD_PROJECT_NUMBER,
// Will open the Side Panel for the activity initiator to set the
// activity starting state. Activity won't start for other participants.
sidePanelUrl: SIDE_PANEL_URL,
startActivityOnOpen: false,
});
}, []);

return (
<>
<div>Screenshare this page to promote an add-on.</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use client';

import { useEffect, useState } from 'react';
import {
meet,
MeetSidePanelClient,
} from '@googleworkspace/meet-addons/meet.addons';
import {
ACTIVITY_SIDE_PANEL_URL,
CLOUD_PROJECT_NUMBER,
MAIN_STAGE_URL,
} from '../../shared/constants';

/**
* @see {@link https://developers.google.com/meet/add-ons/guides/overview#side-panel}
*/
export default function Page() {
const [sidePanelClient, setSidePanelClient] = useState<MeetSidePanelClient>();

/**
* Starts the add-on activity and passes the selected color to the Main Stage,
* as part of the activity starting state.
*/
async function startCollaboration(e: unknown) {
if (!sidePanelClient) {
throw new Error('Side Panel is not yet initialized!');
}

const startingColor = (
document.getElementById('starting-color')! as HTMLInputElement
).value;
await sidePanelClient.startActivity({
mainStageUrl: MAIN_STAGE_URL,
sidePanelUrl: ACTIVITY_SIDE_PANEL_URL,
// Pass the selected color to customize the initial display.
additionalData: `{\"startingColor\": \"${startingColor}\"}`,
});
window.location.replace(ACTIVITY_SIDE_PANEL_URL + window.location.search);
}

useEffect(() => {
/**
* Initializes the Add-on Side Panel Client.
* https://developers.google.com/meet/add-ons/reference/websdk/addon_sdk.meetsidepanelclient
*/
async function initializeSidePanelClient() {
const session = await meet.addon.createAddonSession({
cloudProjectNumber: CLOUD_PROJECT_NUMBER,
});
const client = await session.createSidePanelClient();
setSidePanelClient(client);
}
initializeSidePanelClient();
}, []);

return (
<>
<div>
Welcome to Pretty Colors! This is a contrived demo add-on that lets you
look at an animation involving your favorite color.
</div>
<label htmlFor="starting-color">
Pick a color you like. Everyone will see this:
</label>
<input
type="color"
id="starting-color"
name="starting-color"
defaultValue="#00ff00"
/>
<br />
<button onClick={startCollaboration}>Start the animation!</button>
</>
);
}
Loading

0 comments on commit 9e106c7

Please sign in to comment.