diff --git a/workspaces/components/src/devto/README.md b/workspaces/components/src/devto/README.md deleted file mode 100644 index 483741f..0000000 --- a/workspaces/components/src/devto/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Dev.to profile card widget - -WIP for use on scottnath.com only - -## @todo - -- [ ] Fetch non-key data from api -- [ ] container queries and nested CSS -- [ ] move to separate repo - - [ ] profile-cards -- [ ] i18 || configure titles -- [ ] use `data-thing` for attributes? -- [ ] re-do `parts`, removing parts that are just for style-sharing -- [ ] interaction tests -- [ ] a11y testing -- [ ] create custom element manifest - - [ ] need [plugins](https://custom-elements-manifest.open-wc.org/blog/intro/#plugins) to do JSDoc correctly -- [x] separate out fetch and data handling from component -- [ ] alt-option that allows use of api-key -- [ ] test in plain HTML page -- [ ] test in Qwik -- [ ] test in Next.js - -## Inspriation - -- https://dev.to/asheeshh/devembed-embed-your-devto-profile-anywhere-using-widgets-linode-hacakathon-4659 -- https://dev.to/saurabhdaware/i-made-dev-to-widget-for-websites-blogs-40p2 \ No newline at end of file diff --git a/workspaces/components/src/devto/devto.shared-spec.js b/workspaces/components/src/devto/devto.shared-spec.js deleted file mode 100644 index a1e9506..0000000 --- a/workspaces/components/src/devto/devto.shared-spec.js +++ /dev/null @@ -1,30 +0,0 @@ - -export const smileySvg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAJUlEQVR42u3NQQEAAAQEsJNcdFLw2gqsMukcK4lEIpFIJBLJS7KG6yVo40DbTgAAAABJRU5ErkJggg==' - -export const snUserFixture = { - id: 1055555, - username: 'scottnath', - name: 'Scott Nath', - summary: "Front-end Architect", - joined_at: 'Mar 30, 2023', - // profile_image: 'https://res.cloudinary.com/practicaldev/image/fetch/s--8gi1l6OI--/c_fill,f_auto,fl_progressive,h_320,q_auto,w_320/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/1055555/8146c5bb-31d3-4023-a216-5cb5c00ecb3b.jpg', - profile_image: './multi-face-image.jpeg', - joined: '2023-03-30', - post_count: 8 -} - -export const snPostFixture = { - title: 'Sharing UI Tests Between Javascript Frameworks', - description: 'How to share testing-library UI tests between Javascript frameworks with the same or similar components and use them in Storybook and unit testing.', - url: 'https://dev.to/scottnath/sharing-ui-tests-between-javascript-frameworks-2l6n', - cover_image: 'https://res.cloudinary.com/practicaldev/image/fetch/s--NqWkGO2---/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z5070dozgnb32uwtm5dm.png', -} - -export const meowUserFixture = { - id: 1055555, - username: 'meowmeow', - name: 'Meow Meow', - summary: "Just a meow, with a meow's worries. Nothin but a meow.", - joined_at: 'Feb 29, 2020', - profile_image: smileySvg, -} diff --git a/workspaces/components/src/devto/devto.stories.js b/workspaces/components/src/devto/devto.stories.js deleted file mode 100644 index 0ecf3fa..0000000 --- a/workspaces/components/src/devto/devto.stories.js +++ /dev/null @@ -1,61 +0,0 @@ - -import './'; -import { snUserFixture, meowUserFixture } from './devto.shared-spec'; - -export default { - title: 'DevTo', - component: 'dev-user', - tags: ['autodocs'], -}; - -export const Username = { - args: { - username: 'scottnath', - }, -}; - -export const NewUser = { - args: { - username: 'soyecoder', - }, -} - -export const AltUserData = { - args: { - user: { - ...snUserFixture, - name: 'Someother Name', - summary: 'Different summary content than what is from the dev.to api', - joined_at: 'Jan 1, 1979', - post_count: 1, - }, - }, -} - -export const SkipFetch = { - args: { - user: meowUserFixture, - skipFetch: true, - }, -} - -export const SkipFetchJustUsername = { - args: { - user: { - username: 'scottnath' - }, - skipFetch: true, - }, -} - -export const SkipFetchFail = { - args: { - skipFetch: true, - }, -} - -export const UnknownUsername = { - args: { - username: 'NotAUserMeow', - }, -} diff --git a/workspaces/components/src/devto/get-devto-user.js b/workspaces/components/src/devto/get-devto-user.js deleted file mode 100644 index 1cd935c..0000000 --- a/workspaces/components/src/devto/get-devto-user.js +++ /dev/null @@ -1,76 +0,0 @@ - -/** - * Content about one post by dev.to (or Forem) user, sourced from the Forem API. - * @see https://developers.forem.com/api/v1#tag/articles/operation/getLatestArticles - * @typedef {Object} ForemPost - * @property {string} title - The title of the post - * @property {string} url - The URL of the post - * @property {string} cover_image - The URL of the post's full-size cover image - */ - -/** - * Content about a dev.to (or Forem) user, sourced from the Forem API and combined with post data. - * Only required properties from the api are defined. - * @see https://developers.forem.com/api/v0#tag/users/operation/getUser - * @typedef {Object} ForemUser - * - * @property {string} username - The username of the user - * @property {string} name - The name of the user - * @property {string} summary - The user's bio - * @property {string} joined_at - The date the user joined - * @property {string} profile_image - The URL of the user's profile image - * @property {number} post_count - The number of posts the user has published - */ - -/** - * @function Fetch a user's posts from the Forem API - * @param {string} username - * @returns {ForemPost[]} - An array of posts - */ -export const fetchUserPosts = async (username) => { - const articles = await fetch(`https://dev.to/api/articles/latest?per_page=1000&username=${username?.toLowerCase()}`); - const articlesJson = await articles.json(); - return articlesJson; -} - -/** - * @function Fetch a user's data from the Forem API - * @property {string} username - The username of the user - * @property {string} id - the id of the user - */ -export const fetchUser = async (username, id) => { - let response; - if (!username && id) { - response = await fetch(`https://dev.to/api/users/${id}`); - } else { - response = await fetch(`https://dev.to/api/users/by_username?url=${username?.toLowerCase()}`); - } - const userJson = await response.json(); - return userJson; -} - -/** - * Get a user's profile and posts - * @param {string} username - * @param {string} id - * @returns {Promise<{user: ForemUser, posts: ForemPost[]}>} - */ -export const getUserContent = async (username, id) => { - const user = await fetchUser(username, id); - if (user.error) { - return { - error: user.error, - } - } - if (!user.username) { - return { - error: 'no username found', - } - } - const posts = await fetchUserPosts(user.username); - user.post_count = posts.length; - return { - user, - posts, - } -} diff --git a/workspaces/components/src/devto/index.js b/workspaces/components/src/devto/index.js deleted file mode 100644 index 6bddd6b..0000000 --- a/workspaces/components/src/devto/index.js +++ /dev/null @@ -1,270 +0,0 @@ -import { LitElement, html, css, unsafeCSS } from 'lit'; -import {when} from 'lit/directives/when.js'; - -// import stylesDep from './style.css' -import styles from './styles.css?inline' - -/** - * Blank base64-encoded png - * @see https://png-pixel.com/ - */ -const blankPng = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8/x8AAuMB8DtXNJsAAAAASUVORK5CYII='; - -/** - * dev.to logo - * @see https://dev.to/brand - */ -const devLogoSvg = html` - - -`; - -/** - * Forem icon for a cake (used with "Joined" date) - * @see https://github.com/forem/forem/blob/main/app/assets/images/cake.svg?short_path=e3c7d41 - */ -const joinedSvg = html` - -`; - -/** - * Forem icon for a post - * @see https://github.com/forem/forem/blob/main/app/assets/images/post.svg?short_path=b79fa43 - */ -const postSvg = html` - -`; - -/** - * Content about one post by dev.to (or Forem) user, sourced from the Forem API. - * @see https://developers.forem.com/api/v1#tag/articles/operation/getLatestArticles - * @typedef {Object} ForemPost - * @property {string} title - The title of the post - * @property {string} url - The URL of the post - * @property {string} cover_image - The URL of the post's full-size cover image - */ - -/** - * Render a link to a post - * @param {ForemPost} post - Content about a post - */ -const postLink = (post) => html` -Cover image for post ${post.title} -${post.title}`; - -/** - * Content about a dev.to (or Forem) user, sourced from the Forem API and combined with post data. - * Only the properties used in this component are defined. - * @see https://developers.forem.com/api/v0#tag/users/operation/getUser - * @typedef {Object} ForemUser - * - * @property {string} username - The username of the user - * @property {string} name - The name of the user - * @property {string} summary - The user's bio - * @property {string} joined_at - The date the user joined - * @property {string} profile_image - The URL of the user's profile image - * @property {number} post_count - The number of posts the user has published - */ - - -/** - * Render a link to a user's profile - * @param {ForemUser} user - Content about a user - */ -const profileLink = (user) => html` -
- View Profile on dev.to -
-`; - -/** - * Render a user's avatar - * @param {ForemUser} user - Content about a user - */ -const userAvatar = (user) => html`Avatar for ${user?.name}`; - -/** - * Render a user's joined date - * @param {ForemUser} user - Content about a user - */ -const userJoined = (user) => this.user?.joined_at ? html`

