Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add example code for tutorial #188

Merged
merged 7 commits into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
34 changes: 34 additions & 0 deletions examples/blog-post-metrics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
This project was bootstrapped with [Create Contentful App](https://github.com/contentful/create-contentful-app).

## Available Scripts

In the project directory, you can run:

#### `npm start`

Creates or updates your app definition in contentful, and runs the app in development mode.
Open your app to view it in the browser.

The page will reload if you make edits.
You will also see any lint errors in the console.

#### `npm run build`

Builds the app for production to the `build` folder.
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.
Your app is ready to be deployed!

## Libraries to use

To make your app look and feel like Contentful use the following libraries:

- [Forma 36](https://f36.contentful.com/) – Contentful's design system
- [Contentful Field Editors](https://www.contentful.com/developers/docs/extensibility/field-editors/) – Contentful's field editor React components

## Learn More

[Read more](https://www.contentful.com/developers/docs/extensibility/app-framework/create-contentful-app/) and check out the video on how to use the CLI.

Create Contentful App uses [Create React App](https://create-react-app.dev/). You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started) and how to further customize your app.
16,061 changes: 16,061 additions & 0 deletions examples/blog-post-metrics/package-lock.json

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions examples/blog-post-metrics/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "blog-post-metrics",
"version": "0.1.0",
"private": true,
"dependencies": {
"@contentful/app-sdk": "^3.31.0",
"@contentful/field-editor-single-line": "^0.11.4",
"@contentful/field-editor-test-utils": "^0.8.4",
"@contentful/forma-36-fcss": "^0.2.14",
"@contentful/forma-36-react-components": "^3.75.0",
"@contentful/forma-36-tokens": "^0.9.4",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.3",
"@testing-library/user-event": "^12.6.0",
"@types/jest": "^26.0.20",
"@types/node": "^14.14.22",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"cross-env": "^7.0.3",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.1",
"reading-time": "^1.2.1",
"typescript": "^4.1.3"
},
"scripts": {
"start": "cross-env BROWSER=none react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
19 changes: 19 additions & 0 deletions examples/blog-post-metrics/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start`.
To create a production bundle, use `npm run build`.
-->
</body>
</html>
24 changes: 24 additions & 0 deletions examples/blog-post-metrics/src/components/ConfigScreen.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import ConfigScreen from './ConfigScreen';
import { render } from '@testing-library/react';

describe('Config Screen component', () => {
it('Component text exists', async () => {
const mockSdk: any = {
app: {
onConfigure: jest.fn(),
getParameters: jest.fn().mockReturnValueOnce({}),
setReady: jest.fn(),
getCurrentState: jest.fn()
}
};
const { getByText } = render(<ConfigScreen sdk={mockSdk} />);

// simulate the user clicking the install button
await mockSdk.app.onConfigure.mock.calls[0][0]();

expect(
getByText('Welcome to your contentful app. This is your config page.')
).toBeInTheDocument();
});
});
74 changes: 74 additions & 0 deletions examples/blog-post-metrics/src/components/ConfigScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { Component } from "react";
import { AppExtensionSDK } from "@contentful/app-sdk";
import {
Heading,
Form,
Workbench,
Paragraph,
} from "@contentful/forma-36-react-components";
import { css } from "emotion";

export interface AppInstallationParameters {}

interface ConfigProps {
sdk: AppExtensionSDK;
}

interface ConfigState {
parameters: AppInstallationParameters;
}

export default class Config extends Component<ConfigProps, ConfigState> {
constructor(props: ConfigProps) {
super(props);
this.state = { parameters: {} };

// `onConfigure` allows to configure a callback to be
// invoked when a user attempts to install the app or update
// its configuration.
props.sdk.app.onConfigure(() => this.onConfigure());
}

async componentDidMount() {
// Get current parameters of the app.
// If the app is not installed yet, `parameters` will be `null`.
const parameters: AppInstallationParameters | null = await this.props.sdk.app.getParameters();

this.setState(parameters ? { parameters } : this.state, () => {
// Once preparation has finished, call `setReady` to hide
// the loading screen and present the app to a user.
this.props.sdk.app.setReady();
});
}

onConfigure = async () => {
// This method will be called when a user clicks on "Install"
// or "Save" in the configuration screen.
// for more details see https://www.contentful.com/developers/docs/extensibility/ui-extensions/sdk-reference/#register-an-app-configuration-hook

// Get current the state of EditorInterface and other entities
FLoppix marked this conversation as resolved.
Show resolved Hide resolved
// related to this app installation
const currentState = await this.props.sdk.app.getCurrentState();

return {
// Parameters to be persisted as the app configuration.
parameters: this.state.parameters,
// In case you don't want to submit any update to app
FLoppix marked this conversation as resolved.
Show resolved Hide resolved
// locations, you can just pass the currentState as is
targetState: currentState,
};
};

render() {
return (
<Workbench className={css({ margin: "80px" })}>
<Form>
<Heading>Blog Post Metrics Config</Heading>
<Paragraph>
Welcome to your contentful app. This is your config page.
FLoppix marked this conversation as resolved.
Show resolved Hide resolved
</Paragraph>
</Form>
</Workbench>
);
}
}
11 changes: 11 additions & 0 deletions examples/blog-post-metrics/src/components/Dialog.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import Dialog from './Dialog';
import { render } from '@testing-library/react';

describe('Dialog component', () => {
it('Component text exists', () => {
const { getByText } = render(<Dialog />);

expect(getByText('Hello Dialog Component')).toBeInTheDocument();
});
});
13 changes: 13 additions & 0 deletions examples/blog-post-metrics/src/components/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { Paragraph } from '@contentful/forma-36-react-components';
import { DialogExtensionSDK } from '@contentful/app-sdk';

interface DialogProps {
sdk: DialogExtensionSDK;
}

const Dialog = (props: DialogProps) => {
return <Paragraph>Hello Dialog Component</Paragraph>;
};

export default Dialog;
FLoppix marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 11 additions & 0 deletions examples/blog-post-metrics/src/components/EntryEditor.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import EntryEditor from './EntryEditor';
import { render } from '@testing-library/react';

describe('Entry component', () => {
it('Component text exists', () => {
const { getByText } = render(<EntryEditor />);

expect(getByText('Hello Entry Editor Component')).toBeInTheDocument();
});
});
13 changes: 13 additions & 0 deletions examples/blog-post-metrics/src/components/EntryEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { Paragraph } from '@contentful/forma-36-react-components';
import { EditorExtensionSDK } from '@contentful/app-sdk';

interface EditorProps {
sdk: EditorExtensionSDK;
}

const Entry = (props: EditorProps) => {
return <Paragraph>Hello Entry Editor Component</Paragraph>;
};

export default Entry;
11 changes: 11 additions & 0 deletions examples/blog-post-metrics/src/components/Field.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import Field from './Field';
import { render } from '@testing-library/react';

describe('Field component', () => {
it('Component text exists', () => {
const { getByText } = render(<Field />);

expect(getByText('Hello Entry Field Component')).toBeInTheDocument();
});
});
16 changes: 16 additions & 0 deletions examples/blog-post-metrics/src/components/Field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { Paragraph } from '@contentful/forma-36-react-components';
import { FieldExtensionSDK } from '@contentful/app-sdk';

interface FieldProps {
sdk: FieldExtensionSDK;
}

const Field = (props: FieldProps) => {
// If you only want to extend Contentful's default editing experience
// reuse Contentful's editor components
// -> https://www.contentful.com/developers/docs/extensibility/field-editors/
return <Paragraph>Hello Entry Field Component</Paragraph>;
};

export default Field;
37 changes: 37 additions & 0 deletions examples/blog-post-metrics/src/components/LocalhostWarning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { Paragraph, TextLink, Note } from '@contentful/forma-36-react-components';

const LocalhostWarning = () => {
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
marginTop: '40px'
}}>
<Note title="App running outside of Contentful" style={{ maxWidth: '800px' }}>
<Paragraph>
Contentful Apps need to run inside the Contentful web app to function properly. Install
the app into a space and render your app into one of the{' '}
<TextLink href="https://www.contentful.com/developers/docs/extensibility/ui-extensions/sdk-reference/#locations">
available locations
</TextLink>
.
</Paragraph>
<br />

<Paragraph>
Follow{' '}
<TextLink href="https://www.contentful.com/developers/docs/extensibility/app-framework/tutorial/">
our guide
</TextLink>{' '}
to get started or{' '}
<TextLink href="https://app.contentful.com/deeplink?link=apps">open Contentful</TextLink>{' '}
to manage your app.
</Paragraph>
</Note>
</div>
);
};

export default LocalhostWarning;
11 changes: 11 additions & 0 deletions examples/blog-post-metrics/src/components/Page.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import Page from './Page';
import { render } from '@testing-library/react';

describe('Page component', () => {
it('Component text exists', () => {
const { getByText } = render(<Page />);

expect(getByText('Hello Page Component')).toBeInTheDocument();
});
});
13 changes: 13 additions & 0 deletions examples/blog-post-metrics/src/components/Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { Paragraph } from '@contentful/forma-36-react-components';
import { PageExtensionSDK } from '@contentful/app-sdk';

interface PageProps {
sdk: PageExtensionSDK;
}

const Page = (props: PageProps) => {
return <Paragraph>Hello Page Component</Paragraph>;
};

export default Page;
11 changes: 11 additions & 0 deletions examples/blog-post-metrics/src/components/Sidebar.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import Sidebar from './Sidebar';
import { render } from '@testing-library/react';

describe('Sidebar component', () => {
it('Component text exists', () => {
const { getByText } = render(<Sidebar />);

expect(getByText('Hello Sidebar Component')).toBeInTheDocument();
});
});
Loading