mirror of
https://github.com/wassname/talk.git
synced 2026-06-27 17:32:25 +08:00
feat: amp
This commit is contained in:
@@ -718,6 +718,16 @@ export default function createWebpackConfig(
|
||||
filename: "storyButton.html",
|
||||
template: paths.appEmbedStoryButtonHTML,
|
||||
inject: "head",
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "amp.html",
|
||||
template: paths.appEmbedAMPHTML,
|
||||
inject: "head",
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "storyAMP.html",
|
||||
template: paths.appEmbedStoryAMPHTML,
|
||||
inject: false,
|
||||
})
|
||||
),
|
||||
...ifBuild(
|
||||
|
||||
@@ -53,6 +53,8 @@ export default {
|
||||
appEmbedHTML: resolveSrc("core/client/embed/index.html"),
|
||||
appEmbedStoryHTML: resolveSrc("core/client/embed/story.html"),
|
||||
appEmbedStoryButtonHTML: resolveSrc("core/client/embed/storyButton.html"),
|
||||
appEmbedAMPHTML: resolveSrc("core/client/embed/amp.html"),
|
||||
appEmbedStoryAMPHTML: resolveSrc("core/client/embed/storyAMP.html"),
|
||||
|
||||
appDistStatic: resolveApp("dist/static"),
|
||||
appPublic: resolveApp("public"),
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface Config {
|
||||
enableDeprecatedEvents?: boolean;
|
||||
/** Allow setting className of body tag inside iframe */
|
||||
bodyClassName?: string;
|
||||
amp?: boolean;
|
||||
}
|
||||
|
||||
export function createStreamEmbed(config: Config): StreamEmbed {
|
||||
@@ -32,7 +33,7 @@ export function createStreamEmbed(config: Config): StreamEmbed {
|
||||
return create({
|
||||
title: "Coral Embed Stream",
|
||||
storyID: config.storyID || query.storyID,
|
||||
storyURL: config.storyURL || resolveStoryURL(),
|
||||
storyURL: config.storyURL || query.storyURL || resolveStoryURL(),
|
||||
commentID: config.commentID || query.commentID,
|
||||
id: config.id || "coral-embed-stream",
|
||||
rootURL: config.rootURL || getLocationOrigin(),
|
||||
@@ -41,5 +42,6 @@ export function createStreamEmbed(config: Config): StreamEmbed {
|
||||
accessToken: config.accessToken,
|
||||
bodyClassName: config.bodyClassName,
|
||||
enableDeprecatedEvents: config.enableDeprecatedEvents,
|
||||
amp: config.amp,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface StreamEmbedConfig {
|
||||
accessToken?: string;
|
||||
bodyClassName?: string;
|
||||
enableDeprecatedEvents?: boolean;
|
||||
amp?: boolean;
|
||||
}
|
||||
|
||||
export class StreamEmbed {
|
||||
@@ -137,7 +138,7 @@ export class StreamEmbed {
|
||||
|
||||
const streamDecorators: ReadonlyArray<Decorator> = [
|
||||
withIOSSafariWidthWorkaround,
|
||||
withAutoHeight,
|
||||
withAutoHeight(Boolean(this.config.amp)),
|
||||
withClickEvent,
|
||||
withSetCommentID,
|
||||
withEventEmitter(
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Coral – AMP Embed Stream</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="coralStreamEmbed" style="max-width: 640px; margin: 0 auto"></div>
|
||||
<script>
|
||||
const CoralStreamEmbed = Coral.createStreamEmbed({
|
||||
id: "coralStreamEmbed",
|
||||
rootURL: "http://localhost:8080",
|
||||
amp: true,
|
||||
});
|
||||
window.CoralStreamEmbed = CoralStreamEmbed;
|
||||
CoralStreamEmbed.render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +1,22 @@
|
||||
import { Decorator } from "./types";
|
||||
|
||||
const withAutoHeight: Decorator = (pym) => {
|
||||
const withAutoHeight: (amp: boolean) => Decorator = (amp) => (pym) => {
|
||||
// Resize parent iframe height when child height changes
|
||||
let cachedHeight: string;
|
||||
pym.onMessage("height", (height: string) => {
|
||||
if (height !== cachedHeight) {
|
||||
pym.iframe.style.height = `${height}px`;
|
||||
cachedHeight = height;
|
||||
if (amp) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
sentinel: "amp",
|
||||
type: "embed-size",
|
||||
height: Number.parseInt(height, 10) > 100 ? height : 100,
|
||||
},
|
||||
"*"
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Coral 5.0 – Embed Stream</title>
|
||||
<title>Coral – Embed Stream</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
@@ -16,9 +16,10 @@
|
||||
<body>
|
||||
<p style="text-align: center">
|
||||
<a href="/admin">Admin</a> | <a href="/story.html">Story</a> |
|
||||
<a href="/storyButton.html">Story With Button</a>
|
||||
<a href="/storyButton.html">Story With Button</a> |
|
||||
<a href="/storyAMP.html"> AMP</a>
|
||||
</p>
|
||||
<h1 style="text-align: center">Coral 5.0 – Embed Stream</h1>
|
||||
<h1 style="text-align: center">Coral – Embed Stream</h1>
|
||||
<div id="coralStreamEmbed" style="max-width: 640px; margin: 0 auto"></div>
|
||||
<script>
|
||||
const CoralStreamEmbed = Coral.createStreamEmbed({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Coral 5.0 – Embed Stream – Story</title>
|
||||
<title>Coral – Embed Stream – Story</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no" />
|
||||
@@ -16,9 +16,10 @@
|
||||
<body>
|
||||
<p style="text-align: center">
|
||||
<a href="/admin">Admin</a> | <a href="/">Default</a> |
|
||||
<a href="/storyButton.html">Story With Button</a>
|
||||
<a href="/storyButton.html">Story With Button</a> |
|
||||
<a href="/storyAMP.html"> AMP</a>
|
||||
</p>
|
||||
<h1 style="text-align: center">Coral 5.0 – Story</h1>
|
||||
<h1 style="text-align: center">Coral – Story</h1>
|
||||
<p>
|
||||
<a href="#coralStreamEmbed"><span class="coral-count"></span></a>
|
||||
</p>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<!doctype html>
|
||||
<html amp lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script async src="https://cdn.ampproject.org/v0.js"></script>
|
||||
<script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script>
|
||||
<title>Coral AMP</title>
|
||||
<link rel="canonical" href="https://amp.dev/documentation/guides-and-tutorials/start/create/basic_markup/">
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
|
||||
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
||||
<style amp-custom>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 100px 50px 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p style="text-align: center">
|
||||
<a href="/admin">Admin</a> | <a href="/">Default</a> | <a href="/story.html">Story</a> |
|
||||
<a href="/storyButton.html">Story With Button</a>
|
||||
</p>
|
||||
<h1 style="text-align: center">Coral – AMP</h1>
|
||||
<amp-iframe
|
||||
width=600 height=140
|
||||
layout="responsive"
|
||||
sandbox="allow-scripts allow-same-origin allow-modals allow-popups allow-forms"
|
||||
resizable
|
||||
src="http://127.0.0.1:8080/amp.html?storyURL=http://localhost:8080/storyAMP.html">
|
||||
<div placeholder></div>
|
||||
<div overflow tabindex=0 role=button aria-label="Read more">Read more</div>
|
||||
</amp-iframe>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Coral 5.0 – Embed Stream – Story with Button</title>
|
||||
<title>Coral – Embed Stream – Story with Button</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no" />
|
||||
@@ -16,9 +16,10 @@
|
||||
<body>
|
||||
<p style="text-align: center">
|
||||
<a href="/admin">Admin</a> | <a href="/">Default</a> |
|
||||
<a href="/story.html">Story</a>
|
||||
<a href="/story.html">Story</a> |
|
||||
<a href="/storyAMP.html"> AMP</a>
|
||||
</p>
|
||||
<h1 style="text-align: center">Coral 5.0 – Story with Button</h1>
|
||||
<h1 style="text-align: center">Coral – Story with Button</h1>
|
||||
<p>
|
||||
<a href="#coralStreamEmbed"><span class="coral-count"></span></a>
|
||||
</p>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { GQLSTORY_MODE } from "coral-framework/schema";
|
||||
import CLASSES from "coral-stream/classes";
|
||||
import { Icon, MatchMedia, Tab, TabBar } from "coral-ui/components";
|
||||
|
||||
type TabValue = "COMMENTS" | "PROFILE" | "%future added value";
|
||||
type TabValue = "COMMENTS" | "PROFILE" | "CONFIGURE" | "%future added value";
|
||||
|
||||
export interface Props {
|
||||
activeTab: TabValue;
|
||||
@@ -52,7 +52,12 @@ const AppTabBar: FunctionComponent<Props> = (props) => {
|
||||
</Tab>
|
||||
)}
|
||||
{props.showConfigureTab && (
|
||||
<Tab className={CLASSES.tabBar.configure} tabID="CONFIGURE">
|
||||
<Tab
|
||||
className={cn(CLASSES.tabBar.configure, {
|
||||
[CLASSES.tabBar.activeTab]: props.activeTab === "CONFIGURE",
|
||||
})}
|
||||
tabID="CONFIGURE"
|
||||
>
|
||||
<MatchMedia gteWidth="sm">
|
||||
{(matches) =>
|
||||
matches ? (
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
// This is only loaded in development, so include the React devtools hooks.
|
||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
try {
|
||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
}
|
||||
catch {
|
||||
console.warn("React Devtools Global Hook not loaded")
|
||||
}
|
||||
</script>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
|
||||
@@ -99,7 +99,7 @@ function generateContentSecurityPolicy(allowedOrigins: string[]) {
|
||||
|
||||
// Only the domains that are allowed by the tenant may embed Coral.
|
||||
directives.frameAncestors =
|
||||
allowedOrigins.length > 0 ? allowedOrigins : ["'none'"];
|
||||
allowedOrigins.length > 0 ? ["'self'", ...allowedOrigins] : ["'none'"];
|
||||
|
||||
// Build the directive.
|
||||
const directive = builder({ directives });
|
||||
|
||||
@@ -17,6 +17,11 @@ import Entrypoints, { Entrypoint } from "../helpers/entrypoints";
|
||||
export interface ClientTargetHandlerOptions {
|
||||
defaultLocale: LanguageCode;
|
||||
|
||||
/**
|
||||
* viewTemplate is the html template to use.
|
||||
*/
|
||||
viewTemplate?: string;
|
||||
|
||||
/**
|
||||
* mongo is used when trying to infer a site from the request.
|
||||
*/
|
||||
@@ -73,6 +78,7 @@ const clientHandler = ({
|
||||
entrypoint,
|
||||
enableCustomCSS,
|
||||
defaultLocale,
|
||||
viewTemplate = "client",
|
||||
}: ClientTargetHandlerOptions): RequestHandler => (req, res, next) => {
|
||||
// Provide configuration to the frontend in the HTML.
|
||||
const config = {
|
||||
@@ -86,7 +92,7 @@ const clientHandler = ({
|
||||
}
|
||||
|
||||
res.render(
|
||||
"client",
|
||||
viewTemplate,
|
||||
{ staticURI, entrypoint, enableCustomCSS, locale, config },
|
||||
(err, html) => {
|
||||
if (err) {
|
||||
@@ -104,10 +110,7 @@ const clientHandler = ({
|
||||
);
|
||||
};
|
||||
|
||||
export function mountClientRoutes(
|
||||
router: Router,
|
||||
{ staticURI, tenantCache, defaultLocale, mongo }: MountClientRouteOptions
|
||||
) {
|
||||
function loadEntrypoints(manifestFile: string) {
|
||||
// TODO: (wyattjoh) figure out a better way of referencing paths.
|
||||
// Load the entrypoint manifest.
|
||||
const manifest = path.join(
|
||||
@@ -119,9 +122,17 @@ export function mountClientRoutes(
|
||||
"..",
|
||||
"dist",
|
||||
"static",
|
||||
"asset-manifest.json"
|
||||
manifestFile
|
||||
);
|
||||
const entrypoints = Entrypoints.fromFile(manifest);
|
||||
return Entrypoints.fromFile(manifest);
|
||||
}
|
||||
|
||||
export function mountClientRoutes(
|
||||
router: Router,
|
||||
{ staticURI, tenantCache, defaultLocale, mongo }: MountClientRouteOptions
|
||||
) {
|
||||
const manifest = "asset-manifest.json";
|
||||
const entrypoints = loadEntrypoints(manifest);
|
||||
if (!entrypoints) {
|
||||
logger.error(
|
||||
{ manifest },
|
||||
@@ -129,6 +140,17 @@ export function mountClientRoutes(
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const embedManifest = "embed-asset-manifest.json";
|
||||
const embedEntrypoints = loadEntrypoints(embedManifest);
|
||||
if (!embedEntrypoints) {
|
||||
logger.error(
|
||||
{ manifest: embedManifest },
|
||||
"could not load the generated manifest, client routes will remain un-mounted"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Tenant identification middleware.
|
||||
router.use(
|
||||
tenantMiddleware({
|
||||
@@ -138,6 +160,16 @@ export function mountClientRoutes(
|
||||
);
|
||||
|
||||
// Add the embed targets.
|
||||
router.use(
|
||||
"/embed/stream/amp",
|
||||
createClientTargetRouter({
|
||||
staticURI,
|
||||
entrypoint: embedEntrypoints.get("main"),
|
||||
defaultLocale,
|
||||
mongo,
|
||||
viewTemplate: "amp",
|
||||
})
|
||||
);
|
||||
router.use(
|
||||
"/embed/stream",
|
||||
createClientTargetRouter({
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{% import "macros.html" as macros %}
|
||||
{% extends "templates/base.html" %}
|
||||
|
||||
{% block title %}Coral AMP{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<style>body { margin: 0; }</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div id='coralStreamEmbed'></div>
|
||||
{% if entrypoint.js %}
|
||||
{% for asset in entrypoint.js %}
|
||||
{{ macros.js(asset.src, asset.integrity, staticURI) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<script>
|
||||
const CoralStreamEmbed = Coral.createStreamEmbed({
|
||||
id: "coralStreamEmbed",
|
||||
amp: true,
|
||||
});
|
||||
window.CoralStreamEmbed = CoralStreamEmbed;
|
||||
CoralStreamEmbed.render();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user