-${joinedSvg} -Joined on - - -

-` : ''; - -/** - * dev.to profile component - * @element dev-user - * @cssprop --devto-color - * @prop {string} username - The username of the user - * @prop {ForemUser} user - Content about a user - * @prop {ForemPost} latest_post - Content about a post - */ -export class DevToProfile extends LitElement { - static properties = { - user: { type: Object }, - username: { type: String }, - latest_post: { type: Object }, - skipFetch: { type: Boolean }, - }; - static styles = css` - ${unsafeCSS(styles)} - `; - - async firstUpdated() { - if (!this.username && this.user?.username) { - this.username = this.user.username; - } - if (this.skipFetch) { - if (!this.username) { - this._generateError( - 'A username is required to skip fetching data', - 'UI requires a name and username at minimum', - ) - return; - } - } else { - if (this.username) { - await this._generateUser(this.username); - } else { - await this._generateUser(null, this.user?.id); - } - } - await this._cleanUserData(); - } - - /** - * Format a date for machine-readability - * @param {string} dt - * @returns {string} - the machine-readable value of the date - */ - _formatDate(dt) { - const x = new Date(dt); - const year = x.getFullYear() - const month = String(x.getMonth() + 1).padStart(2, '0') - const day = String(x.getDate()).padStart(2, '0') - - return `${year}-${month}-${day}` - } - - async _fetchPosts(username) { - const articles = await fetch(`https://dev.to/api/articles/latest?per_page=1000&username=${username?.toLowerCase()}`); - const articlesJson = await articles.json(); - this.user.post_count = this.user.post_count || articlesJson.length; - if (articlesJson.length && !this.latest_post) { - this.latest_post = articlesJson[0]; - } - } - - async _fetchUserResponse(username, id) { - if (!username && id) { - return await fetch(`https://dev.to/api/users/${id}`); - } - return await fetch(`https://dev.to/api/users/by_username?url=${username?.toLowerCase()}`); - } - - async _generateError(msg, status) { - this.user = { - name: msg, - status, - } - } - - async _generateUser(username, id) { - const response = await this._fetchUserResponse(username, id); - const jsonResponse = await response.json(); - if (jsonResponse.error) { - this._generateError( - `User ${username || id} ${jsonResponse.error}`, - jsonResponse.error, - ) - return; - } - this.user = { - ...jsonResponse, - ...this.user, - } - if (typeof this.user.post_count !== 'number' || (this.user.post_count > 0 && !this.latest_post)) { - await this._fetchPosts(this.user.username); - } - } - - /** - * Clean up data to conform to the HTML-expected content model - */ - async _cleanUserData() { - this.user.profile_image = this.user.profile_image || blankPng; - this.user.name = this.user.name || `@${this.user.username}`; - if (this.user.joined_at) { - this.user.joined = this.user.joined || this._formatDate(this.user.joined_at); - } - if (this.user.post_count && Number(this.user.post_count) !== NaN) { - this.user.post_count = Number(this.user.post_count); - } else { - delete this.user?.post_count; - } - this.latest_post.cover_image = this.latest_post.cover_image || blankPng; - } - - render() { - if (this.user?.status) { - return html` -
-
-
${devLogoSvg}
- -

