This commit is contained in:
Suphonchai Phoonsawat 2026-08-18 12:52:40 +07:00
commit 41573b3c4f
54 changed files with 32839 additions and 0 deletions

View file

@ -0,0 +1,19 @@
@@ -1,18 +0,0 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
* See LICENSE in the project root for license information.
*/
/* global Office */
Office.onReady(() => {
// If needed, Office.js is ready to be called.
});
/**
* Shows a notification when the add-in command is executed.
* @param event
*/
function action(event: Office.AddinCommands.Event) {
const message: Office.NotificationMessageDetails = {
type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,
message: "Performed action.",
icon: "Icon.80x80",
persistent: true,
};
// Show a notification message.
Office.context.mailbox.item?.notificationMessages.replaceAsync(
"ActionPerformanceNotification",
message
);
// Be sure to indicate when the add-in command function is complete.
event.completed();
}
// Register the function with Office.
Office.actions.associate("action", action);

View file

@ -0,0 +1,47 @@
import * as React from "react";
import Header from "./Header";
import HeroList, { HeroListItem } from "./HeroList";
import TextInsertion from "./TextInsertion";
import { makeStyles } from "@fluentui/react-components";
import { Ribbon24Regular, LockOpen24Regular, DesignIdeas24Regular } from "@fluentui/react-icons";
import { insertText } from "../taskpane";
interface AppProps {
title: string;
}
const useStyles = makeStyles({
root: {
minHeight: "100vh",
},
});
const App: React.FC<AppProps> = (props: AppProps) => {
const styles = useStyles();
// The list items are static and won't change at runtime,
// so this should be an ordinary const, not a part of state.
const listItems: HeroListItem[] = [
{
icon: <Ribbon24Regular />,
primaryText: "Achieve more with Office integration",
},
{
icon: <LockOpen24Regular />,
primaryText: "Unlock features and functionality",
},
{
icon: <DesignIdeas24Regular />,
primaryText: "Create and visualize like a pro",
},
];
return (
<div className={styles.root}>
<Header logo="assets/logo-filled.png" title={props.title} message="Welcome" />
<HeroList message="Discover what this add-in can do for you today!" items={listItems} />
<TextInsertion insertText={insertText} />
</div>
);
};
export default App;

View file

@ -0,0 +1,38 @@
import * as React from "react";
import { Image, tokens, makeStyles } from "@fluentui/react-components";
export interface HeaderProps {
title: string;
logo: string;
message: string;
}
const useStyles = makeStyles({
welcome__header: {
display: "flex",
flexDirection: "column",
alignItems: "center",
paddingBottom: "30px",
paddingTop: "100px",
backgroundColor: tokens.colorNeutralBackground3,
},
message: {
fontSize: tokens.fontSizeHero900,
fontWeight: tokens.fontWeightRegular,
fontColor: tokens.colorNeutralBackgroundStatic,
},
});
const Header: React.FC<HeaderProps> = (props: HeaderProps) => {
const { title, logo, message } = props;
const styles = useStyles();
return (
<section className={styles.welcome__header}>
<Image width="90" height="90" src={logo} alt={title} />
<h1 className={styles.message}>{message}</h1>
</section>
);
};
export default Header;

View file

@ -0,0 +1,62 @@
import * as React from "react";
import { tokens, makeStyles } from "@fluentui/react-components";
export interface HeroListItem {
icon: React.JSX.Element;
primaryText: string;
}
export interface HeroListProps {
message: string;
items: HeroListItem[];
}
const useStyles = makeStyles({
list: {
marginTop: "20px",
},
listItem: {
paddingBottom: "20px",
display: "flex",
},
icon: {
marginRight: "10px",
},
itemText: {
fontSize: tokens.fontSizeBase300,
fontColor: tokens.colorNeutralBackgroundStatic,
},
welcome__main: {
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
},
message: {
fontSize: tokens.fontSizeBase500,
fontColor: tokens.colorNeutralBackgroundStatic,
fontWeight: tokens.fontWeightRegular,
paddingLeft: "10px",
paddingRight: "10px",
},
});
const HeroList: React.FC<HeroListProps> = (props: HeroListProps) => {
const { items, message } = props;
const styles = useStyles();
const listItems = items.map((item, index) => (
<li className={styles.listItem} key={index}>
<i className={styles.icon}>{item.icon}</i>
<span className={styles.itemText}>{item.primaryText}</span>
</li>
));
return (
<div className={styles.welcome__main}>
<h2 className={styles.message}>{message}</h2>
<ul className={styles.list}>{listItems}</ul>
</div>
);
};
export default HeroList;

View file

@ -0,0 +1,57 @@
import * as React from "react";
import { useState } from "react";
import { Button, Field, Textarea, tokens, makeStyles } from "@fluentui/react-components";
/* global HTMLTextAreaElement */
interface TextInsertionProps {
insertText: (text: string) => void;
}
const useStyles = makeStyles({
instructions: {
fontWeight: tokens.fontWeightSemibold,
marginTop: "20px",
marginBottom: "10px",
},
textPromptAndInsertion: {
display: "flex",
flexDirection: "column",
alignItems: "center",
},
textAreaField: {
marginLeft: "20px",
marginTop: "30px",
marginBottom: "20px",
marginRight: "20px",
maxWidth: "50%",
},
});
const TextInsertion: React.FC<TextInsertionProps> = (props: TextInsertionProps) => {
const [text, setText] = useState<string>("Some text.");
const handleTextInsertion = async () => {
await props.insertText(text);
};
const handleTextChange = async (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setText(event.target.value);
};
const styles = useStyles();
return (
<div className={styles.textPromptAndInsertion}>
<Field className={styles.textAreaField} size="large" label="Enter text to be inserted into the document.">
<Textarea size="large" value={text} onChange={handleTextChange} />
</Field>
<Field className={styles.instructions}>Click the button to insert text.</Field>
<Button appearance="primary" disabled={false} size="large" onClick={handleTextInsertion}>
Insert text
</Button>
</div>
);
};
export default TextInsertion;

View file

@ -0,0 +1,27 @@
import * as React from "react";
import { createRoot } from "react-dom/client";
import App from "./components/App";
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
/* global document, Office, module, require, HTMLElement */
const title = "Contoso Task Pane Add-in";
const rootElement: HTMLElement | null = document.getElementById("container");
const root = rootElement ? createRoot(rootElement) : undefined;
/* Render application after Office initializes */
Office.onReady(() => {
root?.render(
<FluentProvider theme={webLightTheme}>
<App title={title} />
</FluentProvider>
);
});
if ((module as any).hot) {
(module as any).hot.accept("./components/App", () => {
const NextApp = require("./components/App").default;
root?.render(NextApp);
});
}

View file

@ -0,0 +1,21 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -->
<!-- See LICENSE in the project root for license information -->
<!doctype html>
<html lang="en" data-framework="typescript">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contoso Task Pane Add-in</title>
<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
</head>
<body style="width: 100%; height: 100%; margin: 0; padding: 0;">
<div id="container"></div>
</body>
</html>

View file

@ -0,0 +1,14 @@
/* global Word console */
export async function insertText(text: string) {
// Write text to the document.
try {
await Word.run(async (context) => {
let body = context.document.body;
body.insertParagraph(text, Word.InsertLocation.end);
await context.sync();
});
} catch (error) {
console.log("Error: " + error);
}
}