From 500ab8c6cbd9a43a26e0ee8e0fe4d38a880c7356 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 6 Jun 2025 22:54:11 +0100 Subject: [PATCH 1/5] badge check --- .../app/builder/features/topbar/publish.tsx | 25 ++++++++++++++++--- packages/sdk/src/core-templates.tsx | 3 ++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/builder/app/builder/features/topbar/publish.tsx b/apps/builder/app/builder/features/topbar/publish.tsx index f23eac27dd32..3c400d6ca3f8 100644 --- a/apps/builder/app/builder/features/topbar/publish.tsx +++ b/apps/builder/app/builder/features/topbar/publish.tsx @@ -51,6 +51,7 @@ import { $instances, $pages, $project, + $propsIndex, $publishedOrigin, $userPlanFeatures, } from "~/shared/nano-states"; @@ -217,8 +218,8 @@ const ChangeProjectDomain = ({ }; const $usedProFeatures = computed( - [$pages, $dataSources, $instances], - (pages, dataSources, instances) => { + [$pages, $dataSources, $instances, $propsIndex], + (pages, dataSources, instances, propsIndex) => { const features = new Map(); if (pages === undefined) { return features; @@ -258,15 +259,33 @@ const $usedProFeatures = computed( ); } } - // instances with animations + + const badgeFeature = "Made with Webstudio badge removal"; + // Badge should be rendered on free sites. + features.set(badgeFeature, undefined); + for (const instance of instances.values()) { const [namespace] = parseComponentName(instance.component); + // instances with animations if (namespace === "@webstudio-is/sdk-components-animation") { features.set( "Animation component", findAwarenessByInstanceId(pages, instances, instance.id) ); } + + // Made with Webstudio badge + if (instance.tag === "a") { + const props = propsIndex.propsByInstanceId.get(instance.id); + for (const prop of props ?? []) { + if ( + prop.name === "href" && + prop.value === "https://webstudio.is?via=badge" + ) { + features.delete(badgeFeature); + } + } + } } return features; } diff --git a/packages/sdk/src/core-templates.tsx b/packages/sdk/src/core-templates.tsx index 5c15406e5ad5..60104a0644ef 100644 --- a/packages/sdk/src/core-templates.tsx +++ b/packages/sdk/src/core-templates.tsx @@ -363,7 +363,8 @@ const builtWithWebstudioMeta: TemplateMeta = { Date: Fri, 6 Jun 2025 23:31:09 +0100 Subject: [PATCH 2/5] add home page check --- .../app/builder/features/topbar/publish.tsx | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/apps/builder/app/builder/features/topbar/publish.tsx b/apps/builder/app/builder/features/topbar/publish.tsx index 3c400d6ca3f8..a743b80580ce 100644 --- a/apps/builder/app/builder/features/topbar/publish.tsx +++ b/apps/builder/app/builder/features/topbar/publish.tsx @@ -70,6 +70,7 @@ import { AddDomain } from "./add-domain"; import { humanizeString } from "~/shared/string-utils"; import { trpcClient, nativeClient } from "~/shared/trpc/trpc-client"; import { + findTreeInstanceIds, isPathnamePattern, parseComponentName, type Templates, @@ -260,21 +261,32 @@ const $usedProFeatures = computed( } } - const badgeFeature = "Made with Webstudio badge removal"; - // Badge should be rendered on free sites. - features.set(badgeFeature, undefined); - + // Instances with animations. for (const instance of instances.values()) { const [namespace] = parseComponentName(instance.component); - // instances with animations if (namespace === "@webstudio-is/sdk-components-animation") { features.set( "Animation component", findAwarenessByInstanceId(pages, instances, instance.id) ); } + } - // Made with Webstudio badge + const badgeFeature = 'No "Built with Webstudio" badge'; + // Badge should be rendered on free sites on every page. + features.set(badgeFeature, undefined); + // We want to check the badge only on the home page + const homePageInstanceIds = findTreeInstanceIds( + instances, + pages.homePage.rootInstanceId + ); + // @todo add a check inside the slot that could be on the home page + for (const instanceId of homePageInstanceIds) { + const instance = instances.get(instanceId); + if (instance === undefined) { + continue; + } + // Built with Webstudio badge if (instance.tag === "a") { const props = propsIndex.propsByInstanceId.get(instance.id); for (const prop of props ?? []) { From 3a6a4d0674450b61192dd18bd2d333c1db280e59 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sat, 7 Jun 2025 12:02:25 +0100 Subject: [PATCH 3/5] add validation of the badge --- .../app/builder/features/topbar/publish.tsx | 89 ++++++++++--------- packages/sdk/src/core-templates.tsx | 2 +- 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/apps/builder/app/builder/features/topbar/publish.tsx b/apps/builder/app/builder/features/topbar/publish.tsx index a743b80580ce..baeed1756331 100644 --- a/apps/builder/app/builder/features/topbar/publish.tsx +++ b/apps/builder/app/builder/features/topbar/publish.tsx @@ -38,6 +38,7 @@ import { PopoverTitleActions, css, textVariants, + SmallIconButton, } from "@webstudio-is/design-system"; import { validateProjectDomain, type Project } from "@webstudio-is/project"; import { @@ -65,6 +66,9 @@ import { CopyIcon, GearIcon, UpgradeIcon, + DotIcon, + EllipsesIcon, + HelpIcon, } from "@webstudio-is/icons"; import { AddDomain } from "./add-domain"; import { humanizeString } from "~/shared/string-utils"; @@ -221,7 +225,10 @@ const ChangeProjectDomain = ({ const $usedProFeatures = computed( [$pages, $dataSources, $instances, $propsIndex], (pages, dataSources, instances, propsIndex) => { - const features = new Map(); + const features = new Map< + string, + undefined | { awareness?: Awareness; info?: string } + >(); if (pages === undefined) { return features; } @@ -231,33 +238,27 @@ const $usedProFeatures = computed( } // pages with dynamic paths for (const page of [pages.homePage, ...pages.pages]) { + const awareness = { + pageId: page.id, + instanceSelector: [page.rootInstanceId], + }; if (isPathnamePattern(page.path)) { - features.set("Dynamic path", { - pageId: page.id, - instanceSelector: [page.rootInstanceId], - }); + features.set("Dynamic path", { awareness }); } if (page.meta.status && page.meta.status !== `200`) { - features.set("Page status code", { - pageId: page.id, - instanceSelector: [page.rootInstanceId], - }); + features.set("Page status code", { awareness }); } if (page.meta.redirect && page.meta.redirect !== `""`) { - features.set("Redirect", { - pageId: page.id, - instanceSelector: [page.rootInstanceId], - }); + features.set("Redirect", { awareness }); } } // has resource variables for (const dataSource of dataSources.values()) { if (dataSource.type === "resource") { const instanceId = dataSource.scopeInstanceId ?? ""; - features.set( - "Resource variable", - findAwarenessByInstanceId(pages, instances, instanceId) - ); + features.set("Resource variable", { + awareness: findAwarenessByInstanceId(pages, instances, instanceId), + }); } } @@ -265,34 +266,31 @@ const $usedProFeatures = computed( for (const instance of instances.values()) { const [namespace] = parseComponentName(instance.component); if (namespace === "@webstudio-is/sdk-components-animation") { - features.set( - "Animation component", - findAwarenessByInstanceId(pages, instances, instance.id) - ); + features.set("Animation component", { + awareness: findAwarenessByInstanceId(pages, instances, instance.id), + }); } } - const badgeFeature = 'No "Built with Webstudio" badge'; + const badgeFeature = 'Remove "Built with Webstudio" badge'; // Badge should be rendered on free sites on every page. - features.set(badgeFeature, undefined); + features.set(badgeFeature, { + info: "Adding the badge to your homepage helps us offer a free version of the service. Please open the Components panel by clicking the “+” icon on the left, and add the “Built with Webstudio” component to your page. Feel free to adjust the badge’s styles to match your design.", + }); // We want to check the badge only on the home page const homePageInstanceIds = findTreeInstanceIds( instances, pages.homePage.rootInstanceId ); - // @todo add a check inside the slot that could be on the home page for (const instanceId of homePageInstanceIds) { const instance = instances.get(instanceId); - if (instance === undefined) { - continue; - } - // Built with Webstudio badge - if (instance.tag === "a") { + // Find a potential link that looks like a badge. + if (instance?.tag === "a") { const props = propsIndex.propsByInstanceId.get(instance.id); for (const prop of props ?? []) { if ( prop.name === "href" && - prop.value === "https://webstudio.is?via=badge" + prop.value === "https://webstudio.is/?via=badge" ) { features.delete(badgeFeature); } @@ -766,19 +764,26 @@ const Content = (props: { {Array.from(usedProFeatures).map( - ([message, awareness], index) => ( + ([message, { awareness, info } = {}], index) => (
  • - {awareness ? ( - - ) : ( - message - )} + + {awareness ? ( + + ) : ( + message + )} + {info && ( + + } /> + + )} +
  • ) )} diff --git a/packages/sdk/src/core-templates.tsx b/packages/sdk/src/core-templates.tsx index 60104a0644ef..4829dd15f938 100644 --- a/packages/sdk/src/core-templates.tsx +++ b/packages/sdk/src/core-templates.tsx @@ -364,7 +364,7 @@ const builtWithWebstudioMeta: TemplateMeta = { ws:tag="a" ws:label="Built with Webstudio" // If you change this, you need to also update this link in publish checks - href="https://webstudio.is?via=badge" + href="https://webstudio.is/?via=badge" target="_blank" ws:style={css` display: inline-flex; From e05f9ac9cf903d437ebe8891e7707deb0a154e2d Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sat, 7 Jun 2025 12:31:59 +0100 Subject: [PATCH 4/5] linter --- apps/builder/app/builder/features/topbar/publish.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/builder/app/builder/features/topbar/publish.tsx b/apps/builder/app/builder/features/topbar/publish.tsx index baeed1756331..e89d42457c36 100644 --- a/apps/builder/app/builder/features/topbar/publish.tsx +++ b/apps/builder/app/builder/features/topbar/publish.tsx @@ -66,8 +66,6 @@ import { CopyIcon, GearIcon, UpgradeIcon, - DotIcon, - EllipsesIcon, HelpIcon, } from "@webstudio-is/icons"; import { AddDomain } from "./add-domain"; From 754da0cf4e85d872123ffafb6b79f78e0469a730 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sat, 7 Jun 2025 19:10:37 +0100 Subject: [PATCH 5/5] wording --- apps/builder/app/builder/features/topbar/publish.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/builder/app/builder/features/topbar/publish.tsx b/apps/builder/app/builder/features/topbar/publish.tsx index e89d42457c36..5693bc64af70 100644 --- a/apps/builder/app/builder/features/topbar/publish.tsx +++ b/apps/builder/app/builder/features/topbar/publish.tsx @@ -270,7 +270,7 @@ const $usedProFeatures = computed( } } - const badgeFeature = 'Remove "Built with Webstudio" badge'; + const badgeFeature = 'No "Built with Webstudio" badge'; // Badge should be rendered on free sites on every page. features.set(badgeFeature, { info: "Adding the badge to your homepage helps us offer a free version of the service. Please open the Components panel by clicking the “+” icon on the left, and add the “Built with Webstudio” component to your page. Feel free to adjust the badge’s styles to match your design.",