- ${this.user?.name} -

-
-
- `; - } - - return when(this.user?.username, () => html` -
-
-
${devLogoSvg}
- -

- - - ${userAvatar(this.user)} - - ${this.user?.name} - -

-
-
- ${when(this.user?.summary, () => html`

${this.user?.summary}

`)} - ${when(this.user?.joined_at, () => html`

- ${joinedSvg} - Joined on - - -

`)} - ${when(this.user?.post_count > 0, () => html` -

- ${postSvg} - ${this.user?.post_count} posts published -

- `)} - ${when(this.latest_post, () => html` -
-
Latest post
-
${postLink(this.latest_post)}
-
- `)} -
- -
- `); - } -} - -customElements.define('dev-user', DevToProfile); \ No newline at end of file diff --git a/workspaces/components/src/devto/profile-card.js b/workspaces/components/src/devto/profile-card.js deleted file mode 100644 index 243f977..0000000 --- a/workspaces/components/src/devto/profile-card.js +++ /dev/null @@ -1,238 +0,0 @@ -import { LitElement, html, css, unsafeCSS } from 'lit'; -import {when} from 'lit/directives/when.js'; - -import styles from './styles.css?inline' - -/** - * Blank base64-encoded png - * @see https://png-pixel.com/ - */ -const blankPng = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mN8/x8AAuMB8DtXNJsAAAAASUVORK5CYII='; - -/** - * dev.to logo - * @see https://dev.to/brand - */ -const devLogoSvg = html` - - -`; - -/** - * Forem icon for a cake (used with "Joined" date) - * @see https://github.com/forem/forem/blob/main/app/assets/images/cake.svg?short_path=e3c7d41 - */ -const joinedSvg = html` - -`; - -/** - * Forem icon for a post - * @see https://github.com/forem/forem/blob/main/app/assets/images/post.svg?short_path=b79fa43 - */ -const postSvg = html` - -`; - -/** - * Format a date for machine-readability - * @param {string} dt - * @returns {string} - the machine-readable value of the date - */ -export const formatDate = (dt) => { - const x = new Date(dt); - const year = x.getFullYear() - const month = String(x.getMonth() + 1).padStart(2, '0') - const day = String(x.getDate()).padStart(2, '0') - - return `${year}-${month}-${day}` -} - -/** - * Container for the dev.to logo - */ -export const logoContainer = html`
${devLogoSvg}
`; - -/** - * Content about one post by dev.to (or Forem) user, sourced from the Forem API. - * @see https://developers.forem.com/api/v1#tag/articles/operation/getLatestArticles - * @typedef {Object} ForemPost - * @property {string} title - The title of the post - * @property {string} url - The URL of the post - * @property {string} cover_image - The URL of the post's full-size cover image - */ - -/** - * Render a link to a post - * @param {ForemPost} post - Content about a post - */ -const postLink = (post) => html` -Cover image for post ${post.title} -${post.title}`; - -/** - * @function Render a post description term group - * @param {string} term - the term to describe - * @param {ForemPost} post - Content about a post - */ -const postDescription = (term, post) => post ? html` -
${term}
-
${postLink(post)}
-` : ''; - -/** - * Content about a dev.to (or Forem) user, sourced from the Forem API and combined with post data. - * Only the properties used in this component are defined. - * @see https://developers.forem.com/api/v0#tag/users/operation/getUser - * @typedef {Object} ForemUser - * - * @property {string} username - The username of the user - * @property {string} name - The name of the user - * @property {string} summary - The user's bio - * @property {string} joined_at - The date the user joined - * @property {string} profile_image - The URL of the user's profile image - * @property {number} post_count - The number of posts the user has published - */ - - -/** - * Render a link to a user's profile - * @param {ForemUser} user - Content about a user - */ -const profileLink = (user) => html` -
- View Profile on dev.to -
-`; - -/** - * Render a user's avatar - * @param {ForemUser} user - Content about a user - */ -const avatarImg = (user) => html`Avatar for ${user?.name}`; - -/** - * @function Render a user's summary content - * @param {string} summary - the user's bio - */ -export const userSummary = (summary) => summary ? html`

