From dc05f93522a027b52eace19e43fbb9f565e300bb Mon Sep 17 00:00:00 2001 From: Badger Date: Thu, 25 Aug 2022 00:35:58 -0400 Subject: [PATCH 1/4] - Added TypeScript support to project - Added Ignores for nullability checks in models - Added Math/Color Utilities - Added models which shall support member-card - Added plugin which will render hexagons --- .gitignore | 1 + SocialCoder.Web/Client/ColorUtil.cs | 24 +++++++ SocialCoder.Web/Client/MathUtil.cs | 14 ++++ .../Client/SocialCoder.Web.Client.csproj | 8 +++ SocialCoder.Web/Client/Typescript/Hexagon.ts | 70 +++++++++++++++++++ SocialCoder.Web/Client/tsconfig.json | 18 +++++ SocialCoder.Web/Client/wwwroot/index.html | 6 ++ .../Client/wwwroot/js/xm_plugins.min.js | 13 ++++ .../Shared/Enums/SocialMediaType.cs | 12 ++++ SocialCoder.Web/Shared/Models/Badge.cs | 3 +- .../Shared/Models/BadgeProgress.cs | 3 +- .../Shared/Models/BadgeRequirement.cs | 3 +- .../Shared/ViewModels/UserBadgeViewModel.cs | 3 +- .../Shared/ViewModels/UserSocialMediaItem.cs | 9 +++ 14 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 SocialCoder.Web/Client/ColorUtil.cs create mode 100644 SocialCoder.Web/Client/MathUtil.cs create mode 100644 SocialCoder.Web/Client/Typescript/Hexagon.ts create mode 100644 SocialCoder.Web/Client/tsconfig.json create mode 100644 SocialCoder.Web/Client/wwwroot/js/xm_plugins.min.js create mode 100644 SocialCoder.Web/Shared/Enums/SocialMediaType.cs create mode 100644 SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs diff --git a/.gitignore b/.gitignore index 8d3207a..1bdec97 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ Database/ .vs/ .idea/ .env +dist \ No newline at end of file diff --git a/SocialCoder.Web/Client/ColorUtil.cs b/SocialCoder.Web/Client/ColorUtil.cs new file mode 100644 index 0000000..17be391 --- /dev/null +++ b/SocialCoder.Web/Client/ColorUtil.cs @@ -0,0 +1,24 @@ +using MudBlazor; +using MudBlazor.Utilities; + +namespace SocialCoder.Web.Client; + +public static class ColorUtil +{ + public static string GetCssValue(MudTheme theme, Color color) + { + return color switch + { + Color.Primary => theme.PaletteDark.Primary.Value, + Color.Secondary => theme.PaletteDark.Secondary.Value, + Color.Tertiary => theme.PaletteDark.Tertiary.Value, + Color.Dark => theme.PaletteDark.Dark.Value, + Color.Error => theme.PaletteDark.Error.Value, + Color.Surface => theme.PaletteDark.Surface.Value, + Color.Warning => theme.PaletteDark.Warning.Value, + Color.Info => theme.PaletteDark.Info.Value, + Color.Success => theme.PaletteDark.Success.Value, + _ => theme.PaletteDark.Primary.Value + }; + } +} \ No newline at end of file diff --git a/SocialCoder.Web/Client/MathUtil.cs b/SocialCoder.Web/Client/MathUtil.cs new file mode 100644 index 0000000..c8da7c1 --- /dev/null +++ b/SocialCoder.Web/Client/MathUtil.cs @@ -0,0 +1,14 @@ +namespace SocialCoder.Web.Client; + +public static class MathUtil +{ + /// + /// Normalizes value between 0 and 1 + /// + /// + /// + /// + /// + public static double GetNormalizedPercentage(int value, int min, int max) + => (double)(value - min) / (max - min); +} \ No newline at end of file diff --git a/SocialCoder.Web/Client/SocialCoder.Web.Client.csproj b/SocialCoder.Web/Client/SocialCoder.Web.Client.csproj index fc638e5..27e209e 100644 --- a/SocialCoder.Web/Client/SocialCoder.Web.Client.csproj +++ b/SocialCoder.Web/Client/SocialCoder.Web.Client.csproj @@ -12,6 +12,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -23,4 +27,8 @@ + + + + diff --git a/SocialCoder.Web/Client/Typescript/Hexagon.ts b/SocialCoder.Web/Client/Typescript/Hexagon.ts new file mode 100644 index 0000000..92b94ee --- /dev/null +++ b/SocialCoder.Web/Client/Typescript/Hexagon.ts @@ -0,0 +1,70 @@ +interface HexagonOptions +{ + /** + * Classname to look for in the DOM + */ + container: string; + + /** + * Width of hexagon + */ + width: number; + + /** + * Height of hexagon + */ + height: number; + + /** + * Should there be rounded corners? + */ + roundedCorners: boolean; + + /** + * Radius for rounded corners + */ + roundedCornerRadius: number; + + /** + * Filled? + */ + fill: boolean; + + /** + * Line color for hexagon + */ + lineColor: string; + + /** + * Line width for hexagon + */ + lineWidth: number; + + clip: boolean; + + gradient: GradientOptions; + scale: ScaleOptions; +} + +interface GradientOptions +{ + colors: string[]; +} + +interface ScaleOptions +{ + start: number; + end: number; + stop: number; +} + +/** + * This function is tied to the xm_plugins.min.js file in the wwwroot/js folder + * @param options + */ +function createHexagon(options: HexagonOptions) +{ + // Badger: This is excluded because it's included as an external library + // @ts-ignore + return new XM_Hexagon(options); +} \ No newline at end of file diff --git a/SocialCoder.Web/Client/tsconfig.json b/SocialCoder.Web/Client/tsconfig.json new file mode 100644 index 0000000..4b7e842 --- /dev/null +++ b/SocialCoder.Web/Client/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "removeComments": false, + "noEmitOnError": true, + "noImplicitAny": false, + "sourceMap": true, + "outDir": "wwwroot/js/dist" + }, + "include": [ + "Typescript/**/*" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/SocialCoder.Web/Client/wwwroot/index.html b/SocialCoder.Web/Client/wwwroot/index.html index 9055307..5939b40 100644 --- a/SocialCoder.Web/Client/wwwroot/index.html +++ b/SocialCoder.Web/Client/wwwroot/index.html @@ -35,7 +35,13 @@ + + + + + + diff --git a/SocialCoder.Web/Client/wwwroot/js/xm_plugins.min.js b/SocialCoder.Web/Client/wwwroot/js/xm_plugins.min.js new file mode 100644 index 0000000..0840a5e --- /dev/null +++ b/SocialCoder.Web/Client/wwwroot/js/xm_plugins.min.js @@ -0,0 +1,13 @@ +"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function XM_Accordion(t){var s={triggerSelector:".accordion-trigger",contentSelector:".accordion-content",animation:{type:"all",speed:.3,ease:"ease-in-out"},paddingAnimation:!1,startOpenClass:"accordion-open",selectedClass:"selected",linkTriggers:!1},d={},n=function(){var t=!0,n=!1,e=void 0;try{for(var o,r=d.accordions[Symbol.iterator]();!(t=(o=r.next()).done);t=!0){var i=o.value;i.open&&(i.content.style.height="auto",i.content.style.height="".concat(i.content.scrollHeight,"px"))}}catch(t){n=!0,e=t}finally{try{t||null==r.return||r.return()}finally{if(n)throw e}}},e=function(){var t=document.querySelectorAll(s.triggerSelector);if(!t.length)throw new Error("Couldn't find ".concat(s.triggerSelector," in the DOM"));var n=!0,e=!(d.accordions=[]),o=void 0;try{for(var r,i=t[Symbol.iterator]();!(n=(r=i.next()).done);n=!0){var a=r.value,c=a.querySelector(s.contentSelector);if(!c&&!(c=a.parentElement.querySelector(s.contentSelector)))throw new Error("Couldn't find ".concat(s.contentSelector," in ").concat(s.triggerSelector," nor as it's sibling"));if(s.paddingAnimation)d.accordions.push({trigger:a,content:c,padding:c.style.padding,open:!0,startOpen:c.classList.contains(s.startOpenClass)});else{var l=document.createElement("div");c.parentElement.appendChild(l),l.appendChild(c),d.accordions.push({trigger:a,content:l,open:!0,startOpen:c.classList.contains(s.startOpenClass)})}}}catch(t){e=!0,o=t}finally{try{n||null==i.return||i.return()}finally{if(e)throw o}}},o=function(){var t=!0,n=!1,e=void 0;try{for(var o,r=d.accordions[Symbol.iterator]();!(t=(o=r.next()).done);t=!0){var i=o.value;i.content.style.overflow="hidden",i.startOpen?(i.content.style.height="".concat(i.content.scrollHeight,"px"),i.content.parentElement.classList.add(s.selectedClass)):f(i)}}catch(t){n=!0,e=t}finally{try{t||null==r.return||r.return()}finally{if(n)throw e}}},r=function(){var t=!0,n=!1,e=void 0;try{for(var o,r=d.accordions[Symbol.iterator]();!(t=(o=r.next()).done);t=!0){o.value.content.style.transition="".concat(s.animation.type," ").concat(s.animation.speed,"s ").concat(s.animation.ease)}}catch(t){n=!0,e=t}finally{try{t||null==r.return||r.return()}finally{if(n)throw e}}},i=function(){var t=!0,n=!1,e=void 0;try{for(var o,r=function(){var c=o.value;c.trigger.addEventListener("click",function(){if(s.linkTriggers){var t=c.open?f:y,n=!0,e=!1,o=void 0;try{for(var r,i=d.accordions[Symbol.iterator]();!(n=(r=i.next()).done);n=!0){var a=r.value;f(a)}}catch(t){e=!0,o=t}finally{try{n||null==i.return||i.return()}finally{if(e)throw o}}s.triggerOpens?y(c):t(c)}else l(c)})},i=d.accordions[Symbol.iterator]();!(t=(o=i.next()).done);t=!0)r()}catch(t){n=!0,e=t}finally{try{t||null==i.return||i.return()}finally{if(n)throw e}}},l=function(t){t.open?f(t):y(t)},y=function(t){t.open||(t.open=!0,t.content.style.height="".concat(t.content.scrollHeight,"px"),t.content.parentElement.classList.add(s.selectedClass),s.paddingAnimation&&(t.content.style.padding=t.padding))},f=function(t){t.open&&(t.open=!1,t.content.style.height=0,t.content.parentElement.classList.remove(s.selectedClass),s.paddingAnimation&&(t.content.style.padding=0))};return function t(n,e){var o;for(var r in e)"object"!==_typeof(e[r])||e[r]instanceof Date?e[r]instanceof Date?n[r]=new Date(e[r].getTime()):n[r]=e[r]:(o=e[r]instanceof Array?[]:{},void 0===n[r]&&(n[r]=o),t(n[r],e[r]))}(s,t),e(),o(),r(),i(),window.addEventListener("resize",n),d} + +"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function XM_Dropdown(t){var c,g={container:".dropdown",trigger:".dropdown-trigger",activeClass:"active",triggerEvent:"click",offset:{},animation:{type:"static",speed:.4,ease:"ease-in-out",zIndex:9999,translateOffset:{horizontal:40,vertical:40}},absolute:!1,closeOnWindowClick:!0,closeOnDropdownClick:!1,linkDropdowns:!0,controlToggle:!1},h=[],n={},r=function(){if(g.controlToggle){var t=document.querySelectorAll(g.container);if(!t.length)throw new Error("".concat(g.container," not found in the DOM"));var n=!0,r=!1,o=void 0;try{for(var e,i=t[Symbol.iterator]();!(n=(e=i.next()).done);n=!0){var a=e.value,l={};l.parent=a.parentElement,l.container=a,h.push(l)}}catch(t){r=!0,o=t}finally{try{n||null==i.return||i.return()}finally{if(r)throw o}}}else{var c=document.querySelectorAll(g.trigger);if(!c.length)throw new Error("".concat(g.trigger," not found in the DOM"));var f=!0,s=!1,u=void 0;try{for(var y,v=c[Symbol.iterator]();!(f=(y=v.next()).done);f=!0){var d=y.value,p=d.parentElement.querySelector(g.container);if(!p)throw new Error("".concat(g.container," not found as sibling of ").concat(g.trigger));var m={};m.parent=p.parentElement,m.trigger=d,m.container=p,h.push(m)}}catch(t){s=!0,u=t}finally{try{f||null==v.return||v.return()}finally{if(s)throw u}}}},o=function(){var t=!0,n=!1,r=void 0;try{for(var o,e=h[Symbol.iterator]();!(t=(o=e.next()).done);t=!0){var i=o.value;a(i)}}catch(t){n=!0,r=t}finally{try{t||null==e.return||e.return()}finally{if(n)throw r}}},a=function(t){for(var n in t.parent.style.position=g.absolute?"absolute":"relative",S(t.container,{position:"absolute",zIndex:g.animation.zIndex}),g.offset)t.container.style[n]="".concat(g.offset[n],"px")},e=function(){var t=!0,n=!1,r=void 0;try{for(var o,e=h[Symbol.iterator]();!(t=(o=e.next()).done);t=!0){var i=o.value;l(i)}}catch(t){n=!0,r=t}finally{try{t||null==e.return||e.return()}finally{if(n)throw r}}},l=function(t){"translate-top"!==g.animation.type&&"translate-bottom"!==g.animation.type||(t.container.style.transition="transform ".concat(g.animation.speed,"s ").concat(g.animation.ease,",\n opacity ").concat(g.animation.speed,"s ").concat(g.animation.ease,",\n visibility ").concat(g.animation.speed,"s ").concat(g.animation.ease))},i=function(){var t=!0,n=!1,r=void 0;try{for(var o,e=h[Symbol.iterator]();!(t=(o=e.next()).done);t=!0){var i=o.value;f(i)}}catch(t){n=!0,r=t}finally{try{t||null==e.return||e.return()}finally{if(n)throw r}}},f=function(t){"click"===g.triggerEvent?t.trigger.addEventListener("click",function(){v(t)}):"hover"===g.triggerEvent&&(t.trigger.addEventListener("mouseenter",function(){m(t)}),t.trigger.addEventListener("mouseleave",function(){p(t)}))},s=function(){var t=!0,n=!1,r=void 0;try{for(var o,e=h[Symbol.iterator]();!(t=(o=e.next()).done);t=!0){var i=o.value;u(i)}}catch(t){n=!0,r=t}finally{try{t||null==e.return||e.return()}finally{if(n)throw r}}},u=function(t){t.container.addEventListener("click",function(){p(t)})},y=function(){window.addEventListener("click",function(t){if(c){var n=t.target;do{var r=!0,o=!1,e=void 0;try{for(var i,a=h[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var l=i.value;if(n===l.trigger||n===l.container)return}}catch(t){o=!0,e=t}finally{try{r||null==a.return||a.return()}finally{if(o)throw e}}}while(n=n.parentElement);d()}})},v=function(t){(t.active?p:m)(t)},d=function(){var t=!0,n=!1,r=void 0;try{for(var o,e=h[Symbol.iterator]();!(t=(o=e.next()).done);t=!0){var i=o.value;p(i)}}catch(t){n=!0,r=t}finally{try{t||null==e.return||e.return()}finally{if(n)throw r}}},p=function(t){w(t),g.controlToggle||function(t){t.trigger.classList.remove(g.activeClass)}(t),t.active=!1,c=!1},m=function(t){g.linkDropdowns&&d(),b(t),g.controlToggle||function(t){t.trigger.classList.add(g.activeClass)}(t),t.active=!0,c=!0},w=function(t){"static"===g.animation.type?S(t.container,{display:"none"}):"translate-top"===g.animation.type?S(t.container,{opacity:0,visibility:"hidden",transform:"translate(0, -".concat(g.animation.translateOffset.vertical,"px)")}):"translate-bottom"===g.animation.type&&S(t.container,{opacity:0,visibility:"hidden",transform:"translate(0, ".concat(g.animation.translateOffset.vertical,"px)")})},b=function(t){"static"===g.animation.type?S(t.container,{display:"block"}):"translate-top"!==g.animation.type&&"translate-bottom"!==g.animation.type||S(t.container,{opacity:1,visibility:"visible",transform:"translate(0, 0)"})},S=function(t,n){for(var r in n)t.style[r]=n[r]};return function t(n,r){var o;for(var e in r)"object"!==_typeof(r[e])||r[e]instanceof Date?r[e]instanceof Date?n[e]=new Date(r[e].getTime()):n[e]=r[e]:(o=r[e]instanceof Array?[]:{},void 0===n[e]&&(n[e]=o),t(n[e],r[e]))}(g,t),r(),o(),g.controlToggle||i(),g.closeOnDropdownClick&&s(),g.closeOnWindowClick&&y(),d(),window.setTimeout(e,300),n.showDropdowns=function(){var t=!0,n=!1,r=void 0;try{for(var o,e=h[Symbol.iterator]();!(t=(o=e.next()).done);t=!0){var i=o.value;m(i)}}catch(t){n=!0,r=t}finally{try{t||null==e.return||e.return()}finally{if(n)throw r}}},n.hideDropdowns=d,n} + +"use strict";function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function XM_Hexagon(t){var p={width:100,height:110,lineWidth:6,lineColor:"#fff",lineCap:"square",buttEnd:!1,fill:!1,clip:!1,roundedCorners:!1,roundedCornerRadius:4,animation:{easing:!0},animateOnScroll:!1,controlAnimation:!1,speed:50,scale:{start:0,end:1,stop:1},invertedProgress:!1,reverse:!1,linkText:!1,innerLink:!0,linkToContainer:".bar-progress-wrap",linkTo:".bar-progress-text",extraLinkTo:[],linkUnits:"%",linkUnitsSelector:".bar-progress-unit",innerTextFollowsProgress:!1,decimalPoints:0,barTextStyle:{primaryColor:"#fff",secondaryColor:"#363636",font:"bold 10px Exo, sans-serif"}},h=[],v={},i=function(){var t=document.querySelectorAll(p.container);if(!t.length)throw Error('Unable to find "'.concat(p.container,'" on the DOM'));var i=!0,e=!1,n=void 0;try{for(var r,o=t[Symbol.iterator]();!(i=(r=o.next()).done);i=!0){var a=r.value,d={};d.container=a,d.imageSrc=a.getAttribute("data-src"),d.canvas=document.createElement("canvas"),d.ctx=d.canvas.getContext("2d"),d.finishedDrawing=!1,d.canvas.width=p.width,d.canvas.height=p.height,d.canvas.style.position="absolute",d.canvas.style.top=0,d.canvas.style.left=0,d.container.style.width="".concat(p.width,"px"),d.container.style.height="".concat(p.height,"px"),d.container.style.position="relative",d.container.append(d.canvas),h.push(d)}}catch(t){e=!0,n=t}finally{try{i||null==o.return||o.return()}finally{if(e)throw n}}},e=function(){t.scale&&(p.scale.stop=p.scale.stop>p.scale.end?p.scale.end:p.scale.stop,p.scale.stop=p.scale.stop=p.stopPoint-1&&(t.animation.currentProgress=p.stopPoint,t.finishedDrawing=!0)):(t.animation.currentProgress+=t.animation.step,t.animation.currentProgress>=p.stopPoint&&(t.animation.currentProgress=p.stopPoint,t.finishedDrawing=!0))),s(t,t.animation.currentProgress),t.finishedDrawing||window.requestAnimationFrame(d)}function m(t,i){return Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2))}function T(t,i,e){var n=m(t,i),r=Math.min(e,n),o=function(t,i,e){var n=i.x-t.x,r=i.y-t.y,o=m(t,i),a=n/o,d=r/o;return{x:t.x+e*a,y:t.y+e*d}}(t,i,r);return{x:o.x,y:o.y,distance:r}}var o=function(t,i){return(-i/2+Math.sqrt(Math.pow(i,2)+.75*Math.pow(t,2)))/1.5},s=function(n,t){var i=1p.scale.end?p.scale.end:t)=p.stopPoint-1&&(p.animation.currentProgress=p.stopPoint,l.done=!0)):(p.animation.currentProgress+=p.animation.step,p.animation.currentProgress>=p.stopPoint&&(p.animation.currentProgress=p.stopPoint,l.done=!0))),E(p.animation.currentProgress),l.done||window.requestAnimationFrame(x)}var E=function(e){var t=0p.scale.end?p.scale.end:e)p.scale.end?p.scale.end:p.scale.stop,p.scale.stop=p.scale.stop /// Archetype for type of badge diff --git a/SocialCoder.Web/Shared/Models/BadgeProgress.cs b/SocialCoder.Web/Shared/Models/BadgeProgress.cs index eda9662..62a58c4 100644 --- a/SocialCoder.Web/Shared/Models/BadgeProgress.cs +++ b/SocialCoder.Web/Shared/Models/BadgeProgress.cs @@ -1,4 +1,5 @@ -namespace SocialCoder.Web.Shared.Models; +#pragma warning disable CS8618 +namespace SocialCoder.Web.Shared.Models; public class BadgeProgress { diff --git a/SocialCoder.Web/Shared/Models/BadgeRequirement.cs b/SocialCoder.Web/Shared/Models/BadgeRequirement.cs index b0be96c..5560fcd 100644 --- a/SocialCoder.Web/Shared/Models/BadgeRequirement.cs +++ b/SocialCoder.Web/Shared/Models/BadgeRequirement.cs @@ -1,4 +1,5 @@ -namespace SocialCoder.Web.Shared.Models; +#pragma warning disable CS8618 +namespace SocialCoder.Web.Shared.Models; public class BadgeRequirement { diff --git a/SocialCoder.Web/Shared/ViewModels/UserBadgeViewModel.cs b/SocialCoder.Web/Shared/ViewModels/UserBadgeViewModel.cs index 7d92a91..cca2118 100644 --- a/SocialCoder.Web/Shared/ViewModels/UserBadgeViewModel.cs +++ b/SocialCoder.Web/Shared/ViewModels/UserBadgeViewModel.cs @@ -1,4 +1,5 @@ -using SocialCoder.Web.Shared.Models; +#pragma warning disable CS8618 +using SocialCoder.Web.Shared.Models; namespace SocialCoder.Web.Shared.ViewModels; diff --git a/SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs b/SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs new file mode 100644 index 0000000..dbf2f27 --- /dev/null +++ b/SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs @@ -0,0 +1,9 @@ +using SocialCoder.Web.Shared.Enums; + +namespace SocialCoder.Web.Shared.ViewModels; + +public class UserSocialMediaItem +{ + public string Url { get; set; } + public SocialMediaType Type { get; set; } +} \ No newline at end of file From 69700bdc7a4eefb24902828faca0cd6bc7333a60 Mon Sep 17 00:00:00 2001 From: Badger Date: Thu, 25 Aug 2022 19:24:48 -0400 Subject: [PATCH 2/4] - Added avatar component - Added member card component --- .../Client/Shared/Components/MemberCard.razor | 77 +++++++++ .../Client/Shared/Components/UserAvatar.razor | 157 ++++++++++++++++++ SocialCoder.Web/Client/wwwroot/css/app.css | 66 +------- SocialCoder.Web/Client/wwwroot/index.html | 2 +- .../Shared/ViewModels/BasicBadgeViewModel.cs | 8 + .../Shared/ViewModels/MemberInfoViewModel.cs | 49 ++++++ 6 files changed, 298 insertions(+), 61 deletions(-) create mode 100644 SocialCoder.Web/Client/Shared/Components/MemberCard.razor create mode 100644 SocialCoder.Web/Client/Shared/Components/UserAvatar.razor create mode 100644 SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs create mode 100644 SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs diff --git a/SocialCoder.Web/Client/Shared/Components/MemberCard.razor b/SocialCoder.Web/Client/Shared/Components/MemberCard.razor new file mode 100644 index 0000000..baa25e2 --- /dev/null +++ b/SocialCoder.Web/Client/Shared/Components/MemberCard.razor @@ -0,0 +1,77 @@ +@using SocialCoder.Web.Shared.ViewModels + + + + + + @Username + + @if (!string.IsNullOrEmpty(AlternativeName)) + { + @AlternativeName + } + + @* + Create a row of badges to showcase + *@ + + @foreach (var badge in Model?.Badges.Take(4) ?? new List()) + { + +
+
+ } +
+ + + +
+ @PostsCount + Posts +
+
+ +
+ @FriendsCount + Friends +
+
+
+ + + + + Add Friend + + + Message + + +
+ +
+
+ +@code { + int UserLevel => Model?.UserLevel ?? 0; + int FriendsCount => Model?.NumberOfFriends ?? 0; + int PostsCount => Model?.NumberOfPosts ?? 0; + string AvatarImage => Model?.UserImage ?? string.Empty; + string Username => Model?.Username ?? string.Empty; + string AlternativeName => Model?.AlternateName ?? string.Empty; + + [Parameter] + public MemberInfoViewModel? Model { get; set; } + +} \ No newline at end of file diff --git a/SocialCoder.Web/Client/Shared/Components/UserAvatar.razor b/SocialCoder.Web/Client/Shared/Components/UserAvatar.razor new file mode 100644 index 0000000..dc6898e --- /dev/null +++ b/SocialCoder.Web/Client/Shared/Components/UserAvatar.razor @@ -0,0 +1,157 @@ +@inject IJSRuntime JsRuntime + +
+
+
+
+
+
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+

