diff --git a/src/components/DocumentationTopic/TopicLinkBlockIcon.vue b/src/components/DocumentationTopic/TopicLinkBlockIcon.vue index 5cfa7df53..8a4d00d3f 100644 --- a/src/components/DocumentationTopic/TopicLinkBlockIcon.vue +++ b/src/components/DocumentationTopic/TopicLinkBlockIcon.vue @@ -9,8 +9,12 @@ --> @@ -24,6 +28,7 @@ import TechnologyIcon from 'theme/components/Icons/TechnologyIcon.vue'; import TutorialIcon from 'theme/components/Icons/TutorialIcon.vue'; import SVGIcon from 'docc-render/components/SVGIcon.vue'; import { TopicRole } from 'docc-render/constants/roles'; +import OverridableAsset from 'docc-render/components/OverridableAsset.vue'; const TopicRoleIcons = { [TopicRole.article]: ArticleIcon, @@ -39,12 +44,16 @@ const TopicRoleIcons = { }; export default { - components: { SVGIcon }, + components: { OverridableAsset, SVGIcon }, props: { role: { type: String, required: true, }, + imageOverride: { + type: Object, + default: null, + }, }, computed: { @@ -84,4 +93,12 @@ export default { height: rem(17px); } } + +// Since we are unable to enforce the actual SVG color when it is embedded in +// an element, this workaround will force a gray color by applying a +// grayscale filter to ensure the color of the icon is consistent with the +// normal, builtin icons +.icon-override:deep(img) { + filter: grayscale(1); +} diff --git a/src/components/DocumentationTopic/TopicsLinkBlock.vue b/src/components/DocumentationTopic/TopicsLinkBlock.vue index f790a6e91..a3ef619fb 100644 --- a/src/components/DocumentationTopic/TopicsLinkBlock.vue +++ b/src/components/DocumentationTopic/TopicsLinkBlock.vue @@ -20,6 +20,7 @@ {{ topic.title }} diff --git a/tests/unit/components/DocumentationTopic/TopicLinkBlockIcon.spec.js b/tests/unit/components/DocumentationTopic/TopicLinkBlockIcon.spec.js index 1f0502651..e9265de7d 100644 --- a/tests/unit/components/DocumentationTopic/TopicLinkBlockIcon.spec.js +++ b/tests/unit/components/DocumentationTopic/TopicLinkBlockIcon.spec.js @@ -13,6 +13,7 @@ import { mount } from '@vue/test-utils'; import { TopicRole } from '@/constants/roles'; import ArticleIcon from '@/components/Icons/ArticleIcon.vue'; import TechnologyIcon from '@/components/Icons/TechnologyIcon.vue'; +import OverridableAsset from '@/components/OverridableAsset.vue'; const defaultProps = { role: TopicRole.article, @@ -32,9 +33,31 @@ describe('TopicLinkBlockIcon', () => { expect(wrapper.find('.topic-icon').is(ArticleIcon)).toBe(true); }); - it('renders nothing if no role', () => { + it('renders an override icon from an image override', () => { + const imageOverride = { + variants: [{ + url: '/foo/bar', + svgID: 'foo', + }], + }; const wrapper = createWrapper({ propsData: { + imageOverride, + }, + }); + const icon = wrapper.find('.topic-icon'); + expect(icon.classes('icon-override')).toBe(true); + expect(icon.is(ArticleIcon)).toBe(false); + expect(icon.is(OverridableAsset)).toBe(true); + expect(icon.props()).toMatchObject({ + imageOverride, + }); + }); + + it('renders nothing if no role or image override', () => { + const wrapper = createWrapper({ + propsData: { + imageOverride: null, role: TopicRole.devLink, // no icon for this }, }); diff --git a/tests/unit/components/DocumentationTopic/TopicsLinkBlock.spec.js b/tests/unit/components/DocumentationTopic/TopicsLinkBlock.spec.js index 02c38529d..db056b453 100644 --- a/tests/unit/components/DocumentationTopic/TopicsLinkBlock.spec.js +++ b/tests/unit/components/DocumentationTopic/TopicsLinkBlock.spec.js @@ -32,13 +32,22 @@ describe('TopicsLinkBlock', () => { /** @type {import('@vue/test-utils').Wrapper} */ let wrapper; + const iconOverride = { + type: 'icon', + identifier: 'icon-override', + }; + + const references = { + [iconOverride.identifier]: { foo: 'bar' }, + }; + const store = { reset: jest.fn(), setAPIChanges: jest.fn(), state: { onThisPageSections: [], apiChanges: null, - references: {}, + references, }, }; @@ -126,6 +135,18 @@ describe('TopicsLinkBlock', () => { expect(link.props('role')).toBe(propsData.topic.role); }); + it('renders a TopicLinkBlockIcon with an override', () => { + const icon = wrapper.find(TopicLinkBlockIcon); + expect(icon.props('imageOverride')).toBe(null); + wrapper.setProps({ + topic: { + ...propsData.topic, + images: [iconOverride, { type: 'card', identifier: 'foo' }], + }, + }); + expect(icon.props('imageOverride')).toBe(references[iconOverride.identifier]); + }); + it('renders a normal `WordBreak` for the link text', () => { const wordBreak = wrapper.find('.link').find(WordBreak); expect(wordBreak.exists()).toBe(true);