Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
45 changes: 45 additions & 0 deletions .storybook/images/logo-remix.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions docs/ProjectTemplates.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Meta } from '@storybook/blocks';
import { FlexBox, FlexBoxJustifyContent, FlexBoxWrap, Label, Link, WrappingType } from '@ui5/webcomponents-react';
import NextLogo from '@sb/images/logo-nextjs.svg';
import ViteLogo from '@sb/images/logo-vitejs.svg';
import RemixLogo from '@sb/images/logo-remix.svg';

<Meta title="Project Templates & Examples" />

Expand Down Expand Up @@ -108,6 +109,24 @@ A curated list of minimal project templates and examples to get started using UI
</li>
</ul>
</ProjectTemplate>
<ProjectTemplate
title={'Remix'}
logo={RemixLogo}
logoAttribution={'Remix.run Logo. Original Source: https://remix.run'}
href={'https://github.com/SAP/ui5-webcomponents-react/tree/main/examples/remix-ts'}
isTypeScript
>
<ul>
<li>
<Label>
Remix template using <code>remix-island</code>
</Label>
</li>
<li>
<Label>Theming</Label>
</li>
</ul>
</ProjectTemplate>
</FlexBox>

## Community Templates & Examples
Expand Down
84 changes: 84 additions & 0 deletions examples/remix-ts/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* This is intended to be a basic starting point for linting in your app.
* It relies on recommended configs out of the box for simplicity, but you can
* and should modify this configuration to best suit your team's needs.
*/

/** @type {import('eslint').Linter.Config} */
module.exports = {
root: true,
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
env: {
browser: true,
commonjs: true,
es6: true,
},
ignorePatterns: ["!**/.server", "!**/.client"],

// Base config
extends: ["eslint:recommended"],

overrides: [
// React
{
files: ["**/*.{js,jsx,ts,tsx}"],
plugins: ["react", "jsx-a11y"],
extends: [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {},
},
},
},

// Typescript
{
files: ["**/*.{ts,tsx}"],
plugins: ["@typescript-eslint", "import"],
parser: "@typescript-eslint/parser",
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
],
},

// Node
{
files: [".eslintrc.cjs"],
env: {
node: true,
},
},
],
};
5 changes: 5 additions & 0 deletions examples/remix-ts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules

/.cache
/build
.env
53 changes: 53 additions & 0 deletions examples/remix-ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# UI5 Web Components React - Remix Example

