Skip to content

Commit

Permalink
feat: Add aboud and license notice modals.
Browse files Browse the repository at this point in the history
* Update NOTICE file to be a bit clearer/complete
* Add simple about dialog that acknowledges contributors and sponsors
* Add License NOTICE link in the footer, to be sure it's present
  and remains for any derivates.
  • Loading branch information
petejohanson committed Aug 7, 2024
1 parent ba15adc commit b9d2692
Show file tree
Hide file tree
Showing 35 changed files with 337 additions and 34 deletions.
5 changes: 3 additions & 2 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
ZMK Studio
Copyright 2024 The ZMK Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
This product includes software developend by the ZMK Project (https://zmk.dev/),
licensed under the Apache License, Version 2.0 (the "License").
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0
Expand Down
234 changes: 234 additions & 0 deletions src/AboutModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import { useModalRef } from "./misc/useModalRef";

import cannonKeys from "./assets/cannonkeys.png";
import cannonKeysDarkMode from "./assets/cannonkeys-dark-mode.png";

import niceAndTyperactive from "./assets/niceandtyperactive.png";
import niceAndTyperactiveDarkMode from "./assets/niceandtyperactive-dark-mode.png";

import kinesis from "./assets/kinesis.png";
import kinesisDarkMode from "./assets/kinesis-dark-mode.png";

import keychron from "./assets/keychron.png";
import keychronDarkMode from "./assets/keychron-dark-mode.png";

import littleKeyboards from "./assets/littlekeyboards.avif";
import littleKeyboardsDarkMode from "./assets/littlekeyboards-dark-mode.avif";

import keebmaker from "./assets/keebmaker.png";
import keebmakerDarkMode from "./assets/keebmaker-dark-mode.png";

import keebio from "./assets/keebio.avif";

import deskHero from "./assets/deskhero.webp";
import deskHeroDarkMode from "./assets/deskhero-dark-mode.webp";

import mode from "./assets/mode.png";
import modeDarkMode from "./assets/mode-dark-mode.png";

import mechlovin from "./assets/mechloving.png";
import mechlovinDarkMode from "./assets/mechlovin-dark-mode.png";

import phaseByte from "./assets/phasebyte.png";

import keycapsss from "./assets/keycapsss.png";
import keycapsssDarkMode from "./assets/keycapsss-dark-mode.png";

import mekibo from "./assets/mekibo.png";
import mekiboDarkMode from "./assets/mekibo-dark-mode.png";

import splitkb from "./assets/splitkb.png";
import splitkbDarkMode from "./assets/splitkb-dark-mode.png";

export interface AboutModalProps {
open: boolean;
onClose: () => void;
}

enum SponsorSize {
Large,
Medium,
Small,
}

const sponsors = [
{
level: "Platinum",
size: SponsorSize.Large,
vendors: [
{
name: "nice!keyboards / typeractive",
img: niceAndTyperactive,
darkModeImg: niceAndTyperactiveDarkMode,
url: "https://typeractive.xyz/",
},
{
name: "Kineses",
img: kinesis,
darkModeImg: kinesisDarkMode,
url: "https://kinesis-ergo.com/",
},
],
},
{
level: "Gold+",
size: SponsorSize.Large,
vendors: [
{
name: "CannonKeys",
img: cannonKeys,
darkModeImg: cannonKeysDarkMode,
url: "https://cannonkeys.com/",
},
{
name: "Keychron",
img: keychron,
darkModeImg: keychronDarkMode,
url: "https://keychron.com/",
},
],
},
{
level: "Gold",
size: SponsorSize.Medium,
vendors: [
{
name: "Little Keyboards",
img: littleKeyboards,
darkModeImg: littleKeyboardsDarkMode,
url: "https://littlekeyboards.com/",
},
{
name: "Keebmaker",
img: keebmaker,
darkModeImg: keebmakerDarkMode,
url: "https://keebmaker.com/",
},
],
},
{
level: "Silver",
size: SponsorSize.Medium,
vendors: [
{
name: "keeb.io",
img: keebio,
url: "https://keeb.io/",
},
{
name: "Mode Designs",
img: mode,
darkModeImg: modeDarkMode,
url: "https://modedesigns.com/",
},
],
},
{
level: "Bronze",
size: SponsorSize.Small,
vendors: [
{
name: "deskhero",
img: deskHero,
darkModeImg: deskHeroDarkMode,
url: "https://deskhero.ca/",
},
{
name: "PhaseByte",
img: phaseByte,
url: "https://phasebyte.com/",
},
{
name: "Mechlovin'",
img: mechlovin,
darkModeImg: mechlovinDarkMode,
url: "https://mechlovin.studio/",
},
],
},
{
level: "Additional",
size: SponsorSize.Small,
vendors: [
{
name: "splitkb.com",
img: splitkb,
darkModeImg: splitkbDarkMode,
url: "https://splitkb.com/",
},
{
name: "keycapsss",
img: keycapsss,
darkModeImg: keycapsssDarkMode,
url: "https://keycapsss.com/",
},
{
name: "mekibo",
img: mekibo,
darkModeImg: mekiboDarkMode,
url: "https://mekibo.com/",
},
],
},
];

export const AboutModal = ({ open, onClose }: AboutModalProps) => {
const ref = useModalRef(open);

return (
<dialog
ref={ref}
onClose={onClose}
className="p-5 rounded-lg border-text-base border min-w-min w-[70vw]"
>
<p className="py-1">
ZMK Studio is made possible thanks to the generous donation of time from
our contributors, as well as the financial sponsorship from the
following vendors:
</p>
<div className="grid gap-2 auto-rows-auto grid-cols-[auto_minmax(min-content,1fr)] justify-items-center items-center">
{sponsors.map((s) => {
const heightVariants = {
[SponsorSize.Large]: "h-16",
[SponsorSize.Medium]: "h-12",
[SponsorSize.Small]: "h-8",
};

return (
<>
<label>{s.level}</label>
<div
className={`grid grid-rows-1 gap-x-1 auto-cols-fr grid-flow-col justify-items-center items-center ${
heightVariants[s.size]
}`}
>
{s.vendors.map((v) => {
const maxSizeVariants = {
[SponsorSize.Large]: "max-h-16",
[SponsorSize.Medium]: "max-h-12",
[SponsorSize.Small]: "max-h-8",
};

return (
<a href={v.url} target="_blank">
<picture aria-label={v.name}>
{v.darkModeImg && (
<source
className={maxSizeVariants[s.size]}
srcSet={v.darkModeImg}
media="(prefers-color-scheme: dark)"
/>
)}
<img className={maxSizeVariants[s.size]} src={v.img} />
</picture>
</a>
);
})}
</div>
</>
);
})}
</div>
</dialog>
);
};
16 changes: 15 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import { LockState } from "@zmkfirmware/zmk-studio-ts-client/core";
import { LockStateContext } from "./rpc/LockStateContext";
import { UnlockModal } from "./UnlockModal";
import { valueAfter } from "./misc/async";
import { AppFooter } from "./AppFooter";
import { AboutModal } from "./AboutModal";
import { LicenseNoticeModal } from "./misc/LicenseNoticeModal";

declare global {
interface Window {
Expand Down Expand Up @@ -153,6 +156,8 @@ function App() {
string | undefined
>(undefined);
const [doIt, undo, redo, canUndo, canRedo, reset] = useUndoRedo();
const [showAbout, setShowAbout] = useState(false);
const [showLicenseNotice, setShowLicenseNotice] = useState(false);

const [lockState, setLockState] = useState<LockState>(
LockState.ZMK_STUDIO_CORE_LOCK_STATE_LOCKED
Expand Down Expand Up @@ -196,7 +201,12 @@ function App() {
connect(t, setConn, setConnectedDeviceName)
}
/>
<div className="bg-bg-base text-text-base h-full w-full min-w-min inline-grid grid-cols-[auto] grid-rows-[auto_1fr]">
<AboutModal open={showAbout} onClose={() => setShowAbout(false)} />
<LicenseNoticeModal
open={showLicenseNotice}
onClose={() => setShowLicenseNotice(false)}
/>
<div className="bg-bg-base text-text-base h-full w-full min-w-min inline-grid grid-cols-[auto] grid-rows-[auto_1fr_auto]">
<AppHeader
connectedDeviceLabel={connectedDeviceName}
canUndo={canUndo}
Expand All @@ -205,6 +215,10 @@ function App() {
onRedo={redo}
/>
<Keyboard />
<AppFooter
onShowAbout={() => setShowAbout(true)}
onShowLicenseNotice={() => setShowLicenseNotice(true)}
/>
</div>
</UndoRedoContext.Provider>
</LockStateContext.Provider>
Expand Down
24 changes: 24 additions & 0 deletions src/AppFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface AppFooterProps {
onShowAbout: () => void;
onShowLicenseNotice: () => void;
}

export const AppFooter = ({
onShowAbout,
onShowLicenseNotice,
}: AppFooterProps) => {
return (
<div className="grid justify-center m-1">
<div>
<span>&copy; 2024 - The ZMK Contributors</span> -{" "}
<a href="#" onClick={onShowAbout}>
About ZMK Studio
</a>{" "}
-{" "}
<a href="#" onClick={onShowLicenseNotice}>
License NOTICE
</a>
</div>
</div>
);
};
17 changes: 3 additions & 14 deletions src/ConnectModal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";

import type { RpcTransport } from "@zmkfirmware/zmk-studio-ts-client/transport/index";
import type { AvailableDevice } from "./tauri/index";
import { SignalIcon } from "@heroicons/react/24/outline";
import { Key, ListBox, ListBoxItem, Selection } from "react-aria-components";
import { useModalRef } from "./misc/useModalRef";

export type TransportFactory = {
label: string;
Expand Down Expand Up @@ -199,19 +200,7 @@ export const ConnectModal = ({
transports,
onTransportCreated,
}: ConnectModalProps) => {
const dialog = useRef<HTMLDialogElement | null>(null);

useEffect(() => {
if (dialog.current) {
if (open) {
if (!dialog.current.open) {
dialog.current.showModal();
}
} else {
dialog.current.close();
}
}
}, [open]);
const dialog = useModalRef(open || false);

const useSimplePicker = useMemo(
() => transports.every((t) => !t.pick_and_connect),
Expand Down
24 changes: 7 additions & 17 deletions src/UnlockModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useContext, useEffect, useRef } from "react";
import { useContext, useMemo } from "react";

import type { RpcTransport } from "@zmkfirmware/zmk-studio-ts-client/transport/index";
import type { AvailableDevice } from "./tauri/index";
import { LockStateContext } from "./rpc/LockStateContext";
import { LockState } from "@zmkfirmware/zmk-studio-ts-client/core";
import { ConnectionContext } from "./rpc/ConnectionContext";
import { useModalRef } from "./misc/useModalRef";

export type TransportFactory = {
label: string;
Expand All @@ -18,25 +19,14 @@ export type TransportFactory = {
export interface UnlockModalProps {}

export const UnlockModal = ({}: UnlockModalProps) => {
const dialog = useRef<HTMLDialogElement | null>(null);

let conn = useContext(ConnectionContext);
let lockState = useContext(LockStateContext);

useEffect(() => {
let open =
!!conn && lockState != LockState.ZMK_STUDIO_CORE_LOCK_STATE_UNLOCKED;

if (dialog.current) {
if (open) {
if (!dialog.current.open) {
dialog.current.showModal();
}
} else {
dialog.current.close();
}
}
}, [lockState, conn]);
let open = useMemo(
() => !!conn && lockState != LockState.ZMK_STUDIO_CORE_LOCK_STATE_UNLOCKED,
[conn, lockState]
);
const dialog = useModalRef(open);

return (
<dialog ref={dialog} className="p-5 rounded-lg border-text-base border">
Expand Down
Binary file added src/assets/cannonkeys-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/cannonkeys.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/deskhero-dark-mode.webp
Binary file not shown.
Binary file added src/assets/deskhero.webp
Binary file not shown.
Binary file added src/assets/keebio.avif
Binary file not shown.
Binary file added src/assets/keebmaker-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/keebmaker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/keycapsss-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/keycapsss.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/keychron-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/keychron.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/kinesis-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/kinesis.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/littlekeyboards-dark-mode.avif
Binary file not shown.
Binary file added src/assets/littlekeyboards.avif
Binary file not shown.
Binary file added src/assets/mechlovin-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mechloving.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mekibo-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mekibo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mode-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/mode.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/niceandtyperactive-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/niceandtyperactive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/phasebyte.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/splitkb-dark-mode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/splitkb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit b9d2692

Please sign in to comment.