add "Add age-restricted instance display logic to Location component" (#1629)

This commit is contained in:
pa
2026-03-18 21:20:19 +09:00
parent 647a902e9f
commit 3fbcf5b6ef
3 changed files with 73 additions and 24 deletions
+15 -1
View File
@@ -2,6 +2,15 @@
<div class="cursor-pointer"> <div class="cursor-pointer">
<div v-if="!text" class="text-transparent">-</div> <div v-if="!text" class="text-transparent">-</div>
<div v-show="text" class="flex items-center"> <div v-show="text" class="flex items-center">
<template v-if="isAgeRestricted">
<TooltipWrapper :content="t('dialog.user.info.instance_age_restricted_tooltip')" :delay-duration="300" side="top">
<div class="inline-flex items-center gap-1 text-muted-foreground">
<Lock class="size-3.5 shrink-0" />
<span>{{ t('dialog.user.info.instance_age_restricted') }}</span>
</div>
</TooltipWrapper>
</template>
<template v-else>
<div v-if="region" :class="['flags', 'mr-1.5', 'shrink-0', region]"></div> <div v-if="region" :class="['flags', 'mr-1.5', 'shrink-0', region]"></div>
<TooltipWrapper :content="tooltipContent" :disabled="tooltipDisabled" :delay-duration="300" side="top"> <TooltipWrapper :content="tooltipContent" :disabled="tooltipDisabled" :delay-duration="300" side="top">
<div <div
@@ -25,6 +34,7 @@
<AlertTriangle class="inline-block ml-2 text-muted-foreground shrink-0" /> <AlertTriangle class="inline-block ml-2 text-muted-foreground shrink-0" />
</TooltipWrapper> </TooltipWrapper>
<Lock v-if="strict" class="inline-block ml-2 text-muted-foreground shrink-0" /> <Lock v-if="strict" class="inline-block ml-2 text-muted-foreground shrink-0" />
</template>
</div> </div>
</div> </div>
</template> </template>
@@ -56,7 +66,7 @@
const { verifyShortName } = useSearchStore(); const { verifyShortName } = useSearchStore();
const { cachedInstances } = useInstanceStore(); const { cachedInstances } = useInstanceStore();
const { lastInstanceApplied } = storeToRefs(useInstanceStore()); const { lastInstanceApplied } = storeToRefs(useInstanceStore());
const { showInstanceIdInLocation } = storeToRefs(useAppearanceSettingsStore()); const { showInstanceIdInLocation, isAgeGatedInstancesVisible } = storeToRefs(useAppearanceSettingsStore());
const props = defineProps({ const props = defineProps({
location: String, location: String,
@@ -86,11 +96,13 @@
const text = ref(''); const text = ref('');
const region = ref(''); const region = ref('');
const strict = ref(false); const strict = ref(false);
const ageGate = ref(false);
const isTraveling = ref(false); const isTraveling = ref(false);
const groupName = ref(''); const groupName = ref('');
const isClosed = ref(false); const isClosed = ref(false);
const instanceName = ref(''); const instanceName = ref('');
const isAgeRestricted = computed(() => !isAgeGatedInstancesVisible.value && ageGate.value);
const isLocationLink = computed(() => props.link && props.location !== 'private' && props.location !== 'offline'); const isLocationLink = computed(() => props.link && props.location !== 'private' && props.location !== 'offline');
const locationClasses = computed(() => [ const locationClasses = computed(() => [
'x-location', 'x-location',
@@ -135,6 +147,7 @@
text.value = ''; text.value = '';
region.value = ''; region.value = '';
strict.value = false; strict.value = false;
ageGate.value = false;
isTraveling.value = false; isTraveling.value = false;
groupName.value = ''; groupName.value = '';
isClosed.value = false; isClosed.value = false;
@@ -166,6 +179,7 @@
updateGroupName(L, instanceId); updateGroupName(L, instanceId);
updateRegion(L); updateRegion(L);
strict.value = L.strict; strict.value = L.strict;
ageGate.value = L.ageGate;
} }
/** /**
+35 -2
View File
@@ -126,7 +126,7 @@ const stubs = {
AlertTriangle: { template: '<span class="alert-triangle" />' } AlertTriangle: { template: '<span class="alert-triangle" />' }
}; };
function mountLocation(props = {}) { function mountLocation(props = {}, appearanceOverrides = {}) {
return mount(Location, { return mount(Location, {
props, props,
global: { global: {
@@ -139,7 +139,9 @@ function mountLocation(props = {}) {
World: {}, World: {},
Search: {}, Search: {},
AppearanceSettings: { AppearanceSettings: {
showInstanceIdInLocation: false showInstanceIdInLocation: false,
isAgeGatedInstancesVisible: false,
...appearanceOverrides
}, },
Group: {} Group: {}
} }
@@ -150,6 +152,7 @@ function mountLocation(props = {}) {
}); });
} }
describe('Location.vue', () => { describe('Location.vue', () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
@@ -342,4 +345,34 @@ describe('Location.vue', () => {
expect(wrapper.text()).toContain('Second Name'); expect(wrapper.text()).toContain('Second Name');
}); });
}); });
describe('age-restricted display', () => {
test('shows Restricted with lock when ageGate instance and setting is hidden', () => {
const wrapper = mountLocation(
{ location: 'wrld_12345:67890~ageGate', hint: 'Test World' },
{ isAgeGatedInstancesVisible: false }
);
expect(wrapper.text()).toContain('Restricted');
expect(wrapper.find('.lucide-lock').exists()).toBe(true);
expect(wrapper.text()).not.toContain('Test World');
});
test('shows normal location when ageGate instance and setting is visible', () => {
const wrapper = mountLocation(
{ location: 'wrld_12345:67890~ageGate', hint: 'Test World' },
{ isAgeGatedInstancesVisible: true }
);
expect(wrapper.text()).toContain('Test World');
expect(wrapper.text()).not.toContain('Restricted');
});
test('shows normal location for non-ageGate instance even when setting is hidden', () => {
const wrapper = mountLocation(
{ location: 'wrld_12345:67890', hint: 'Normal World' },
{ isAgeGatedInstancesVisible: false }
);
expect(wrapper.text()).toContain('Normal World');
expect(wrapper.text()).not.toContain('Restricted');
});
});
}); });
+2
View File
@@ -1342,6 +1342,8 @@
"vrcplus_hides_avatar": "When a VRC+ profile photo is set, avatar info is hidden. This also hides avatar changes in the feed", "vrcplus_hides_avatar": "When a VRC+ profile photo is set, avatar info is hidden. This also hides avatar changes in the feed",
"instance_full": "full", "instance_full": "full",
"instance_closed": "Instance closed", "instance_closed": "Instance closed",
"instance_age_restricted": "Restricted",
"instance_age_restricted_tooltip": "In an age-restricted instance",
"close_instance": "Close Instance", "close_instance": "Close Instance",
"instance_age_gated": "Age Gated", "instance_age_gated": "Age Gated",
"open_previous_instance": "Open Previous Instances", "open_previous_instance": "Open Previous Instances",