${summary}

` : ''; - -/** - * @function Render a user's joined date - * @param {string} joined_at - date the user joined - */ -export const userJoined = (joined_at) => joined_at ? html`

-${joinedSvg} -Joined on - - -

-` : ''; - -/** - * @function Render a user's post count - * @param {number} post_count - number of posts the user has published - */ -export const userPostCount = (post_count) => post_count !== undefined ? html`

- ${postSvg} - ${post_count} posts published -

-` : ''; - -/** - * dev.to profile card component - * @element devto-profile-card - * @prop {ForemUser} user - Content about a user - * @prop {ForemPost} [latest_post] - Content about a post - */ -export class DevToProfileCard extends LitElement { - static properties = { - user: { type: Object }, - latest_post: { type: Object }, - }; - static styles = css` - ${unsafeCSS(styles)} - `; - - constructor() { - super(); - this.error = null; - } - - connectedCallback() { - super.connectedCallback(); - this._cleanUserData(); - } - - /** - * Clean up data to conform to the HTML-expected content model - */ - _cleanUserData() { - if (!this.user) { - this.error = 'No user data provided'; - return; - } - if (!this.user?.username) { - this.error = 'Username (user.username) is required'; - return; - } - this.user.profile_image = this.user.profile_image || blankPng; - this.user.name = this.user.name || `@${this.user.username}`; - if (this.user.post_count && Number(this.user.post_count) !== NaN) { - this.user.post_count = Number(this.user.post_count); - } else { - delete this.user?.post_count; - } - if (this.latest_post) { - this.latest_post.cover_image = this.latest_post.cover_image || blankPng; - } - } - - render() { - if (this.error) { - return html` -
-
- ${logoContainer} - -

