diff --git a/examples/next-app/components/HomePage.tsx b/examples/next-app/components/HomePage.tsx index 6a95fab..65f17fb 100644 --- a/examples/next-app/components/HomePage.tsx +++ b/examples/next-app/components/HomePage.tsx @@ -1,6 +1,6 @@ "use client" -import { IpProvider, useIpContext, IpWidget, IpPolicyAccordion, IpRoyaltyPieChart, IpGraph, Button } from "@storyprotocol/storykit" +import { IpProvider, useIpContext, IpWidget, IpPolicyAccordion, IpRoyaltyPieChart, IpGraph } from "@storyprotocol/storykit" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import React from "react" diff --git a/packages/storykit/package.json b/packages/storykit/package.json index a71796b..ab4670e 100644 --- a/packages/storykit/package.json +++ b/packages/storykit/package.json @@ -1,7 +1,7 @@ { "name": "@storyprotocol/storykit", "author": "storyprotocol engineering ", - "version": "0.1.8", + "version": "0.1.9", "type": "module", "exports": { ".": { diff --git a/packages/storykit/src/components/IpPolicyAccordion/IpPolicyAccordion.tsx b/packages/storykit/src/components/IpPolicyAccordion/IpPolicyAccordion.tsx index a4a5c10..0305502 100644 --- a/packages/storykit/src/components/IpPolicyAccordion/IpPolicyAccordion.tsx +++ b/packages/storykit/src/components/IpPolicyAccordion/IpPolicyAccordion.tsx @@ -1,72 +1,13 @@ -import { POLICY_TYPE } from "@/lib/types" import { cn, getPolicyTypeByPILData } from "@/lib/utils" import { useIpContext } from "@/providers" import { cva } from "class-variance-authority" -import { CircleCheck, CircleMinus } from "lucide-react" import { useState } from "react" import { FaCaretDown, FaCaretUp } from "react-icons/fa6" import "../../global.css" +import LicenseTerms from "../LicenseTerms/LicenseTerms" import "./styles.css" -const CANS = { - REMIX: "Remix this work", - INCLUDE: "Include this work in their own work(s)", - CREDIT: "Credit you appropriately", - DISTRIBUTE: "Distribute their remix anywhere", - PURCHASE_RIGHTS: "Purchase the right to use your creation (for a price you set) and register it into Story Protocol", - CREATOR_CREDIT: "Credit you as the creator", - PUBLISH: "Display / publish the work in any medium", -} - -const ShowCans = ({ type }: { type: string }) => { - switch (type) { - case POLICY_TYPE.NON_COMMERCIAL_SOCIAL_REMIXING: - return [CANS.REMIX, CANS.INCLUDE, CANS.CREDIT, CANS.DISTRIBUTE] - break - case POLICY_TYPE.COMMERCIAL_USE: - return [CANS.PURCHASE_RIGHTS, CANS.CREATOR_CREDIT, CANS.PUBLISH] - break - case POLICY_TYPE.COMMERCIAL_REMIX: - return [CANS.REMIX, CANS.INCLUDE, CANS.CREDIT, CANS.DISTRIBUTE] - break - case POLICY_TYPE.OPEN_DOMAIN: - return [CANS.REMIX, CANS.INCLUDE, CANS.DISTRIBUTE, CANS.PUBLISH] - break - default: - return [] - break - } -} - -const CANNOTS = { - RESELL: "Resell your original work", - COMMERCIALIZE: "Commercialize the remix", - CLAIM_AS_ORIGINAL: "Claim credit for the remix (as original work)", - CLAIM: "Claim your work as their own", - REMIX: "Create remixes of the commercial use.", -} - -const ShowCannots = ({ type }: { type: string }) => { - switch (type) { - case POLICY_TYPE.NON_COMMERCIAL_SOCIAL_REMIXING: - return [CANNOTS.RESELL, CANNOTS.COMMERCIALIZE, CANNOTS.CLAIM_AS_ORIGINAL] - break - case POLICY_TYPE.COMMERCIAL_USE: - return [CANNOTS.CLAIM, CANNOTS.REMIX, CANNOTS.RESELL] - break - case POLICY_TYPE.COMMERCIAL_REMIX: - return [CANNOTS.RESELL, CANNOTS.COMMERCIALIZE, CANNOTS.CLAIM_AS_ORIGINAL] - break - case POLICY_TYPE.OPEN_DOMAIN: - return [CANNOTS.RESELL, CANNOTS.COMMERCIALIZE, CANNOTS.CLAIM_AS_ORIGINAL, CANNOTS.CLAIM] - break - default: - return [CANNOTS.RESELL, CANNOTS.CLAIM, CANNOTS.REMIX] - break - } -} - const policiesStyles = cva("", { variants: { size: { @@ -85,8 +26,6 @@ function IpPolicyAccordion({ size = "medium" }: IpPolicyAccordionProps) { const { policyData } = useIpContext() const [expanded, setExpanded] = useState(0) - const iconWidth = size === "small" ? 16 : size === "medium" ? 20 : 24 - return policyData?.length ? (
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} @@ -106,30 +45,7 @@ function IpPolicyAccordion({ size = "medium" }: IpPolicyAccordionProps) { expanded === index && "skIpPolicyAccordion__item-list--expanded" )} > -
- {ShowCans({ type: getPolicyTypeByPILData(policy.licenseTerms) }).length ? ( - <> -
Others Can
-
- {ShowCans({ type: getPolicyTypeByPILData(policy.licenseTerms) }).map((can, index) => ( -
- - {can} -
- ))} -
- - ) : null} -
Others Cannot
-
- {ShowCannots({ type: getPolicyTypeByPILData(policy.licenseTerms) }).map((can, index) => ( -
- - {can} -
- ))} -
-
+
{index < policyData.length - 1 &&
} diff --git a/packages/storykit/src/components/IpPolicyAccordion/styles.css b/packages/storykit/src/components/IpPolicyAccordion/styles.css index 0cefe8e..bcf4105 100644 --- a/packages/storykit/src/components/IpPolicyAccordion/styles.css +++ b/packages/storykit/src/components/IpPolicyAccordion/styles.css @@ -10,60 +10,17 @@ } .skIpPolicyAccordion__item-list { - @apply flex w-full items-center justify-between overflow-hidden h-0; + @apply flex w-full overflow-hidden h-0; &.skIpPolicyAccordion__item-list--expanded { @apply h-auto; } } - .skIpPolicyAccordion__properties { - @apply flex flex-col pt-2 gap-2; - } - - .skIpPolicyAccordion__item-list-title { - @apply font-bold; - } - - .skIpPolicyAccordion__list { - @apply flex flex-col; - } - - .skIpPolicyAccordion__property { - @apply flex w-full items-center gap-2; - - &.skIpPolicyAccordion__property--can > svg { - @apply text-green-500; - } - - &.skIpPolicyAccordion__property--cannot > svg { - @apply text-red-500; - } - } - .skIpPolicyAccordion__divider { @apply border-b border-gray-200 w-full my-2; } - &.skIpPolicyAccordion--small { - @apply text-sm; - } - - &.skIpPolicyAccordion--medium { - @apply text-base; - - .policy-list { - @apply gap-1; - } - } - - &.skIpPolicyAccordion--large { - @apply text-lg; - .policy-list { - @apply gap-2; - } - } - &.skIpPolicyAccordion--no-policy { @apply text-slate-400; } diff --git a/packages/storykit/src/components/LicenseTerms/LicenseTerms.tsx b/packages/storykit/src/components/LicenseTerms/LicenseTerms.tsx new file mode 100644 index 0000000..7a6b9c5 --- /dev/null +++ b/packages/storykit/src/components/LicenseTerms/LicenseTerms.tsx @@ -0,0 +1,115 @@ +import { POLICY_TYPE, PolicyType } from "@/lib/types" +import { cn } from "@/lib/utils" +import { cva } from "class-variance-authority" +import { CircleCheck, CircleMinus } from "lucide-react" + +import "../../global.css" +import "./styles.css" + +const CANS = { + REMIX: "Remix this work", + INCLUDE: "Include this work in their own work(s)", + CREDIT: "Credit you appropriately", + DISTRIBUTE: "Distribute their remix anywhere", + PURCHASE_RIGHTS: "Purchase the right to use your creation (for a price you set) and register it into Story Protocol", + CREATOR_CREDIT: "Credit you as the creator", + PUBLISH: "Display / publish the work in any medium", +} + +const ShowCans = ({ type }: { type: string }) => { + switch (type) { + case POLICY_TYPE.NON_COMMERCIAL_SOCIAL_REMIXING: + return [CANS.REMIX, CANS.INCLUDE, CANS.CREDIT, CANS.DISTRIBUTE] + break + case POLICY_TYPE.COMMERCIAL_USE: + return [CANS.PURCHASE_RIGHTS, CANS.CREATOR_CREDIT, CANS.PUBLISH] + break + case POLICY_TYPE.COMMERCIAL_REMIX: + return [CANS.REMIX, CANS.INCLUDE, CANS.CREDIT, CANS.DISTRIBUTE] + break + case POLICY_TYPE.OPEN_DOMAIN: + return [CANS.REMIX, CANS.INCLUDE, CANS.DISTRIBUTE, CANS.PUBLISH] + break + default: + return [] + break + } +} + +const CANNOTS = { + RESELL: "Resell your original work", + COMMERCIALIZE: "Commercialize the remix", + CLAIM_AS_ORIGINAL: "Claim credit for the remix (as original work)", + CLAIM: "Claim your work as their own", + REMIX: "Create remixes of the commercial use.", +} + +const ShowCannots = ({ type }: { type: string }) => { + switch (type) { + case POLICY_TYPE.NON_COMMERCIAL_SOCIAL_REMIXING: + return [CANNOTS.RESELL, CANNOTS.COMMERCIALIZE, CANNOTS.CLAIM_AS_ORIGINAL] + break + case POLICY_TYPE.COMMERCIAL_USE: + return [CANNOTS.CLAIM, CANNOTS.REMIX, CANNOTS.RESELL] + break + case POLICY_TYPE.COMMERCIAL_REMIX: + return [CANNOTS.RESELL, CANNOTS.COMMERCIALIZE, CANNOTS.CLAIM_AS_ORIGINAL] + break + case POLICY_TYPE.OPEN_DOMAIN: + return [CANNOTS.RESELL, CANNOTS.COMMERCIALIZE, CANNOTS.CLAIM_AS_ORIGINAL, CANNOTS.CLAIM] + break + default: + return [CANNOTS.RESELL, CANNOTS.CLAIM, CANNOTS.REMIX] + break + } +} + +const policiesStyles = cva("", { + variants: { + size: { + small: "skLicenseTerms--small", + medium: "skLicenseTerms--medium", + large: "skLicenseTerms--large", + }, + }, +}) + +export type LicenseTermsProps = { + size?: "small" | "medium" | "large" + type: PolicyType +} + +function LicenseTerms({ size = "medium", type }: LicenseTermsProps) { + const iconWidth = size === "small" ? 16 : size === "medium" ? 20 : 24 + + return ( +
+
+ {ShowCans({ type }).length ? ( + <> +
Others Can
+
+ {ShowCans({ type }).map((can, index) => ( +
+ + {can} +
+ ))} +
+ + ) : null} +
Others Cannot
+
+ {ShowCannots({ type }).map((can, index) => ( +
+ + {can} +
+ ))} +
+
+
+ ) +} + +export default LicenseTerms diff --git a/packages/storykit/src/components/LicenseTerms/__docs__/LicenseTerms.mdx b/packages/storykit/src/components/LicenseTerms/__docs__/LicenseTerms.mdx new file mode 100644 index 0000000..9ebcd02 --- /dev/null +++ b/packages/storykit/src/components/LicenseTerms/__docs__/LicenseTerms.mdx @@ -0,0 +1,30 @@ +import { Canvas, Controls, Meta } from "@storybook/blocks" + +import * as LicenseTermsStory from "./LicenseTerms.stories" + + + +# LicenseTerms + +Displays the License Terms cans and cannots for specified license type. + +#### Example + + + + + +## Usage + +```ts + +import { LicenseTerms, POLICY_TYPE } from "@storyprotocol/storykit" + +const ExamplePage = () => { + return ( + + ); +}; + +export default ExamplePage; +``` diff --git a/packages/storykit/src/components/LicenseTerms/__docs__/LicenseTerms.stories.tsx b/packages/storykit/src/components/LicenseTerms/__docs__/LicenseTerms.stories.tsx new file mode 100644 index 0000000..8c601aa --- /dev/null +++ b/packages/storykit/src/components/LicenseTerms/__docs__/LicenseTerms.stories.tsx @@ -0,0 +1,29 @@ +import { POLICY_TYPE, PolicyType } from "@/index" +import type { Meta, StoryObj } from "@storybook/react" + +import Example from "../LicenseTerms" + +const meta = { + title: "UI/LicenseTerms", + component: Example, + parameters: { + layout: "centered", + }, + argTypes: { + type: { + options: Object.values(POLICY_TYPE), + }, + }, + args: {}, +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Select: Story = { + argTypes: {}, + args: { + size: "medium", + type: POLICY_TYPE.COMMERCIAL_REMIX as PolicyType, + }, +} diff --git a/packages/storykit/src/components/LicenseTerms/index.tsx b/packages/storykit/src/components/LicenseTerms/index.tsx new file mode 100644 index 0000000..aa9ec4e --- /dev/null +++ b/packages/storykit/src/components/LicenseTerms/index.tsx @@ -0,0 +1 @@ +export { default as LicenseTerms } from "./LicenseTerms" diff --git a/packages/storykit/src/components/LicenseTerms/styles.css b/packages/storykit/src/components/LicenseTerms/styles.css new file mode 100644 index 0000000..5ca6417 --- /dev/null +++ b/packages/storykit/src/components/LicenseTerms/styles.css @@ -0,0 +1,54 @@ +.skLicenseTerms { + @apply flex flex-col w-full min-w-48; + + .skLicenseTerms__properties { + @apply flex flex-col pt-2 gap-2; + } + + .skLicenseTerms__item-list-title { + @apply font-bold; + } + + .skLicenseTerms__list { + @apply flex flex-col; + } + + .skLicenseTerms__property { + @apply flex w-full items-center gap-2; + + &.skLicenseTerms__property--can > svg { + @apply text-green-500; + } + + &.skLicenseTerms__property--cannot > svg { + @apply text-red-500; + } + } + + .skLicenseTerms__divider { + @apply border-b border-gray-200 w-full my-2; + } + + &.skLicenseTerms--small { + @apply text-sm; + } + + &.skLicenseTerms--medium { + @apply text-base; + + .policy-list { + @apply gap-1; + } + } + + &.skLicenseTerms--large { + @apply text-lg; + .policy-list { + @apply gap-2; + } + } + + &.skLicenseTerms--no-policy { + @apply text-slate-400; + } +} diff --git a/packages/storykit/src/components/index.ts b/packages/storykit/src/components/index.ts index db39fd2..2057c98 100644 --- a/packages/storykit/src/components/index.ts +++ b/packages/storykit/src/components/index.ts @@ -1,5 +1,6 @@ export * from "./Button" export * from "./IpWidget" export * from "./IpGraph" +export * from "./LicenseTerms" export * from "./IpPolicyAccordion" export * from "./IpRoyaltyPieChart" diff --git a/packages/storykit/src/lib/types.ts b/packages/storykit/src/lib/types.ts index c5d6b4a..efb2716 100644 --- a/packages/storykit/src/lib/types.ts +++ b/packages/storykit/src/lib/types.ts @@ -1,12 +1,27 @@ import { Address } from "viem" -export const POLICY_TYPE = { - NON_COMMERCIAL_SOCIAL_REMIXING: "Non-Commercial Social Remixing", - COMMERCIAL_USE: "Commercial Use", - COMMERCIAL_REMIX: "Commercial Remix", - OPEN_DOMAIN: "Open Domain", - NO_DERIVATIVE: "No Derivative", -} +export enum POLICY_TYPE { + NON_COMMERCIAL_SOCIAL_REMIXING = "Non-Commercial Social Remixing", + COMMERCIAL_USE = "Commercial Use", + COMMERCIAL_REMIX = "Commercial Remix", + OPEN_DOMAIN = "Open Domain", + NO_DERIVATIVE = "No Derivative", +} + +// export const POLICY_TYPE = { +// NON_COMMERCIAL_SOCIAL_REMIXING: "Non-Commercial Social Remixing", +// COMMERCIAL_USE: "Commercial Use", +// COMMERCIAL_REMIX: "Commercial Remix", +// OPEN_DOMAIN: "Open Domain", +// NO_DERIVATIVE: "No Derivative", +// } + +export type PolicyType = + | POLICY_TYPE.NON_COMMERCIAL_SOCIAL_REMIXING + | POLICY_TYPE.COMMERCIAL_USE + | POLICY_TYPE.COMMERCIAL_REMIX + | POLICY_TYPE.OPEN_DOMAIN + | POLICY_TYPE.NO_DERIVATIVE export enum RESOURCE_TYPE { ASSET = "assets", diff --git a/packages/storykit/src/lib/utils.ts b/packages/storykit/src/lib/utils.ts index 4d6d29e..1fabd2c 100644 --- a/packages/storykit/src/lib/utils.ts +++ b/packages/storykit/src/lib/utils.ts @@ -1,7 +1,7 @@ import { type ClassValue, clsx } from "clsx" import { twMerge } from "tailwind-merge" -import { PILType, POLICY_TYPE } from "./types" +import { PILType, POLICY_TYPE, PolicyType } from "./types" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) @@ -28,7 +28,7 @@ export function camelize(str: string) { }) } -export function getPolicyTypeByPILData(pilData: PILType) { +export function getPolicyTypeByPILData(pilData: PILType): PolicyType { const { derivativesAttribution, derivativesAllowed, commercialUse, derivativesReciprocal } = pilData if (commercialUse) {