Extract TitleBar and AppIcon to shared package and implement it in apps (#134)

* Update imports from apps-shared package

* Extract main bar and app icon

* Remove graphql generated

* Implement AppIcon and MainBar in data importer and invoices

* Change name to TitleBar

* Use TitleBar and AppIcon from shared package

* Use title bar from shared in search

* Refactor slack to use TitleBar from shared package

* Make TitleBar sticky

* Run codegen before cicd tests

* Add generate script
This commit is contained in:
Lukasz Ostrowski 2023-02-09 18:41:23 +01:00 committed by GitHub
parent 260a57c6fc
commit 9f843b2d31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 266 additions and 511723 deletions

View file

@ -0,0 +1,9 @@
---
"saleor-app-data-importer": patch
"saleor-app-invoices": patch
"saleor-app-klaviyo": patch
"saleor-app-search": patch
"saleor-app-slack": patch
---
Update imports to @saleor/apps-shared

View file

@ -0,0 +1,5 @@
---
"saleor-app-klaviyo": patch
---
Use TitleBar and AppIcon from shared package

View file

@ -0,0 +1,5 @@
---
"saleor-app-search": patch
---
Use TitleBar and AppIcon from shared package

View file

@ -0,0 +1,10 @@
---
"saleor-app-data-importer": patch
"@saleor/apps-shared": patch
"saleor-app-invoices": patch
"saleor-app-klaviyo": patch
"saleor-app-search": patch
"saleor-app-slack": patch
---
Remove generated folders form git history

View file

@ -0,0 +1,5 @@
---
"@saleor/apps-shared": minor
---
Add main-bar and app-icon

View file

@ -0,0 +1,5 @@
---
"saleor-app-slack": patch
---
Use TitleBar and AppIcon from Shared package

View file

@ -0,0 +1,5 @@
---
"@saleor/apps-shared": minor
---
Make TitleBar sticky to the top

View file

@ -0,0 +1,5 @@
---
"@saleor/apps-shared": minor
---
Allow icon, text and theme to AppIcon

View file

@ -0,0 +1,5 @@
---
"@saleor/apps-shared": minor
---
Add root index file

3
.eslintignore Normal file
View file

@ -0,0 +1,3 @@
node_modules
**/generated
pnpm-lock.yaml

View file

@ -18,6 +18,8 @@ jobs:
cache: "pnpm" cache: "pnpm"
- name: Install dependencies - name: Install dependencies
run: pnpm install run: pnpm install
- name: Generate schema
run: pnpm generate
- name: Test - name: Test
run: pnpm test:ci run: pnpm test:ci
# TODO: Add coverage - crawl through every package # TODO: Add coverage - crawl through every package

1
.gitignore vendored
View file

@ -38,3 +38,4 @@ yarn-error.log*
.saleor-app-auth.json .saleor-app-auth.json
test-invoice.pdf test-invoice.pdf
coverage/ coverage/
apps/**/generated

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,28 +0,0 @@
import { Typography } from "@material-ui/core";
import { makeStyles } from "@saleor/macaw-ui";
const useStyles = makeStyles({
appIconContainer: {
background: "rgb(58, 86, 199)",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
borderRadius: "50%",
color: "#fff",
width: 50,
height: 50,
},
});
export function AppIcon() {
const styles = useStyles();
return (
<div className={styles.appIconContainer}>
<div>
<Typography variant="h2">DI</Typography>
</div>
</div>
);
}

View file

@ -5,8 +5,8 @@ import { Button, makeStyles, PageTab, PageTabs, SaleorTheme } from "@saleor/maca
import { CustomersImporterView } from "../modules/customers/customers-importer-nuvo/customers-importer-view"; import { CustomersImporterView } from "../modules/customers/customers-importer-nuvo/customers-importer-view";
import GraphQLProvider from "../providers/GraphQLProvider"; import GraphQLProvider from "../providers/GraphQLProvider";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge"; import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { MainBar } from "../modules/ui/main-bar"; import { AppIcon, TitleBar } from "@saleor/apps-shared";
import { AppIcon } from "../modules/ui/app-icon";
type Tab = "customers"; type Tab = "customers";
@ -34,9 +34,9 @@ const ImporterPage: NextPage = () => {
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<MainBar <TitleBar
bottomMargin bottomMargin
icon={<AppIcon />} icon={<AppIcon theme="rgb(58, 86, 199)" text="DI"/>}
name="Data Importer" name="Data Importer"
author="By Saleor Commerce" author="By Saleor Commerce"
rightColumnContent={ rightColumnContent={

View file

@ -3,7 +3,7 @@ import { useAppBridge } from "@saleor/app-sdk/app-bridge";
import { useEffect } from "react"; import { useEffect } from "react";
import { useIsMounted } from "usehooks-ts"; import { useIsMounted } from "usehooks-ts";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { isInIframe } from "@saleor/apps-shared/is-in-iframe"; import { isInIframe } from "@saleor/apps-shared";
import { LinearProgress } from "@material-ui/core"; import { LinearProgress } from "@material-ui/core";
const IndexPage: NextPage = () => { const IndexPage: NextPage = () => {

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -7,16 +7,19 @@ import { AddressForm } from "./address-form";
import { ChannelsList } from "./channels-list"; import { ChannelsList } from "./channels-list";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge"; import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { AppColumnsLayout } from "../../ui/app-columns-layout"; import { AppColumnsLayout } from "../../ui/app-columns-layout";
import { TitleBar } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => { const useStyles = makeStyles((theme) => {
return { return {
header: { marginBottom: 20 }, header: { marginBottom: 20 },
grid: { display: "grid", gridTemplateColumns: "1fr 1fr", alignItems: "start", gap: 40 }, grid: { display: "grid", gridTemplateColumns: "1fr 1fr", alignItems: "start", gap: 40 },
formContainer: { formContainer: {
top: 0, top: TitleBar.height + 16,
position: "sticky", position: "sticky",
}, },
instructionsContainer: { instructionsContainer: {
top: TitleBar.height + 16,
position: "sticky",
padding: 15, padding: 15,
}, },
}; };

View file

@ -1,51 +0,0 @@
import { makeStyles } from "@saleor/macaw-ui";
import { ReactNode } from "react";
import { Paper, PaperProps } from "@material-ui/core";
import clsx from "clsx";
const useStyles = makeStyles((theme) => ({
root: {
height: 96,
padding: "0 32px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
},
leftColumn: {
marginRight: "auto",
},
rightColumn: {},
iconColumn: {
marginRight: 24,
},
appName: { fontSize: 24, margin: 0 },
appAuthor: {
fontSize: 12,
textTransform: "uppercase",
color: theme.palette.text.secondary,
fontWeight: 500,
margin: 0,
},
}));
type Props = {
name: string;
author: string;
rightColumnContent?: ReactNode;
icon?: ReactNode;
} & PaperProps;
export const MainBar = ({ name, author, rightColumnContent, className, icon }: Props) => {
const styles = useStyles();
return (
<Paper elevation={0} className={clsx(styles.root, className)}>
{icon && <div className={styles.iconColumn}>{icon}</div>}
<div className={styles.leftColumn}>
<h1 className={styles.appName}>{name}</h1>
<h1 className={styles.appAuthor}>{author}</h1>
</div>
<div className={styles.rightColumn}>{rightColumnContent}</div>
</Paper>
);
};

View file

@ -3,37 +3,20 @@ import React, { useEffect } from "react";
import { ChannelsConfiguration } from "../modules/app-configuration/ui/channels-configuration"; import { ChannelsConfiguration } from "../modules/app-configuration/ui/channels-configuration";
import { trpcClient } from "../modules/trpc/trpc-client"; import { trpcClient } from "../modules/trpc/trpc-client";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { MainBar } from "../modules/ui/main-bar";
import { Button, makeStyles } from "@saleor/macaw-ui"; import { Button, makeStyles } from "@saleor/macaw-ui";
import { GitHub, OfflineBoltOutlined } from "@material-ui/icons"; import { GitHub, OfflineBoltOutlined } from "@material-ui/icons";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge"; import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import appIcon from "../app-invoices-icon.svg"; import appIcon from "../app-invoices-icon.svg";
import Image from "next/image"; import Image from "next/image";
import { AppIcon, TitleBar } from "@saleor/apps-shared";
const useStyles = makeStyles({ const useStyles = makeStyles({
buttonsGrid: { display: "flex", gap: 10 }, buttonsGrid: { display: "flex", gap: 10 },
topBar: { topBar: {
marginBottom: 32, marginBottom: 32,
}, },
appIconContainer: {
background: `rgb(227, 149, 60)`,
padding: 10,
borderRadius: "50%",
width: 50,
height: 50,
},
}); });
const AppIcon = () => {
const styles = useStyles();
return (
<div className={styles.appIconContainer}>
<Image width={30} height={30} alt="icon" src={appIcon} />
</div>
);
};
const ConfigurationPage: NextPage = () => { const ConfigurationPage: NextPage = () => {
const styles = useStyles(); const styles = useStyles();
const channels = trpcClient.channels.fetch.useQuery(); const channels = trpcClient.channels.fetch.useQuery();
@ -58,8 +41,13 @@ const ConfigurationPage: NextPage = () => {
return ( return (
<div> <div>
<MainBar <TitleBar
icon={<AppIcon />} icon={
<AppIcon
theme={`rgb(227, 149, 60)`}
icon={<Image width={30} height={30} alt="icon" src={appIcon} />}
/>
}
className={styles.topBar} className={styles.topBar}
name="Saleor Invoices" name="Saleor Invoices"
author="By Saleor Commerce" author="By Saleor Commerce"

View file

@ -4,7 +4,7 @@ import { useEffect } from "react";
import { useIsMounted } from "usehooks-ts"; import { useIsMounted } from "usehooks-ts";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { LinearProgress } from "@material-ui/core"; import { LinearProgress } from "@material-ui/core";
import { isInIframe } from "@saleor/apps-shared/is-in-iframe"; import { isInIframe } from "@saleor/apps-shared";
const IndexPage: NextPage = () => { const IndexPage: NextPage = () => {
const { appBridgeState } = useAppBridge(); const { appBridgeState } = useAppBridge();

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1,28 +0,0 @@
import { Typography } from "@material-ui/core";
import { makeStyles } from "@saleor/macaw-ui";
const useStyles = makeStyles({
appIconContainer: {
background: "rgb(58, 86, 199)",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
borderRadius: "50%",
color: "#fff",
width: 50,
height: 50,
},
});
export function AppIcon() {
const styles = useStyles();
return (
<div className={styles.appIconContainer}>
<div>
<Typography variant="h2">K</Typography>
</div>
</div>
);
}

View file

@ -1,67 +0,0 @@
import { Paper, PaperProps } from "@material-ui/core";
import { makeStyles } from "@saleor/macaw-ui";
import clsx from "clsx";
import { ReactNode } from "react";
const useStyles = makeStyles((theme) => ({
root: {
height: 96,
padding: "0 32px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
},
leftColumn: {
marginRight: "auto",
},
rightColumn: {},
iconColumn: {
marginRight: 24,
},
appName: { fontSize: 24, margin: 0 },
appAuthor: {
fontSize: 12,
textTransform: "uppercase",
color: theme.palette.text.secondary,
fontWeight: 500,
margin: 0,
},
bottomMargin: {
marginBottom: 32,
},
}));
type Props = {
name: string;
author: string;
rightColumnContent?: ReactNode;
icon?: ReactNode;
bottomMargin?: boolean;
} & PaperProps;
export function MainBar({
name,
author,
rightColumnContent,
className,
icon,
bottomMargin,
}: Props) {
const styles = useStyles();
return (
<Paper
elevation={0}
className={clsx(styles.root, className, {
[styles.bottomMargin]: bottomMargin,
})}
>
{icon && <div className={styles.iconColumn}>{icon}</div>}
<div className={styles.leftColumn}>
<h1 className={styles.appName}>{name}</h1>
<h1 className={styles.appAuthor}>{author}</h1>
</div>
<div className={styles.rightColumn}>{rightColumnContent}</div>
</Paper>
);
}

View file

@ -15,6 +15,7 @@ const nextConfig = {
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment, disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment, disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
}, },
transpilePackages: ["nuvo-react", "@saleor/apps-shared"],
redirects() { redirects() {
return [ return [
{ {

View file

@ -20,17 +20,18 @@
"@material-ui/lab": "4.0.0-alpha.61", "@material-ui/lab": "4.0.0-alpha.61",
"@saleor/app-sdk": "~0.27.1", "@saleor/app-sdk": "~0.27.1",
"@saleor/macaw-ui": "^0.7.2", "@saleor/macaw-ui": "^0.7.2",
"@sentry/nextjs": "^7.31.0", "@sentry/nextjs": "^7.36.0",
"@urql/exchange-auth": "^1.0.0", "@urql/exchange-auth": "^1.0.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"graphql": "^16.6.0", "graphql": "^16.6.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"next": "12.3.1", "next": "13.1.6",
"node-fetch": "^3.2.6", "node-fetch": "^3.2.6",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"urql": "^3.0.3" "urql": "^3.0.3",
"@saleor/apps-shared": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@graphql-codegen/cli": "2.7.0", "@graphql-codegen/cli": "2.7.0",

View file

@ -2,14 +2,14 @@ import { Link, List, ListItem, Paper, PaperProps, TextField, Typography } from "
import Skeleton from "@material-ui/lab/Skeleton"; import Skeleton from "@material-ui/lab/Skeleton";
import { useAppBridge, withAuthorization } from "@saleor/app-sdk/app-bridge"; import { useAppBridge, withAuthorization } from "@saleor/app-sdk/app-bridge";
import { SALEOR_API_URL_HEADER, SALEOR_AUTHORIZATION_BEARER_HEADER } from "@saleor/app-sdk/const"; import { SALEOR_API_URL_HEADER, SALEOR_AUTHORIZATION_BEARER_HEADER } from "@saleor/app-sdk/const";
import { AppIcon, TitleBar } from "@saleor/apps-shared";
import { ConfirmButton, ConfirmButtonTransitionState, makeStyles } from "@saleor/macaw-ui"; import { ConfirmButton, ConfirmButtonTransitionState, makeStyles } from "@saleor/macaw-ui";
import { ChangeEvent, SyntheticEvent, useEffect, useState } from "react"; import { ChangeEvent, SyntheticEvent, useEffect, useState } from "react";
import AccessWarning from "../components/AccessWarning/AccessWarning"; import AccessWarning from "../components/AccessWarning/AccessWarning";
import useAppApi from "../hooks/useAppApi"; import useAppApi from "../hooks/useAppApi";
import { AppColumnsLayout } from "../lib/ui/app-columns-layout"; import { AppColumnsLayout } from "../lib/ui/app-columns-layout";
import { AppIcon } from "../lib/ui/app-icon";
import { MainBar } from "../lib/ui/main-bar";
import useDashboardNotifier from "../utils/useDashboardNotifier"; import useDashboardNotifier from "../utils/useDashboardNotifier";
interface ConfigurationField { interface ConfigurationField {
@ -218,8 +218,8 @@ function Configuration() {
return ( return (
<div> <div>
<MainBar <TitleBar
icon={<AppIcon />} icon={<AppIcon theme="rgb(58, 86, 199)" text="K" />}
bottomMargin bottomMargin
name="Saleor Klaviyo App" name="Saleor Klaviyo App"
author="By Saleor Commerce" author="By Saleor Commerce"

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,9 @@ const { withSentryConfig } = require("@sentry/nextjs");
const isSentryPropertiesInEnvironment = const isSentryPropertiesInEnvironment =
process.env.SENTRY_AUTH_TOKEN && process.env.SENTRY_PROJECT && process.env.SENTRY_ORG; process.env.SENTRY_AUTH_TOKEN && process.env.SENTRY_PROJECT && process.env.SENTRY_ORG;
/**
* @type {import('next').NextConfig}
*/
const moduleExports = { const moduleExports = {
reactStrictMode: true, reactStrictMode: true,
images: { images: {
@ -18,7 +21,7 @@ const moduleExports = {
}, },
], ],
}, },
transpilePackages: ["@saleor/apps-shared"],
sentry: { sentry: {
// Use `hidden-source-map` rather than `source-map` as the Webpack `devtool` // Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
// for client-side builds. (This will be the default starting in // for client-side builds. (This will be the default starting in

View file

@ -36,7 +36,8 @@
"react-hook-form": "^7.39.1", "react-hook-form": "^7.39.1",
"react-instantsearch-hooks-web": "^6.38.0", "react-instantsearch-hooks-web": "^6.38.0",
"react-query": "^3.39.2", "react-query": "^3.39.2",
"urql": "^3.0.3" "urql": "^3.0.3",
"@saleor/apps-shared": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@graphql-codegen/cli": "2.13.11", "@graphql-codegen/cli": "2.13.11",

View file

@ -1,23 +0,0 @@
import { makeStyles } from "@saleor/macaw-ui";
import Image from "next/image";
import appIcon from "./AppIcon.svg";
const useStyles = makeStyles({
appIconContainer: {
background: `rgb(199, 58, 63)`,
padding: 10,
borderRadius: "50%",
width: 50,
height: 50,
},
});
export const AppIcon = () => {
const styles = useStyles();
return (
<div className={styles.appIconContainer}>
<Image width={30} height={30} alt="icon" src={appIcon} />
</div>
);
};

View file

@ -1,52 +0,0 @@
import { makeStyles } from "@saleor/macaw-ui";
import { ReactNode } from "react";
import { Paper, PaperProps } from "@material-ui/core";
import clsx from "clsx";
const useStyles = makeStyles((theme) => ({
root: {
height: 96,
padding: "0 32px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
},
leftColumn: {
marginRight: "auto",
},
rightColumn: {},
iconColumn: {
marginRight: 24,
},
appName: { fontSize: 24, margin: 0 },
appAuthor: {
fontSize: 12,
textTransform: "uppercase",
color: theme.palette.text.secondary,
fontWeight: 500,
margin: 0,
},
}));
type Props = {
name: string;
author: string;
rightColumnContent?: ReactNode;
icon?: ReactNode;
} & PaperProps;
export const MainBar = ({ name, author, rightColumnContent, className, icon }: Props) => {
const styles = useStyles();
return (
<Paper elevation={0} className={clsx(styles.root, className)}>
{icon && <div className={styles.iconColumn}>{icon}</div>}
<div className={styles.leftColumn}>
<h1 className={styles.appName}>{name}</h1>
<h1 className={styles.appAuthor}>{author}</h1>
</div>
<div className={styles.rightColumn}>{rightColumnContent}</div>
</Paper>
);
};

View file

@ -1,8 +1,10 @@
import { GitHub, OfflineBoltOutlined } from "@material-ui/icons"; import { GitHub, OfflineBoltOutlined } from "@material-ui/icons";
import { Button, makeStyles } from "@saleor/macaw-ui"; import { Button, makeStyles } from "@saleor/macaw-ui";
import { MainBar } from "./MainBar";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge"; import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { AppIcon } from "./AppIcon"; import appIcon from "./AppIcon.svg";
import { AppIcon, TitleBar } from "@saleor/apps-shared";
import Image from "next/image";
const useStyles = makeStyles({ const useStyles = makeStyles({
buttonsGrid: { display: "flex", gap: 10 }, buttonsGrid: { display: "flex", gap: 10 },
@ -23,13 +25,13 @@ export const SearchAppMainBar = () => {
actions.Redirect({ actions.Redirect({
to: url, to: url,
newContext: true, newContext: true,
}), })
); );
}; };
return ( return (
<MainBar <TitleBar
icon={<AppIcon />} icon={<AppIcon theme={`rgb(199, 58, 63)`} icon={<Image src={appIcon} alt="Search App" />} />}
className={styles.topBar} className={styles.topBar}
name="Saleor Search" name="Saleor Search"
author="By Saleor Commerce" author="By Saleor Commerce"

View file

@ -1,7 +0,0 @@
export function isInIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}

View file

@ -1,6 +1,6 @@
import { useAppBridge, withAuthorization } from "@saleor/app-sdk/app-bridge"; import { useAppBridge, withAuthorization } from "@saleor/app-sdk/app-bridge";
import ConfigurationView from "../components/ConfigurationView"; import ConfigurationView from "../components/ConfigurationView";
import { isInIframe } from "../lib/is-in-iframe"; import { isInIframe } from "@saleor/apps-shared";
import { LinearProgress } from "@material-ui/core"; import { LinearProgress } from "@material-ui/core";
const IndexPage = () => { const IndexPage = () => {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@ const isSentryPropertiesInEnvironment =
process.env.SENTRY_AUTH_TOKEN && process.env.SENTRY_PROJECT && process.env.SENTRY_ORG; process.env.SENTRY_AUTH_TOKEN && process.env.SENTRY_PROJECT && process.env.SENTRY_ORG;
const moduleExports = { const moduleExports = {
transpilePackages: ["@saleor/apps-shared"],
eslint: { eslint: {
ignoreDuringBuilds: false, ignoreDuringBuilds: false,
}, },

View file

@ -22,7 +22,6 @@
"@sentry/nextjs": "^7.30.0", "@sentry/nextjs": "^7.30.0",
"@urql/exchange-auth": "^1.0.0", "@urql/exchange-auth": "^1.0.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"eslint-config-next": "13.1.4",
"graphql": "^16.5.0", "graphql": "^16.5.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"jose": "^4.11.2", "jose": "^4.11.2",
@ -31,7 +30,8 @@
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"urql": "^3.0.3", "urql": "^3.0.3",
"usehooks-ts": "^2.9.1" "usehooks-ts": "^2.9.1",
"@saleor/apps-shared": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@graphql-codegen/cli": "2.7.0", "@graphql-codegen/cli": "2.7.0",

View file

@ -1,28 +0,0 @@
import { Typography } from "@material-ui/core";
import { makeStyles } from "@saleor/macaw-ui";
const useStyles = makeStyles({
appIconContainer: {
background: `rgb(95, 58, 199)`,
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
borderRadius: "50%",
color: "#fff",
width: 50,
height: 50,
},
});
export const AppIcon = () => {
const styles = useStyles();
return (
<div className={styles.appIconContainer}>
<div>
<Typography variant="h2">S</Typography>
</div>
</div>
);
};

View file

@ -1,52 +0,0 @@
import { makeStyles } from "@saleor/macaw-ui";
import { ReactNode } from "react";
import { Paper, PaperProps } from "@material-ui/core";
import clsx from "clsx";
const useStyles = makeStyles((theme) => ({
root: {
height: 96,
padding: "0 32px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
},
leftColumn: {
marginRight: "auto",
},
rightColumn: {},
iconColumn: {
marginRight: 24,
},
appName: { fontSize: 24, margin: 0 },
appAuthor: {
fontSize: 12,
textTransform: "uppercase",
color: theme.palette.text.secondary,
fontWeight: 500,
margin: 0,
},
}));
type Props = {
name: string;
author: string;
rightColumnContent?: ReactNode;
icon?: ReactNode;
} & PaperProps;
export const MainBar = ({ name, author, rightColumnContent, className, icon }: Props) => {
const styles = useStyles();
return (
<Paper elevation={0} className={clsx(styles.root, className)}>
{icon && <div className={styles.iconColumn}>{icon}</div>}
<div className={styles.leftColumn}>
<h1 className={styles.appName}>{name}</h1>
<h1 className={styles.appAuthor}>{author}</h1>
</div>
<div className={styles.rightColumn}>{rightColumnContent}</div>
</Paper>
);
};

View file

@ -1,8 +1,8 @@
import { GitHub, OfflineBoltOutlined } from "@material-ui/icons"; import { GitHub, OfflineBoltOutlined } from "@material-ui/icons";
import { Button, makeStyles } from "@saleor/macaw-ui"; import { Button, makeStyles } from "@saleor/macaw-ui";
import { MainBar } from "../MainBar/MainBar"; import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { AppIcon } from "../AppIcon/AppIcon"; import { AppIcon, TitleBar } from "@saleor/apps-shared";
const useStyles = makeStyles({ const useStyles = makeStyles({
buttonsGrid: { display: "flex", gap: 10 }, buttonsGrid: { display: "flex", gap: 10 },
@ -28,8 +28,8 @@ export const SlackAppMainBar = () => {
}; };
return ( return (
<MainBar <TitleBar
icon={<AppIcon />} icon={<AppIcon theme={`rgb(95, 58, 199)`} text="S" />}
className={styles.topBar} className={styles.topBar}
name="Saleor Slack" name="Saleor Slack"
author="By Saleor Commerce" author="By Saleor Commerce"

View file

@ -8,7 +8,7 @@ import SaleorLogoImage from "../assets/saleor-logo.svg";
import SaleorLogoImageDark from "../assets/saleor-logo-dark.svg"; import SaleorLogoImageDark from "../assets/saleor-logo-dark.svg";
import { InputAdornment, LinearProgress, TextField, Typography } from "@material-ui/core"; import { InputAdornment, LinearProgress, TextField, Typography } from "@material-ui/core";
import { Button, makeStyles, useTheme } from "@saleor/macaw-ui"; import { Button, makeStyles, useTheme } from "@saleor/macaw-ui";
import { isInIframe } from "../lib/is-in-iframe"; import { isInIframe } from "@saleor/apps-shared";
const useStyles = makeStyles({ const useStyles = makeStyles({
root: { root: {

View file

@ -13,7 +13,8 @@
"lint": "turbo run lint", "lint": "turbo run lint",
"test": "turbo run test", "test": "turbo run test",
"test:ci": "turbo run test:ci", "test:ci": "turbo run test:ci",
"format": "prettier --write \"**/*.{ts,tsx,md}\"" "format": "prettier --write \"**/*.{ts,tsx,md}\"",
"generate": "turbo run generate"
}, },
"devDependencies": { "devDependencies": {
"@changesets/cli": "^2.26.0", "@changesets/cli": "^2.26.0",

View file

@ -0,0 +1,4 @@
{
"root": true,
"extends": ["saleor"]
}

3
packages/shared/index.ts Normal file
View file

@ -0,0 +1,3 @@
export * from "./src/is-in-iframe";
export * from "./src/title-bar/title-bar";
export * from "./src/app-icon/app-icon";

View file

@ -1,5 +1,19 @@
{ {
"name": "@saleor/apps-shared", "name": "@saleor/apps-shared",
"version": "1.0.1", "version": "1.0.1",
"dependencies": {} "dependencies": {},
"devDependencies": {
"eslint-config-saleor": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@material-ui/core": "^4.12.4",
"@material-ui/icons": "^4.11.3",
"@material-ui/lab": "4.0.0-alpha.61",
"@saleor/app-sdk": "0.26.1",
"@saleor/macaw-ui": "^0.7.2",
"clsx": "^1.2.1"
},
"main": "index.ts"
} }

View file

@ -0,0 +1,38 @@
import { Typography } from "@material-ui/core";
import { makeStyles } from "@saleor/macaw-ui";
import { HTMLProps, ReactNode } from "react";
import clsx from "clsx";
const useStyles = makeStyles(({ props }) => {
console.log(props);
return {
appIconContainer: {
background: "rgb(58, 86, 199)",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
borderRadius: "50%",
color: "#fff",
width: 50,
height: 50,
},
};
});
type Props = HTMLProps<HTMLDivElement> & {
theme: string;
text?: string;
icon?: ReactNode;
};
export function AppIcon({ className, children, text, icon, ...props }: Props) {
const styles = useStyles();
return (
<div className={clsx(styles.appIconContainer, className)} {...props}>
{text && <Typography variant="h2">{text}</Typography>}
{icon && icon}
</div>
);
}

View file

@ -3,9 +3,20 @@ import { makeStyles } from "@saleor/macaw-ui";
import clsx from "clsx"; import clsx from "clsx";
import { ReactNode } from "react"; import { ReactNode } from "react";
const height = 96;
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
container: {
position: "relative",
height: height,
},
root: { root: {
height: 96, zIndex: 300,
position: "fixed",
left: 0,
right: 0,
top: 0,
height: height,
padding: "0 32px", padding: "0 32px",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
@ -40,7 +51,7 @@ type Props = {
bottomMargin?: boolean; bottomMargin?: boolean;
} & PaperProps; } & PaperProps;
export function MainBar({ export function TitleBar({
name, name,
author, author,
rightColumnContent, rightColumnContent,
@ -51,6 +62,7 @@ export function MainBar({
const styles = useStyles(); const styles = useStyles();
return ( return (
<div className={styles.container}>
<Paper <Paper
elevation={0} elevation={0}
className={clsx(styles.root, className, { className={clsx(styles.root, className, {
@ -64,5 +76,8 @@ export function MainBar({
</div> </div>
<div className={styles.rightColumn}>{rightColumnContent}</div> <div className={styles.rightColumn}>{rightColumnContent}</div>
</Paper> </Paper>
</div>
); );
} }
TitleBar.height = height;

File diff suppressed because it is too large Load diff

View file

@ -73,6 +73,9 @@
"cache": false "cache": false
}, },
"test": {}, "test": {},
"test:ci": {} "test:ci": {},
"generate": {
"outputs": ["generated/"]
}
} }
} }