- ${this.error} -

-
-
- `; - } - - return html` -
-
- ${logoContainer} - -
- - - ${avatarImg(this.user)} - - ${this.user?.name} - -
-
-
- ${userSummary(this.user?.summary)} - ${userJoined(this.user?.joined_at)} - ${userPostCount(this.user?.post_count)} - ${when(this.latest_post, () => html` -
- ${postDescription('Latest post', this.latest_post)} -
- `)} -
- -
- `; - } -} - -customElements.define('devto-profile-card', DevToProfileCard); \ No newline at end of file diff --git a/workspaces/components/src/devto/profile-card.stories.js b/workspaces/components/src/devto/profile-card.stories.js deleted file mode 100644 index 279ba8b..0000000 --- a/workspaces/components/src/devto/profile-card.stories.js +++ /dev/null @@ -1,32 +0,0 @@ - -import './profile-card'; -import { snUserFixture, snPostFixture } from './devto.shared-spec'; - -export default { - title: 'Profile Card', - component: 'devto-profile-card', - tags: ['autodocs'], -}; - -export const User = { - args: { - user: snUserFixture, - }, -} - -export const UserWithLatestPost = { - args: { - user: snUserFixture, - latest_post: snPostFixture, - }, -} - -export const NoUser = {}; -export const NoUsername = { - args: { - user: { - ...snUserFixture, - username: undefined, - }, - }, -}; diff --git a/workspaces/components/src/devto/styles.css b/workspaces/components/src/devto/styles.css deleted file mode 100644 index beb9fae..0000000 --- a/workspaces/components/src/devto/styles.css +++ /dev/null @@ -1,215 +0,0 @@ -:host { - /** styles from forem/forem */ - --ff-sans-serif: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol'; - --white: 255, 255, 255; - --black: 0, 0, 0; - --grey-100: 245, 245, 245; - --grey-900: 23, 23, 23; - --indigo-600: 79, 70, 229; - --indigo-700: 67, 56, 202; - --base-60: #717171; - --base-70: #575757; - --base-90: #242424; - --radius: 0.375rem; - - --body-bg: rgb(var(--grey-100)); - --card-bg: rgb(var(--white)); - --card-color: var(--base-70); - --card-color-bold: var(--base-90); - --card-shadow-color: rgba(var(--grey-900), 0.05); - - --color-base: var(--base-70); - --color-mild: var(--base-70); - --color-bold: var(--base-90); - - --divider: 1px solid var(--body-bg); - - --ff-base: var(--ff-sans-serif); - - --fs-base: 16px; - --fs-mild: 0.875em; - --fs-bold: 1.25em; - - --fw-base: 500; - --fw-bold: 700; - - --accent-brand: rgb(var(--indigo-600)); - --accent-brand-darker: rgb(var(--indigo-700)); - --profile-brand-color: rgb(var(--black)); - - --cta-bg: transparent; - --cta-bg-hover: rgba(var(--indigo-600), 0.1); - --cta-color: rgb(var(--grey-800)); - --cta-color-hover: var(--accent-brand-darker); - --cta-border: rgb(var(--grey-600)); - --cta-border-hover: var(--accent-brand-darker); - - --cta-branded-bg: transparent; - --cta-branded-bg-hover: var(--accent-brand); - --cta-branded-color: var(--accent-brand); - --cta-branded-color-hover: rgb(var(--white)); - --cta-branded-border: var(--accent-brand); - --cta-branded-border-hover: var(--accent-brand-darker); - - - -} -:host { - line-height: 1.5; - - color: var(--color-base); - font-family: var(--ff-base); - font-size: var(--fs-base); - font-weight: var(--fw-base); -} -/** root elements cleanup */ -* { - padding: 0; - margin: 0; - margin-inline: 0; -} -a { - text-decoration: none; -} -address { - font-style: normal; - margin: 0.5em 0; -} -dt { - color: var(--color-mild); - font-size: var(--fs-mild); -} -p { - color: var(--color-mild); - font-size: var(--fs-mild); - margin: 0.5em 0; -} -p > svg { - vertical-align: top; - width: 1.3em; - height: 1.3em; -} -.summary { - color: var(--color-base); - font-size: var(--fs-base); - font-style: italic; -} -.summary { - font-style: italic; -} - -:host::part(card) { - position: relative; - border-top: 2em solid var(--profile-brand-color); - border-radius: var(--radius); - box-shadow: 0 0 0 1px var(--card-shadow-color); - background: var(--card-bg); - - overflow-wrap: break-word; - overflow-wrap: anywhere; - max-width: 30em; -} - -:host header { - border-bottom: var(--divider); - margin-bottom: 1em; - padding: 0 1em; -} -:host footer { - border-top: var(--divider); - margin-top: 1em; - padding: 1em; -} - -:host::part(logo) { - width: 1.6em; - height: 1.6em; - margin: 0 auto; - position: absolute; - right: 1em; - top: -1.8em; - box-shadow: 0 0 0 1px white; - border-radius: .07em; -} - -:host header a { - display: flex; - margin-top: -1em; -} - -:host::part(avatar) { - display: inline-block; - border-radius: 100%; - position: relative; - width: 3em; - height: 3em; - overflow: hidden; - vertical-align: middle; - flex-shrink: 0; - margin-right: .5em; -} -:host::part(avatar) img { - border-radius: 100%; - width: 100%; - height: 100%; - display: inline-block; - vertical-align: bottom; -} - -:host::part(name) { - margin-top: 1.25em; - - color: var(--color-bold); - font-size: var(--fs-bold); - font-weight: var(--fw-bold); -} - -:host::part(main) { - padding: 0 1em; -} - -:host::part(post) { - color: var(--card-color-bold); -} -:host::part(post-img) { - width: 100%; - height: auto; -} -:host::part(cta) { - border: 1px solid; - outline: 0; - text-align: center; - display: block; - position: relative; - overflow-wrap: normal; - padding: .5em 1em; - - border-color: var(--cta-border); - border-radius: var(--radius); - background-color: var(--cta-bg); - color: var(--cta-color); -} - -:host::part(cta):hover, :host::part(cta):focus { - background-color: var(--cta-bg-hover); - border-color: var(--cta-border-hover); - color: var(--cta-color-hover); -} - -:host::part(cta):focus { - box-shadow: var(--focus-ring); - text-decoration: underline -} - -:host::part(branded) { - border-color: var(--cta-branded-border); - background-color: var(--cta-branded-bg); - color: var(--cta-branded-color); -} -:host::part(branded):hover, :host::part(branded):focus { - background-color: var(--cta-branded-bg-hover); - border-color: var(--cta-branded-border-hover); - color: var(--cta-branded-color-hover); -} \ No newline at end of file diff --git a/workspaces/website/public/scott-nath-profile-pic.jpeg b/workspaces/website/public/scott-nath-profile-pic.jpeg new file mode 100644 index 0000000..54ce471 Binary files /dev/null and b/workspaces/website/public/scott-nath-profile-pic.jpeg differ diff --git a/workspaces/website/src/components/BaseHead.astro b/workspaces/website/src/components/BaseHead.astro index 4a029e7..00e7f62 100644 --- a/workspaces/website/src/components/BaseHead.astro +++ b/workspaces/website/src/components/BaseHead.astro @@ -22,6 +22,7 @@ const { title, description, image = '/placeholder-scottnath.jpeg' } = Astro.prop + diff --git a/workspaces/website/src/components/DevToUser.astro b/workspaces/website/src/components/DevToUser.astro new file mode 100644 index 0000000..ea5d6cc --- /dev/null +++ b/workspaces/website/src/components/DevToUser.astro @@ -0,0 +1,20 @@ +--- +// @todo: vite, via astro, doesn't support dynamic imports yet +// @see https://github.com/withastro/astro/issues/8660 +// @future-feature: import { user } from 'profile-components/devto-utils'; +import devto from 'profile-components/devto-utils'; +const user = devto.user; + +const userContent = await user.generateContent({ + username: 'scottnath', + profile_image: '/scott-nath-profile-pic.jpeg' +},true); +let userHTML = ''; +userHTML += user.html(userContent); +--- + + + + + diff --git a/workspaces/website/src/components/GitHubUser.astro b/workspaces/website/src/components/GitHubUser.astro index c8a7447..e7210ad 100644 --- a/workspaces/website/src/components/GitHubUser.astro +++ b/workspaces/website/src/components/GitHubUser.astro @@ -8,6 +8,7 @@ const user = github.user; const repos = JSON.stringify(['scottnath/profile-components', 'storydocker/storydocker']); const userContent = await user.generateContent({ login: 'scottnath', + avatar_url: '/scott-nath-profile-pic.jpeg', repos },true); let userHTML = ''; diff --git a/workspaces/website/src/pages/index.astro b/workspaces/website/src/pages/index.astro index 1c13529..566bb40 100644 --- a/workspaces/website/src/pages/index.astro +++ b/workspaces/website/src/pages/index.astro @@ -1,16 +1,12 @@ --- -import { DevToProfileCard } from 'scottnath-components/src/devto/profile-card'; -import { getUserContent } from 'scottnath-components/src/devto/get-devto-user'; - import GitHubUser from '../components/GitHubUser.astro'; +import DevToUser from '../components/DevToUser.astro'; import BaseHead from '../components/BaseHead.astro'; import Header from '../components/Header.astro'; import Footer from '../components/Footer.astro'; import { SITE_TITLE, SITE_DESCRIPTION } from '../consts'; import linkedinLogo from '~/assets/logos/linkedin.svg'; import mastodonLogo from '~/assets/logos/Mastodon.svg'; - -const { user, posts } = await getUserContent('scottnath'); --- @@ -33,7 +29,7 @@ const { user, posts } = await getUserContent('scottnath');