Skip to content

Commit 55fab14

Browse files
committed
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 9712b78 commit 55fab14

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 {
@@ -82,6 +83,10 @@ import { CopyToClipboard } from "~/builder/shared/copy-to-clipboard";
8283
import { $openProjectSettings } from "~/shared/nano-states/project-settings";
8384
import { RelativeTime } from "~/builder/shared/relative-time";
8485
import cmsUpgradeBanner from "../settings-panel/cms-upgrade-banner.svg?url";
86+
import { showAttribute } from "@webstudio-is/react-sdk";
87+
import { $styleObjectModel } from "../style-panel/shared/model";
88+
import { toValue, type CssProperty } from "@webstudio-is/css-engine";
89+
import { getComputedStyleDecl } from "~/shared/style-object-model";
8590

8691
type ChangeProjectDomainProps = {
8792
project: Project;
@@ -221,11 +226,11 @@ const ChangeProjectDomain = ({
221226
};
222227

223228
const $usedProFeatures = computed(
224-
[$pages, $dataSources, $instances, $propsIndex],
225-
(pages, dataSources, instances, propsIndex) => {
229+
[$pages, $dataSources, $instances, $propsIndex, $styleObjectModel],
230+
(pages, dataSources, instances, propsIndex, styleObjectModel) => {
226231
const features = new Map<
227232
string,
228-
undefined | { awareness?: Awareness; info?: string }
233+
undefined | { awareness?: Awareness; info?: ReactNode }
229234
>();
230235
if (pages === undefined) {
231236
return features;
@@ -273,7 +278,22 @@ const $usedProFeatures = computed(
273278
const badgeFeature = 'No "Built with Webstudio" badge';
274279
// Badge should be rendered on free sites on every page.
275280
features.set(badgeFeature, {
276-
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.",
281+
info: (
282+
<Text>
283+
Adding the badge to your "home" page helps us offer a free version of
284+
the service. Please open the Components panel by clicking the “+” icon
285+
on the left, and add the “Built with Webstudio” component to your
286+
page.
287+
<br />
288+
- Feel free to adjust the badge's style to match your design - after
289+
all, it's just a link, and you can place it wherever you like.
290+
<br />
291+
- Please don’t add that badge to every page, because search engines
292+
will view it negatively.
293+
<br />- Hiding the link in any way is considered a violation of the
294+
terms.
295+
</Text>
296+
),
277297
});
278298
// We want to check the badge only on the home page
279299
const homePageInstanceIds = findTreeInstanceIds(
@@ -285,15 +305,57 @@ const $usedProFeatures = computed(
285305
// Find a potential link that looks like a badge.
286306
if (instance?.tag === "a") {
287307
const props = propsIndex.propsByInstanceId.get(instance.id);
308+
let hasWsHref = false;
309+
let highTrust = true;
310+
let show = true;
311+
288312
for (const prop of props ?? []) {
289313
if (
290314
prop.name === "href" &&
291-
typeof prop.value === "string" &&
315+
prop.type === "string" &&
292316
prop.value.includes("https://webstudio.is")
293317
) {
294-
features.delete(badgeFeature);
318+
hasWsHref = true;
319+
}
320+
if (prop.name === "rel" && prop.type === "string") {
321+
if (
322+
prop.value.includes("nofollow") ||
323+
prop.value.includes("ugc") ||
324+
prop.value.includes("sponsored")
325+
) {
326+
highTrust = false;
327+
}
328+
}
329+
if (prop.name === showAttribute) {
330+
show = prop.type === "boolean" && prop.value;
295331
}
296332
}
333+
334+
const getValue = (property: CssProperty) => {
335+
return toValue(
336+
getComputedStyleDecl({
337+
model: styleObjectModel,
338+
instanceSelector: [instance.id],
339+
property,
340+
}).usedValue
341+
);
342+
};
343+
344+
// Check styles.
345+
if (
346+
getValue("display") === "none" ||
347+
getValue("visibility") === "hidden" ||
348+
getValue("opacity") === "0" ||
349+
getValue("opacity") === "0%"
350+
) {
351+
show = false;
352+
}
353+
354+
// @todo check all parents
355+
if (hasWsHref && highTrust && show) {
356+
features.delete(badgeFeature);
357+
break;
358+
}
297359
}
298360
}
299361
return features;

0 commit comments

Comments
 (0)