+ @UserLevel +

+
+
+
+
+@code { + + [Parameter] + public string AvatarImage { get; set; } + + [Parameter] + public int UserLevel { get; set; } + + [Parameter] + public int Progress { get; set; } + + [Parameter] + public int ProgressMin { get; set; } = 0; + + [Parameter] + public int ProgressMax { get; set; } = 100; + + [Parameter] + public int Width { get; set; } = 100; + + [Parameter] + public int Height { get; set; } = 100; + + [Parameter] + public int LineWidth { get; set; } = 8; + + [Parameter] + public Color ProgressColor { get; set; } = Color.Primary; + + [Parameter] + public RenderFragment? CenterContent { get; set; } + + [Parameter] + public Color BadgeLineColor { get; set; } = Color.Secondary; + + [Parameter] + public Color BadgeColor { get; set; } = Color.Tertiary; + + MudTheme _theme = new(); + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + /* + It is worth mentioning that + + 1. To have the line color appear -- you cannot use the gradient value + 2. To see the progress bar you cannot use the fill or clip value -- those are for images + 3. These methods are called AFTER render because we want to make sure our + DOM elements are present before executing these scripts + */ + + await JsRuntime.InvokeVoidAsync("createHexagon", new + { + width = Width, + height = Height, + container = ".hexagon-progress", + roundedCorners = true, + lineWidth = LineWidth, + lineColor = ColorUtil.GetCssValue(_theme, ProgressColor), + scale = new { start = 0, end = 1, stop = MathUtil.GetNormalizedPercentage(Progress, ProgressMin, ProgressMax) } + }); + + await JsRuntime.InvokeVoidAsync("createHexagon", new + { + width = 68, + Height = 68, + container = ".hexagon-image", + roundedCorners = true, + clip = true + }); + + await JsRuntime.InvokeVoidAsync("createHexagon", new + { + container = ".hexagon-dark", + width = 26, + height = 28, + roundedCorners = true, + roundedCornerRadius = 1, + lineColor = ColorUtil.GetCssValue(_theme, BadgeLineColor), + fill = true + }); + + await JsRuntime.InvokeVoidAsync("createHexagon", new + { + container = ".hexagon-avatar-badge", + width = 32, + height = 36, + fill = true, + roundedCorners = true, + roundedCornerRadius = 1, + lineColor = ColorUtil.GetCssValue(_theme, BadgeColor) + }); + } + +} \ No newline at end of file diff --git a/SocialCoder.Web/Client/wwwroot/css/app.css b/SocialCoder.Web/Client/wwwroot/css/app.css index 9cd148f..8707e83 100644 --- a/SocialCoder.Web/Client/wwwroot/css/app.css +++ b/SocialCoder.Web/Client/wwwroot/css/app.css @@ -1,64 +1,10 @@ @import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); -html, body { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +.container-item { + flex: 1; + display: flex; + justify-content: center; } -h1:focus { - outline: none; -} - -a, .btn-link { - color: #0071c1; -} - -.btn-primary { - color: #fff; - background-color: #1b6ec2; - border-color: #1861ac; -} - -.content { - padding-top: 1.1rem; -} - -.valid.modified:not([type=checkbox]) { - outline: 1px solid #26b050; -} - -.invalid { - outline: 1px solid red; -} - -.validation-message { - color: red; -} - -#blazor-error-ui { - background: lightyellow; - bottom: 0; - box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); - display: none; - left: 0; - padding: 0.6rem 1.25rem 0.7rem 1.25rem; - position: fixed; - width: 100%; - z-index: 1000; -} - - #blazor-error-ui .dismiss { - cursor: pointer; - position: absolute; - right: 0.75rem; - top: 0.5rem; - } - -.blazor-error-boundary { - background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; - padding: 1rem 1rem 1rem 3.7rem; - color: white; -} - - .blazor-error-boundary::after { - content: "An error has occurred." - } +.container-item:first-child > * { margin-right: auto; } +.container-item:last-child > * { margin-left: auto; } \ No newline at end of file diff --git a/SocialCoder.Web/Client/wwwroot/index.html b/SocialCoder.Web/Client/wwwroot/index.html index 5939b40..e09efec 100644 --- a/SocialCoder.Web/Client/wwwroot/index.html +++ b/SocialCoder.Web/Client/wwwroot/index.html @@ -12,7 +12,7 @@ - + diff --git a/SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs b/SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs new file mode 100644 index 0000000..4bc0b8f --- /dev/null +++ b/SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs @@ -0,0 +1,8 @@ +namespace SocialCoder.Web.Shared.ViewModels; + +public class BasicBadgeViewModel +{ + public int BadgeId { get; set; } + public string Title { get; set; } + public string ImagePath { get; set; } +} \ No newline at end of file diff --git a/SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs b/SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs new file mode 100644 index 0000000..b3450a3 --- /dev/null +++ b/SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs @@ -0,0 +1,49 @@ +namespace SocialCoder.Web.Shared.ViewModels; + +public class MemberInfoViewModel +{ + /// + /// Unique User Id + /// + public string UserId { get; set; } + + /// + /// Primary display name for user on the website + /// + public string Username { get; set; } + + /// + /// Name user also goes by + /// + public string AlternateName { get; set; } + + /// + /// Avatar image for user + /// + public string UserImage { get; set; } + + /// + /// Current user level + /// + public int UserLevel { get; set; } + + /// + /// Number of posts this user has made + /// + public int NumberOfPosts { get; set; } + + /// + /// Number of friends this user has + /// + public int NumberOfFriends { get; set; } + + /// + /// Any social media links this user may have on their profile + /// + public List Socials { get; set; } = new(); + + /// + /// Any badges this user has + /// + public List Badges { get; set; } = new(); +} \ No newline at end of file From dc69bb1c07ef652449c14c1f609532fc70e8d431 Mon Sep 17 00:00:00 2001 From: Badger Date: Thu, 25 Aug 2022 21:34:41 -0400 Subject: [PATCH 3/4] Added social media icons/links to member card. --- .../Client/Shared/Components/MemberCard.razor | 49 ++++++++++++++++++- SocialCoder.Web/Client/_Imports.razor | 3 +- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/SocialCoder.Web/Client/Shared/Components/MemberCard.razor b/SocialCoder.Web/Client/Shared/Components/MemberCard.razor index baa25e2..726943a 100644 --- a/SocialCoder.Web/Client/Shared/Components/MemberCard.razor +++ b/SocialCoder.Web/Client/Shared/Components/MemberCard.razor @@ -1,4 +1,5 @@ @using SocialCoder.Web.Shared.ViewModels +@using SocialCoder.Web.Shared.Enums @@ -48,7 +49,20 @@ - + + + @foreach (var social in Model?.Socials ?? new List()) + { + var icon = GetSocialInfo(social.Type); + var color = $"color: {colors[_count % 6]}"; + + + + + + _count++; + } + @@ -70,8 +84,39 @@ string AvatarImage => Model?.UserImage ?? string.Empty; string Username => Model?.Username ?? string.Empty; string AlternativeName => Model?.AlternateName ?? string.Empty; + int _count = 0; + + MudTheme _theme = new(); + string[] colors; + + string GetSocialInfo(SocialMediaType type) + => type switch + { + SocialMediaType.Discord => Icons.Custom.Brands.Discord, + SocialMediaType.Microsoft => Icons.Custom.Brands.Microsoft, + SocialMediaType.Instagram => Icons.Custom.Brands.Instagram, + SocialMediaType.GitHub => Icons.Custom.Brands.GitHub, + SocialMediaType.Twitter => Icons.Custom.Brands.Twitter, + SocialMediaType.Google => Icons.Custom.Brands.Google, + _ => Icons.Filled.QuestionMark + }; + [Parameter] public MemberInfoViewModel? Model { get; set; } - + + protected override void OnInitialized() + { + base.OnInitialized(); + + colors = new[] + { + _theme.PaletteDark.PrimaryLighten, + _theme.PaletteDark.SecondaryLighten, + _theme.PaletteDark.TertiaryLighten, + _theme.PaletteDark.SuccessLighten, + _theme.PaletteDark.InfoLighten + }; + } + } \ No newline at end of file diff --git a/SocialCoder.Web/Client/_Imports.razor b/SocialCoder.Web/Client/_Imports.razor index 2830dd6..abee34f 100644 --- a/SocialCoder.Web/Client/_Imports.razor +++ b/SocialCoder.Web/Client/_Imports.razor @@ -12,4 +12,5 @@ @using MudBlazor @using SocialCoder.Web.Shared.Models @using SocialCoder.Web.Shared.Extensions -@using SocialCoder.Web.Client.Shared.Components \ No newline at end of file +@using SocialCoder.Web.Client.Shared.Components +@using SocialCoder.Web.Shared.Enums \ No newline at end of file From ca343924b55b5599dc248cc6d662f7ffe82f7c2b Mon Sep 17 00:00:00 2001 From: Badger Date: Thu, 25 Aug 2022 21:57:07 -0400 Subject: [PATCH 4/4] For certain warnings that have no weight -- added ignores, or default values. --- SocialCoder.Web/Client/Shared/Components/MemberCard.razor | 6 +++--- SocialCoder.Web/Client/Shared/Components/PageHeader.razor | 5 +++-- SocialCoder.Web/Client/Shared/Components/UserAvatar.razor | 4 ++-- SocialCoder.Web/Server/Data/ApplicationDbContext.cs | 3 +++ SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs | 4 ++-- SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs | 4 +++- SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs | 4 ++-- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/SocialCoder.Web/Client/Shared/Components/MemberCard.razor b/SocialCoder.Web/Client/Shared/Components/MemberCard.razor index 726943a..17148e9 100644 --- a/SocialCoder.Web/Client/Shared/Components/MemberCard.razor +++ b/SocialCoder.Web/Client/Shared/Components/MemberCard.razor @@ -54,7 +54,7 @@ @foreach (var social in Model?.Socials ?? new List()) { var icon = GetSocialInfo(social.Type); - var color = $"color: {colors[_count % 6]}"; + var color = $"color: {_colors[_count % 6]}"; @@ -88,7 +88,7 @@ MudTheme _theme = new(); - string[] colors; + string[] _colors = Array.Empty(); string GetSocialInfo(SocialMediaType type) => type switch @@ -109,7 +109,7 @@ { base.OnInitialized(); - colors = new[] + _colors = new[] { _theme.PaletteDark.PrimaryLighten, _theme.PaletteDark.SecondaryLighten, diff --git a/SocialCoder.Web/Client/Shared/Components/PageHeader.razor b/SocialCoder.Web/Client/Shared/Components/PageHeader.razor index a032e20..7d58305 100644 --- a/SocialCoder.Web/Client/Shared/Components/PageHeader.razor +++ b/SocialCoder.Web/Client/Shared/Components/PageHeader.razor @@ -13,8 +13,9 @@ public PageType Type { get; set; } [Parameter] - public string Title { get; set; } + public string Title { get; set; } = string.Empty; [Parameter] - public string Subtitle { get; set; } + public string Subtitle { get; set; } = string.Empty; + } \ No newline at end of file diff --git a/SocialCoder.Web/Client/Shared/Components/UserAvatar.razor b/SocialCoder.Web/Client/Shared/Components/UserAvatar.razor index dc6898e..0e54092 100644 --- a/SocialCoder.Web/Client/Shared/Components/UserAvatar.razor +++ b/SocialCoder.Web/Client/Shared/Components/UserAvatar.razor @@ -56,9 +56,9 @@ @code { - + [Parameter] - public string AvatarImage { get; set; } + public string AvatarImage { get; set; } = string.Empty; [Parameter] public int UserLevel { get; set; } diff --git a/SocialCoder.Web/Server/Data/ApplicationDbContext.cs b/SocialCoder.Web/Server/Data/ApplicationDbContext.cs index 451dcc8..2e7ce7d 100644 --- a/SocialCoder.Web/Server/Data/ApplicationDbContext.cs +++ b/SocialCoder.Web/Server/Data/ApplicationDbContext.cs @@ -5,6 +5,9 @@ using SocialCoder.Web.Server.Models; using SocialCoder.Web.Shared.Models; +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS8618 + namespace SocialCoder.Web.Server.Data { public class ApplicationDbContext : ApiAuthorizationDbContext diff --git a/SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs b/SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs index 4bc0b8f..cdbfe1c 100644 --- a/SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs +++ b/SocialCoder.Web/Shared/ViewModels/BasicBadgeViewModel.cs @@ -3,6 +3,6 @@ public class BasicBadgeViewModel { public int BadgeId { get; set; } - public string Title { get; set; } - public string ImagePath { get; set; } + public string Title { get; set; } = string.Empty; + public string ImagePath { get; set; } = string.Empty; } \ No newline at end of file diff --git a/SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs b/SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs index b3450a3..19b36ac 100644 --- a/SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs +++ b/SocialCoder.Web/Shared/ViewModels/MemberInfoViewModel.cs @@ -1,4 +1,6 @@ -namespace SocialCoder.Web.Shared.ViewModels; +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS8618 +namespace SocialCoder.Web.Shared.ViewModels; public class MemberInfoViewModel { diff --git a/SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs b/SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs index dbf2f27..b4a500a 100644 --- a/SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs +++ b/SocialCoder.Web/Shared/ViewModels/UserSocialMediaItem.cs @@ -4,6 +4,6 @@ namespace SocialCoder.Web.Shared.ViewModels; public class UserSocialMediaItem { - public string Url { get; set; } - public SocialMediaType Type { get; set; } + public string Url { get; set; } = string.Empty; + public SocialMediaType Type { get; set; } = SocialMediaType.Discord; } \ No newline at end of file