This example shows how to use the [Remix](https://remix.run) with UI5 Web Components for React.

## How to use this template

```bash
npx degit SAP/ui5-webcomponents-react/examples/remix-ts#main my-project
cd my-project
```

## Getting Started

First, install the node_modules:

```bash
npm install
```

Then, run the development server:

```bash
npm run dev
```

## Deployment

First, build your app for production:

```sh
npm run build
```

Then run the app in production mode:

```sh
npm start
```

Now you'll need to pick a host to deploy it to.

### DIY

If you're familiar with deploying Node applications, the built-in Remix app server is production-ready.

Make sure to deploy the output of `npm run build`

- `build/server`
- `build/client`

## Learn More

- 📖 See the [Remix docs](https://remix.run/docs) and the [Remix Vite docs](https://remix.run/docs/en/main/guides/vite) for details on supported features.
17 changes: 17 additions & 0 deletions examples/remix-ts/app/components/AppShell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import '@ui5/webcomponents-react/dist/Assets.js';
import { ThemeProvider } from '@ui5/webcomponents-react';
import { ReactNode } from 'react';
import { AppShellBar } from './AppShellBar';

interface AppShellProps {
children?: ReactNode | ReactNode[];
}

export function AppShell({ children }: AppShellProps) {
return (
<ThemeProvider>
<AppShellBar />
<div className="appScrollContainer">{children}</div>
</ThemeProvider>
);
}
5 changes: 5 additions & 0 deletions examples/remix-ts/app/components/AppShellBar.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.popover {
}
.popover::part(content) {
padding: 0;
}
71 changes: 71 additions & 0 deletions examples/remix-ts/app/components/AppShellBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import navBackIcon from '@ui5/webcomponents-icons/dist/nav-back.js';
import paletteIcon from '@ui5/webcomponents-icons/dist/palette.js';
import {
Button,
List,
ListMode,
ListPropTypes,
ResponsivePopover,
ResponsivePopoverDomRef,
ShellBar,
ShellBarItem,
ShellBarItemPropTypes,
StandardListItem
} from '@ui5/webcomponents-react';
import { useRef, useState } from 'react';
import classes from './AppShellBar.module.css';
import { getTheme, setTheme } from '@ui5/webcomponents-base/dist/config/Theme.js';
import { useLocation, useNavigate } from '@remix-run/react';

const THEMES = [
{ key: 'sap_horizon', value: 'Morning Horizon (Light)' },
{ key: 'sap_horizon_dark', value: 'Evening Horizon (Dark)' },
{ key: 'sap_horizon_hcb', value: 'Horizon High Contrast Black' },
{ key: 'sap_horizon_hcw', value: 'Horizon High Contrast White' }
];

export function AppShellBar() {
const navigate = useNavigate();
const { pathname } = useLocation();
const popoverRef = useRef<ResponsivePopoverDomRef | null>(null);
const [currentTheme, setCurrentTheme] = useState(getTheme);

const handleThemeSwitchItemClick: ShellBarItemPropTypes['onClick'] = (e) => {
popoverRef.current?.showAt(e.detail.targetRef);
};
const handleThemeSwitch: ListPropTypes['onSelectionChange'] = (e) => {
const { targetItem } = e.detail;
setTheme(targetItem.dataset.key!);
setCurrentTheme(targetItem.dataset.key!);
};

return (
<>
<ShellBar
primaryTitle={'UI5 Web Components for React Examples'}
secondaryTitle={'Remix.run App'}
startButton={
pathname !== '/' && (
<Button
icon={navBackIcon}
onClick={() => {
navigate(-1);
}}
/>
)
}
>
<ShellBarItem icon={paletteIcon} text="Change Theme" onClick={handleThemeSwitchItemClick} />
</ShellBar>
<ResponsivePopover ref={popoverRef} className={classes.popover}>
<List onSelectionChange={handleThemeSwitch} headerText="Change Theme" mode={ListMode.SingleSelect}>
{THEMES.map((theme) => (
<StandardListItem key={theme.key} selected={currentTheme === theme.key} data-key={theme.key}>
{theme.value}
</StandardListItem>
))}
</List>
</ResponsivePopover>
</>
);
}
32 changes: 32 additions & 0 deletions examples/remix-ts/app/components/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useNavigate } from '@remix-run/react';
import { List, ListItemType, ListPropTypes, StandardListItem, ValueState } from '@ui5/webcomponents-react';
import { Todo } from '~/mockData/todos';

interface TodoListProps {
items: Todo[];
}

export function TodoList({ items }: TodoListProps) {
const navigate = useNavigate();
const handleTodoClick: ListPropTypes['onItemClick'] = (event) => {
navigate(`/todos/${event.detail.item.dataset.id}`);
};

return (
<List onItemClick={handleTodoClick}>
{items.map((todo) => {
return (
<StandardListItem
key={todo.id}
data-id={todo.id}
type={ListItemType.Navigation}
additionalText={`${!todo.completed ? 'Not ' : ''}Completed`}
additionalTextState={todo.completed ? ValueState.Success : ValueState.None}
>
{todo.title}
</StandardListItem>
);
})}
</List>
);
}
22 changes: 22 additions & 0 deletions examples/remix-ts/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from '@remix-run/react';
import { startTransition, StrictMode } from 'react';
import { hydrateRoot } from 'react-dom/client';

import './globals.css';
import '@ui5/webcomponents-react/styles.css';
import '@ui5/webcomponents-icons/dist/Assets.js';

startTransition(() => {
hydrateRoot(
document.getElementById('root')!,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});
Loading