Skip to content

Commit 07c2710

Browse files
authored
feat: Improve badge checks (#5278)
## Description Checks: - show - display - visibility - opacity - rel attribute ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file
1 parent 959fd11 commit 07c2710

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

apps/builder/app/builder/features/style-panel/shared/model.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ const getDefinedStyles = ({
208208
];
209209
};
210210

211-
const $model = computed(
211+
export const $styleObjectModel = computed(
212212
[
213213
$styles,
214214
$styleSourceSelections,
@@ -241,7 +241,7 @@ const $model = computed(
241241

242242
export const $computedStyleDeclarations = computed(
243243
[
244-
$model,
244+
$styleObjectModel,
245245
$selectedInstancePathWithRoot,
246246
$selectedOrLastStyleSourceSelector,
247247
$registeredComponentMetas,
@@ -331,7 +331,11 @@ export const $availableColorVariables = computed(
331331

332332
export const createComputedStyleDeclStore = (property: CssProperty) => {
333333
return computed(
334-
[$model, $selectedInstancePathWithRoot, $selectedOrLastStyleSourceSelector],
334+
[
335+
$styleObjectModel,
336+
$selectedInstancePathWithRoot,
337+
$selectedOrLastStyleSourceSelector,
338+
],
335339
(model, instancePath, styleSourceSelector) => {
336340
return getComputedStyleDecl({
337341
model,
@@ -345,7 +349,7 @@ export const createComputedStyleDeclStore = (property: CssProperty) => {
345349
};
346350

347351
export const useStyleObjectModel = () => {
348-
return useStore($model);
352+
return useStore($styleObjectModel);
349353
};
350354

351355
export const useComputedStyleDecl = (property: CssProperty) => {
@@ -378,7 +382,7 @@ export const useParentComputedStyleDecl = (property: CssProperty) => {
378382
const $store = useMemo(
379383
() =>
380384
computed(
381-
[$model, $closestStylableInstanceSelector],
385+
[$styleObjectModel, $closestStylableInstanceSelector],
382386
(model, instanceSelector) => {
383387
return getComputedStyleDecl({
384388
model,
@@ -397,7 +401,7 @@ export const getInstanceStyleDecl = (
397401
instanceSelector: InstanceSelector
398402
) => {
399403
return getComputedStyleDecl({
400-
model: $model.get(),
404+
model: $styleObjectModel.get(),
401405
instanceSelector,
402406
property,
403407
});

apps/builder/app/builder/features/topbar/publish.tsx

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
startTransition,
99
useRef,
1010
useId,
11+
type ReactNode,
1112
} from "react";
1213
import { useStore } from "@nanostores/react";
1314
import {
@@ -83,6 +84,10 @@ import { CopyToClipboard } from "~/builder/shared/copy-to-clipboard";
8384
import { $openProjectSettings } from "~/shared/nano-states/project-settings";
8485
import { RelativeTime } from "~/builder/shared/relative-time";
8586
import cmsUpgradeBanner from "../settings-panel/cms-upgrade-banner.svg?url";
87+
import { showAttribute } from "@webstudio-is/react-sdk";
88+
import { $styleObjectModel } from "../style-panel/shared/model";
89+
import { toValue, type CssProperty } from "@webstudio-is/css-engine";
90+
import { getComputedStyleDecl } from "~/shared/style-object-model";
8691

8792
type ChangeProjectDomainProps = {
8893
project: Project;
@@ -233,11 +238,11 @@ const ChangeProjectDomain = ({
233238
};
234239

235240
const $usedProFeatures = computed(
236-
[$pages, $dataSources, $instances, $propsIndex],
237-
(pages, dataSources, instances, propsIndex) => {
241+
[$pages, $dataSources, $instances, $propsIndex, $styleObjectModel],
242+
(pages, dataSources, instances, propsIndex, styleObjectModel) => {
238243
const features = new Map<
239244
string,
240-
undefined | { awareness?: Awareness; info?: string }
245+
undefined | { awareness?: Awareness; info?: ReactNode }
241246
>();
242247
if (pages === undefined) {
243248
return features;
@@ -285,7 +290,22 @@ const $usedProFeatures = computed(
285290
const badgeFeature = 'No "Built with Webstudio" badge';
286291
// Badge should be rendered on free sites on every page.
287292
features.set(badgeFeature, {
288-
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 style to match your design - after all, it's just a link, and you can place it wherever you like.",
293+
info: (
294+
<Text>
295+
Adding the badge to your "home" page helps us offer a free version of
296+
the service. Please open the Components panel by clicking the “+” icon
297+
on the left, and add the “Built with Webstudio” component to your
298+
page.
299+
<br />
300+
- Feel free to adjust the badge's style to match your design - after
301+
all, it's just a link, and you can place it wherever you like.
302+
<br />
303+
- Please don’t add that badge to every page, because search engines
304+
will view it negatively.
305+
<br />- Hiding the link in any way is considered a violation of the
306+
terms.
307+
</Text>
308+
),
289309
});
290310
// We want to check the badge only on the home page
291311
const homePageInstanceIds = findTreeInstanceIds(
@@ -297,14 +317,56 @@ const $usedProFeatures = computed(
297317
// Find a potential link that looks like a badge.
298318
if (instance?.tag === "a") {
299319
const props = propsIndex.propsByInstanceId.get(instance.id);
320+
let hasWsHref = false;
321+
let highTrust = true;
322+
let show = true;
323+
300324
for (const prop of props ?? []) {
301325
if (
302326
prop.name === "href" &&
303-
typeof prop.value === "string" &&
327+
prop.type === "string" &&
304328
prop.value.includes("https://webstudio.is")
305329
) {
306-
features.delete(badgeFeature);
330+
hasWsHref = true;
331+
}
332+
if (prop.name === "rel" && prop.type === "string") {
333+
if (
334+
prop.value.includes("nofollow") ||
335+
prop.value.includes("ugc") ||
336+
prop.value.includes("sponsored")
337+
) {
338+
highTrust = false;
339+
}
307340
}
341+
if (prop.name === showAttribute) {
342+
show = prop.type === "boolean" && prop.value;
343+
}
344+
}
345+
346+
const getValue = (property: CssProperty) => {
347+
return toValue(
348+
getComputedStyleDecl({
349+
model: styleObjectModel,
350+
instanceSelector: [instance.id],
351+
property,
352+
}).usedValue
353+
);
354+
};
355+
356+
// Check styles.
357+
if (
358+
getValue("display") === "none" ||
359+
getValue("visibility") === "hidden" ||
360+
getValue("opacity") === "0" ||
361+
getValue("opacity") === "0%"
362+
) {
363+
show = false;
364+
}
365+
366+
// @todo check all parents
367+
if (hasWsHref && highTrust && show) {
368+
features.delete(badgeFeature);
369+
break;
308370
}
309371
}
310372
}

0 commit comments

Comments
 (0)