diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..d3f7e93
Binary files /dev/null and b/.DS_Store differ
diff --git a/assets/css/readmore.css b/assets/css/readmore.css
new file mode 100644
index 0000000..4b366f4
--- /dev/null
+++ b/assets/css/readmore.css
@@ -0,0 +1,94 @@
+.joinads-readmore-block {
+ text-align: center;
+ margin: 20px 0;
+}
+
+.joinads-readmore-button {
+ background-color: #0073aa;
+ color: white;
+ padding: 10px 15px;
+ border: none;
+ cursor: pointer;
+ border-radius: 5px;
+ font-size: 16px;
+ transition: background-color 0.3s ease;
+}
+
+.joinads-readmore-button:hover {
+ background-color: #005177;
+ color: white;
+}
+
+.joinads-hidden-content {
+ animation: fadeIn 0.5s ease-in-out;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+/* Estilo para o campo de entrada numérica */
+input[name="joinads_readmore_position"] {
+ width: 80px;
+ padding: 5px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 14px;
+}
+
+input[name="joinads_readmore_position"]:focus {
+ border-color: #0073aa;
+ box-shadow: 0 0 0 1px #0073aa;
+ outline: none;
+}
+
+.description {
+ color: #666;
+ font-style: italic;
+ margin-top: 5px;
+ font-size: 13px;
+}
+
+.joinads-hidden-content {
+ position: relative;
+ overflow: hidden;
+}
+
+.joinads-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 90%);
+ transition: transform 0.5s ease-in-out;
+}
+
+.joinads-overlay.hidden {
+ transform: translateY(100%);
+}
+
+.joinads-readmore-button {
+ display: block;
+ margin: 15px auto;
+ padding: 10px 20px;
+ background: #0073aa;
+ color: white;
+ border: none;
+ cursor: pointer;
+ border-radius: 5px;
+}
+
+.joinads-readmore-button:hover {
+ background: #005f8d;
+}
+
+.joinads-readmore-button.loading {
+ opacity: 0.7;
+ cursor: wait;
+}
diff --git a/assets/css/style.css b/assets/css/style.css
new file mode 100644
index 0000000..5821a4d
--- /dev/null
+++ b/assets/css/style.css
@@ -0,0 +1,897 @@
+.css-16udod0 {
+ box-sizing: border-box;
+ display: flex;
+ flex-flow: wrap;
+ margin-top: -16px;
+ width: calc(100% + 16px);
+ margin-left: -16px;
+ padding-left: 1.5rem;
+ padding-right: 0.5rem;
+ font-size: 20px;
+}
+.css-isbt42 {
+ box-sizing: border-box;
+ display: flex;
+ flex-flow: wrap;
+ margin-top: -16px;
+ width: calc(100% + 16px);
+ margin-left: -16px;
+}
+
+.css-r98zzg {
+ box-sizing: border-box;
+ margin: 0px;
+ flex-direction: row;
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ padding-top: 16px;
+ padding-left: 16px;
+}
+
+@media (min-width: 1536px) {
+ .css-r98zzg {
+ flex-basis: 20%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 20%;
+ }
+}
+@media (min-width: 1266px) and (max-width: 1536px) {
+ .css-r98zzg {
+ flex-basis: 20%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 20%;
+ }
+}
+@media (min-width: 1024px) and (max-width: 1266px) {
+ .css-r98zzg {
+ flex-basis: 20%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 20%;
+ }
+}
+@media (min-width: 768px) and (max-width: 1024px) {
+ .css-r98zzg {
+ flex-basis: 50%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 50%;
+ padding-left: 16px;
+ padding-top: 16px;
+ }
+}
+
+.css-u6v7fs {
+ background-color: rgb(255, 255, 255);
+ color: rgb(38, 38, 38);
+ box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
+ transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
+ overflow: hidden;
+ border-width: 1px 1px 1px 4px;
+ border-style: solid;
+ border-image: initial;
+ border-radius: 8px;
+ border-color: rgb(245, 245, 245) rgb(245, 245, 245) rgb(245, 245, 245)
+ rgb(59, 242, 107);
+ border-left: 4px solid rgb(59, 242, 107);
+}
+
+.css-3ofp2w:last-child {
+ padding-bottom: 20px;
+}
+
+.css-3ofp2w:last-child {
+ padding-bottom: 24px;
+}
+
+.css-3ofp2w {
+ padding: 18px;
+}
+
+.css-4jin6z {
+ display: flex;
+ flex-direction: column;
+}
+.css-4jin6z > :not(style):not(style) {
+ margin: 0px;
+}
+.css-69i1ev {
+ display: flex;
+ -webkit-box-pack: justify;
+ justify-content: space-between;
+ -webkit-box-align: center;
+ align-items: center;
+}
+
+.css-4jin6z > :not(style) ~ :not(style) {
+ margin-top: 4px;
+}
+.css-4jin6z > :not(style):not(style) {
+ margin: 0px;
+}
+.css-q1yb4z {
+ margin: 0px;
+ font-weight: 600;
+ line-height: 1.4;
+ font-family: Outfit, sans-serif;
+ color: inherit;
+ font-size: 1.25rem;
+}
+.css-1mucns2 {
+ display: flex;
+ -webkit-box-pack: end;
+ justify-content: end;
+ -webkit-box-align: center;
+ align-items: center;
+}
+
+.css-1bntj9o {
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: justify;
+ justify-content: space-between;
+ width: 100%;
+}
+
+.css-iylkxw {
+ margin: 0px;
+ font-weight: 400;
+ font-size: 0.875rem;
+ line-height: 1.57;
+ font-family: Outfit, sans-serif;
+ color: rgb(140, 140, 140);
+}
+
+h6 {
+ display: block;
+ font-size: 0.67em;
+ margin-block-start: 2.33em;
+ margin-block-end: 2.33em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+ unicode-bidi: isolate;
+}
+
+.css-1bntj9o {
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: justify;
+ justify-content: space-between;
+ width: 100%;
+}
+
+.css-hjmalu {
+ user-select: none;
+ width: 1em;
+ height: 1em;
+ display: inline-block;
+ fill: currentcolor;
+ flex-shrink: 0;
+ font-size: 1.5rem;
+ margin-right: 8px;
+ transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.css-173d6y {
+ display: inline-flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ position: relative;
+ box-sizing: border-box;
+ -webkit-tap-highlight-color: transparent;
+ background-color: transparent;
+ cursor: pointer;
+ user-select: none;
+ vertical-align: middle;
+ appearance: none;
+ text-align: center;
+ color: rgba(0, 0, 0, 0.54);
+ width: 30px;
+ height: 30px;
+ font-size: 0.75rem;
+ outline: 0px;
+ border-width: 0px;
+ border-style: initial;
+ border-color: initial;
+ border-image: initial;
+ margin: 0px;
+ text-decoration: none;
+ flex: 0 0 auto;
+ overflow: visible;
+ transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
+ padding: 5px;
+ border-radius: 4px;
+}
+
+.css-1k33q06 {
+ user-select: none;
+ width: 1em;
+ height: 1em;
+ display: inline-block;
+ fill: currentcolor;
+ flex-shrink: 0;
+ font-size: 1.25rem;
+ transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+.css-w0pj6f {
+ overflow: hidden;
+ pointer-events: none;
+ position: absolute;
+ z-index: 0;
+ inset: 0px;
+ border-radius: inherit;
+}
+
+.css-y9g7i8 {
+ background-color: rgb(255, 255, 255);
+ color: rgb(38, 38, 38);
+ box-shadow: inherit;
+ transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
+ overflow: hidden;
+ border-width: 1px;
+ border-style: solid;
+ border-image: initial;
+ border-radius: 8px;
+ border-color: rgb(245, 245, 245);
+ margin-top: 20px;
+ margin-right: 20px;
+}
+
+.css-gazh6o {
+ padding: 20px;
+}
+
+.css-4tz9zv > .MuiGrid-item {
+ padding-left: 22px;
+}
+
+.css-4tz9zv > .MuiGrid-item {
+ padding-top: 36px;
+}
+
+.css-4tz9zv {
+ box-sizing: border-box;
+ display: flex;
+ flex-flow: wrap;
+ margin-top: -36px;
+ width: calc(100% + 22px);
+ margin-left: -22px;
+ padding-bottom: 2rem;
+ float: right;
+ padding-top: 36px;
+ padding-left: 22px;
+}
+@media (min-width: 1266px) {
+ .css-1lois7l {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+
+@media (min-width: 1024px) {
+ .css-1lois7l {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+
+@media (min-width: 768px) {
+ .css-1lois7l {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+
+.css-1lois7l {
+ box-sizing: border-box;
+ margin: 0px 0px 18px;
+ flex-direction: row;
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+}
+
+/* .css-16prq53 {
+ font-size: 0.875rem;
+ line-height: 1.4375em;
+ font-family: Outfit, sans-serif;
+ font-weight: 400;
+ display: block;
+ transform-origin: left top;
+ text-overflow: ellipsis;
+ max-width: 133%;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ transform: translate(0px, -1.5px) scale(0.75);
+ color: rgb(89, 89, 89);
+ padding: 0px;
+ white-space: nowrap;
+ overflow: hidden;
+ transition: color 200ms cubic-bezier(0, 0, 0.2, 1),
+ transform 200ms cubic-bezier(0, 0, 0.2, 1),
+ max-width 200ms cubic-bezier(0, 0, 0.2, 1);
+} */
+.css-tzsjye {
+ display: inline-flex;
+ flex-direction: column;
+ position: relative;
+ min-width: 0px;
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+ vertical-align: top;
+ width: 100%;
+ padding-left: 10px;
+}
+@media (min-width: 1266px) {
+ .css-1ipn5om {
+ flex-basis: 16.6667%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 16.6667%;
+ }
+}
+
+@media (min-width: 1024px) and (max-width: 1266px) {
+ .css-1ipn5om {
+ flex-basis: 25%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 25%;
+ }
+}
+
+@media (min-width: 768px) and (max-width: 1024px) {
+ .css-1ipn5om {
+ flex-basis: 25%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 25%;
+ }
+}
+
+.css-1ipn5om {
+ box-sizing: border-box;
+ margin: 0px;
+ flex-direction: row;
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+}
+.css-21yr5o {
+ margin: 0px;
+ font-weight: 600;
+ font-size: 1.5rem;
+ line-height: 1.33;
+ font-family: Outfit, sans-serif;
+}
+
+@media (min-width: 768px) and (max-width: 1024px) {
+ .css-1ipn5om {
+ flex-basis: 25%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 25%;
+ }
+}
+
+.css-1ipn5om {
+ box-sizing: border-box;
+ margin: 0px;
+ flex-direction: row;
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+}
+
+.css-1jwcqz0 {
+ box-sizing: border-box;
+ display: flex;
+ flex-flow: wrap;
+ width: calc(100% + 16px);
+ margin-left: -16px;
+ padding: 0.5rem;
+ padding-left: 24px;
+}
+
+.css-1m7shs5 {
+ box-sizing: border-box;
+ margin: 0px;
+ flex-direction: row;
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ width: 100%;
+}
+
+@media (min-width: 1536px) {
+ .css-1m7shs5 {
+ padding-left: 12px;
+ flex-basis: 50%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 50%;
+ }
+}
+@media (min-width: 1266px) and (max-width: 1536px) {
+ .css-1m7shs5 {
+ padding-left: 12px;
+ flex-basis: 50%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 50%;
+ }
+}
+@media (min-width: 1024px) and (max-width: 1266px) {
+ .css-1m7shs5 {
+ padding-left: 12px;
+ flex-basis: 50%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 50%;
+ }
+
+}
+@media (min-width: 768px) and (max-width: 1024px) {
+ .css-1m7shs5 {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ margin-top: 26px;
+ }
+}
+
+@media (max-width: 768px) {
+ .css-1m7shs5 {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ margin-top: 26px;
+ }
+}
+.css-1ih4t8m {
+ background-color: rgb(255, 255, 255);
+ color: rgb(38, 38, 38);
+ box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 1px -1px,
+ rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px;
+ height: 100%;
+ transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
+ border-radius: 4px;
+ padding: 1rem 0.5rem 0rem;
+}
+
+.css-1k4ujvj {
+ background-color: rgb(255, 255, 255);
+ color: rgb(38, 38, 38);
+ box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 1px -1px,
+ rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px;
+ height: 100%;
+ transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
+ border-radius: 4px;
+ padding: 1rem;
+}
+
+.css-rfnosa {
+ box-sizing: border-box;
+ flex-direction: row;
+}
+
+.css-uw5qdi h5 {
+ margin: 0px;
+ font-weight: 600;
+ font-size: 1rem;
+ line-height: 1.5;
+ font-family: Outfit, sans-serif;
+
+ display: block;
+ font-size: 0.83em;
+ margin-block-start: 1.67em;
+ margin-block-end: 1.67em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
+ unicode-bidi: isolate;
+}
+
+.css-w82akl {
+ flex-shrink: 0;
+ border-width: 0px 0px thin;
+ border-style: solid;
+ border-color: rgb(240, 240, 240);
+ margin: 8px;
+}
+.css-8h6itf {
+ list-style: none;
+ margin: 0px;
+ padding: 8px 0px;
+ position: relative;
+ width: 100%;
+ background-color: rgb(255, 255, 255);
+}
+
+.css-uowjlg {
+ list-style: none;
+ margin: 0px;
+ position: relative;
+ width: 98%;
+ background-color: rgb(255, 255, 255);
+
+ padding: 10.4px;
+}
+/* .css-uowjlg {
+ list-style: none;
+ margin: 0px;
+ position: relative;
+ width: 100%;
+ background-color: rgb(255, 255, 255);
+ height: 100%;
+ padding: 10.4px;
+} */
+.css-ktwerk {
+ display: flex;
+ -webkit-box-pack: start;
+ justify-content: flex-start;
+ -webkit-box-align: center;
+ align-items: center;
+ position: relative;
+ text-decoration: none;
+ width: 100%;
+ box-sizing: border-box;
+ text-align: left;
+ padding: 8px 16px;
+ background-color: rgb(255, 255, 255);
+ transition: background-color 0.3s ease-in-out;
+}
+
+@media (min-width: 1024px) and (max-width: 1266px) {
+ .css-uowjlg {
+ width: 96%;
+ }
+}
+
+@media (min-width: 1266px) and (max-width: 1536px) {
+ .css-uowjlg {
+ width: 95%;
+ }
+}
+
+@media (min-width: 1536px) {
+ .css-uowjlg {
+ width: 98%;
+ }
+}
+.css-a5kqs7 {
+ min-width: 56px;
+ flex-shrink: 0;
+}
+.bandeira {
+ width: 24px;
+ height: 16px;
+}
+.css-1rg3ltq {
+ margin: 0px 4px;
+ flex-shrink: 0;
+ border-width: 0px 0px thin;
+ border-style: solid;
+ border-color: rgb(240, 240, 240);
+}
+
+.css-1xar93x {
+ flex: 1 1 auto;
+ min-width: 0px;
+
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.css-1edxfyp {
+ overflow-wrap: break-word;
+ color: rgb(0, 0, 0);
+ margin: 0;
+ font-weight: bold;
+ transition: color 0.3s ease-in-out;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+
+ display: inline-block; /* Certifica-se de que o link seja tratado como um bloco de linha */
+ width: 100%;
+}
+.css-1uc5cvd {
+ margin: 0px;
+ font-size: 0.75rem;
+ line-height: 1.66;
+ font-family: Outfit, sans-serif;
+ font-weight: 400;
+ color: rgb(140, 140, 140);
+ display: block;
+}
+.css-1ofqig9 {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+}
+.css-gg4vpm {
+ display: flex;
+ -webkit-box-pack: justify;
+ justify-content: space-between;
+}
+.css-fi5e9e {
+ margin: 0px;
+ font-size: 0.75rem;
+ line-height: 1.66;
+ font-family: Outfit, sans-serif;
+ font-weight: 600;
+}
+.css-1lnf5xi {
+ margin: 0px 56px 0px 0px;
+ font-size: 0.75rem;
+ line-height: 1.66;
+ font-family: Outfit, sans-serif;
+ font-weight: 600;
+}
+.css-1w30cbz {
+ max-width: 100%;
+ font-family: Outfit, sans-serif;
+ font-size: 0.8125rem;
+ display: inline-flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ height: 32px;
+ cursor: unset;
+ vertical-align: middle;
+ box-sizing: border-box;
+ background-color: rgb(60, 242, 107);
+ color: rgb(255, 255, 255);
+ font-weight: 600;
+ margin-left: 1%;
+ white-space: nowrap;
+ transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1),
+ box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
+ outline: 0px;
+ text-decoration: none;
+ border-width: 0px;
+ border-style: initial;
+ border-color: initial;
+ border-image: initial;
+ padding: 0px;
+ border-radius: 16px;
+}
+.css-14vsv3w {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-left: 12px;
+ padding-right: 12px;
+ white-space: nowrap;
+}
+
+.css-1f9xl3h {
+ box-sizing: border-box;
+ margin: 0px;
+ flex-direction: row;
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ width: 100%;
+ padding-right: 0px;
+}
+
+@media (min-width: 1536px) {
+ .css-1f9xl3h {
+ flex-basis: 50%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+
+@media (min-width: 1266px) and (max-width: 1536px) {
+ .css-1f9xl3h {
+ flex-basis: 50%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+
+@media (min-width: 1024px) and (max-width: 1266px) {
+ .css-1f9xl3h {
+ flex-basis: 50%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+
+@media (min-width: 768px) and (max-width: 1024px) {
+ .css-1f9xl3h {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+
+.css-1ber4kh {
+ box-sizing: border-box;
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+@media (min-width: 1536px) {
+ .css-1ber4kh {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+@media (min-width: 1266px) and (max-width: 1536px) {
+ .css-1ber4kh {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ }
+}
+@media (min-width: 1024px) and (max-width: 1266px) {
+ .css-1ber4kh {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+
+ }
+}
+@media (min-width: 768px) and (max-width: 1024px) {
+ .css-1ber4kh {
+ flex-basis: 100%;
+ -webkit-box-flex: 0;
+ flex-grow: 0;
+ max-width: 100%;
+ margin-top: 26px;
+ }
+}
+
+.css-uw5qdi {
+ margin: 0px;
+ font-weight: 600;
+ font-size: 1rem;
+ line-height: 1.5;
+ font-family: Outfit, sans-serif;
+}
+.css-10klw3m {
+ height: 100%;
+}
+
+.css-3sjlis {
+ position: relative;
+ display: flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ flex-shrink: 0;
+ width: 40px;
+ height: 40px;
+ font-family: Outfit, sans-serif;
+ font-size: 1.25rem;
+ line-height: 1;
+ border-radius: 50%;
+ overflow: hidden;
+ user-select: none;
+ color: rgb(250, 250, 251);
+ background-color: rgb(255, 255, 255);
+ box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px;
+ margin-right: 1rem;
+}
+
+.css-jidhqd {
+ user-select: none;
+ width: 1em;
+ height: 1em;
+ display: inline-block;
+ fill: currentcolor;
+ flex-shrink: 0;
+ font-size: 1.5rem;
+ color: rgb(60, 242, 107);
+ transition: fill 200ms cubic-bezier(0.4, 0, 0.2, 1);
+}
+.css-18y373z {
+ margin: 0px;
+ font-size: 0.875rem;
+ line-height: 1.57;
+ font-family: Outfit, sans-serif;
+ font-weight: 400;
+ display: block;
+}
+.css-13up9h1 {
+ margin: 0px;
+ line-height: 1.66;
+ font-family: Outfit, sans-serif;
+ font-weight: 400;
+ color: rgb(140, 140, 140);
+ display: block;
+ font-size: 0.875rem;
+}
+
+.topLink {
+ overflow-wrap: break-word;
+ color: rgb(0, 0, 0);
+ text-decoration: underline;
+ font-weight: bold;
+ transition: color 0.3s ease-in-out;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+
+ display: inline-block; /* Certifica-se de que o link seja tratado como um bloco de linha */
+ width: 100%;
+}
+
+.css-1w30cbz {
+ max-width: 100%;
+ font-family: Outfit, sans-serif;
+ font-size: 0.8125rem;
+ display: inline-flex;
+ -webkit-box-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ justify-content: center;
+ height: 32px;
+ cursor: unset;
+ vertical-align: middle;
+ box-sizing: border-box;
+ /* background-color: rgb(60, 242, 107); */
+ color: rgb(255, 255, 255);
+ font-weight: 600;
+ margin-right: 5%;
+ white-space: nowrap;
+ transition: background-color 300ms cubic-bezier(0.4, 0, 0.2, 1),
+ box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
+ outline: 0px;
+ text-decoration: none;
+ border-width: 0px;
+ border-style: initial;
+ border-color: initial;
+ border-image: initial;
+ padding: 0px;
+ border-radius: 16px;
+}
+.css-14vsv3w {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-left: 12px;
+ padding-right: 12px;
+ white-space: nowrap;
+}
diff --git a/assets/js/admin.js b/assets/js/admin.js
new file mode 100644
index 0000000..9097c1a
--- /dev/null
+++ b/assets/js/admin.js
@@ -0,0 +1,3 @@
+jQuery(document).ready(function($) {
+ $('.my-color-field').wpColorPicker();
+});
\ No newline at end of file
diff --git a/assets/js/readmore.js b/assets/js/readmore.js
new file mode 100644
index 0000000..c3adecd
--- /dev/null
+++ b/assets/js/readmore.js
@@ -0,0 +1,16 @@
+jQuery(document).ready(function($) {
+ $('.joinads-readmore-button').on('click', function(e) {
+ e.preventDefault();
+
+ const $button = $(this);
+ const $hiddenContent = $button.closest('.joinads-readmore-block').next('.joinads-hidden-content');
+
+ if ($hiddenContent.length) {
+ $hiddenContent.slideDown(400, function() {
+ // Dispara evento de redimensionamento para recalcular anúncios
+ $(window).trigger('resize');
+ });
+ $button.parent('.joinads-readmore-block').fadeOut();
+ }
+ });
+});
\ No newline at end of file
diff --git a/functions.php b/functions.php
deleted file mode 100644
index 465cd63..0000000
--- a/functions.php
+++ /dev/null
@@ -1,17 +0,0 @@
-add_settings_sections();
+ $this->add_settings_fields();
+
+ register_setting('joinads_readmore_settings_group', 'joinads_readmore_enabled');
+ register_setting('joinads_readmore_settings_group', 'joinads_readmore_position');
+
+ add_settings_section(
+ 'joinads_readmore_main_section',
+ 'Configurações do Leia Mais',
+ null,
+ 'joinads-readmore'
+ );
+
+ add_settings_field(
+ 'joinads_readmore_enabled',
+ 'Ativar Leia Mais',
+ array($this, 'render_enabled_field'),
+ 'joinads-readmore',
+ 'joinads_readmore_main_section'
+ );
+
+ add_settings_field(
+ 'joinads_readmore_position',
+ 'Posição do Leia Mais',
+ array($this, 'render_position_field'),
+ 'joinads-readmore',
+ 'joinads_readmore_main_section'
+ );
+ }
+
+ private function add_settings_sections()
+ {
+ add_settings_section(
+ 'joinads_loader_joinAdsLoader_section',
+ '',
+ array($this, 'settings_section_callback'),
+ 'joinAdsLoader'
+ );
+
+ add_settings_section(
+ 'joinads_loader_main_section',
+ 'Configurações da API',
+ array($this, 'config_section_callback'),
+ 'join_ads_config'
+ );
+ }
+
+ private function add_settings_fields()
+ {
+ //Campos do Loader
+ $loader_fields = array(
+ 'joinads_loader_enabled' => array(
+ 'label' => 'Ativar Loader:',
+ 'callback' => 'loader_enabled_field_render'
+ ),
+ 'joinads_loader_color' => array(
+ 'label' => 'Loader Cor:',
+ 'callback' => 'color_field_render'
+ ),
+ 'joinads_loader_timeout' => array(
+ 'label' => 'Loader:
(segundos para aguardar o anúncio)',
+ 'callback' => 'timeout_field_render'
+ ),
+ 'joinads_loader_timeout_home' => array(
+ 'label' => 'Home Loader:
(segundos para aguardar o anúncio)',
+ 'callback' => 'timeout_home_field_render'
+ ),
+ 'joinads_loader_ad_block' => array(
+ 'label' => 'AdUnit Name:
(Nome do bloco ex: Content1)',
+ 'callback' => 'ad_block_field_render'
+ )
+ );
+
+ foreach ($loader_fields as $id => $field) {
+ add_settings_field(
+ $id,
+ $field['label'],
+ array($this, $field['callback']),
+ 'joinAdsLoader',
+ 'joinads_loader_joinAdsLoader_section'
+ );
+ }
+
+ //Campos de configuração
+ $config_fields = array(
+ 'id_domain' => 'Domínio:
(Nome do domínio ex: joinads.com.br)',
+ 'token_api' => 'Token da API:',
+ 'short' => 'Forçar ShortLink:'
+ );
+
+
+ foreach ($config_fields as $id => $label) {
+ add_settings_field(
+ 'joinads_loader_' . $id,
+ $label,
+ array($this, 'config_field_render'),
+ 'join_ads_config',
+ 'joinads_loader_main_section',
+ array('field' => $id)
+ );
+ }
+ }
+
+ public function color_field_render()
+ {
+ $options = get_option('joinads_loader_settings');
+ ?>
+ ' class='my-color-field'>
+
+ '>
+
+ '>
+
+ '>
+ ";
+ } else {
+ echo "";
+ }
+ }
+
+ public function settings_section_callback()
+ {
+ echo 'Configure de acordo com as suas preferências';
+ }
+
+ public function config_section_callback()
+ {
+ echo '
Preencha as informações abaixo para configurar a API da Join Ads Network.
'; + } + + public function add_admin_menu() + { + // Adiciona o menu principal + add_menu_page( + 'Join Ads', + 'Join Ads', + 'manage_options', + 'join_ads_loader_main', + array($this, 'display_dashboard_page'), + 'dashicons-plugins-checked' + ); + + // Adiciona os submenus + add_submenu_page( + 'join_ads_loader_main', + 'Loader Manager', + 'Loader Manager', + 'manage_options', + 'join_ads_loader', + array($this, 'display_loader_page') + ); + + add_submenu_page( + 'join_ads_loader_main', + 'Configurações', + 'Configurações', + 'manage_options', + 'join_ads_config', + array($this, 'display_config_page') + ); + } + + public function transformObject($original) + { + // Mapeamento de traduções das chaves + $translations = [ + "impressions" => "Impressões", + "revenue_client" => "Receita", + "ecpm_client" => "ECPM", + "clicks" => "Cliques", + "ctr" => "CTR", + "unfilled_impressions" => "Não preenchidas", + "active_view" => "Viewability", + "pageview" => "Visualização Única", + "pmr" => "PMR", + "ipv" => "IPV", + "average-roi" => "Roi geral", + "total_result" => "Resultado Total", + "total_spend" => "Total Gasto", + "total_revenue" => "Receita de Campanhas" + ]; + + // Definir os helpers para cada chave do objeto original + $helpers = [ + "impressions" => "Total de impressões entregues pelo Ad Exchange.", + "revenue_client" => "Receita gerada a partir da sua conta do Ad Manager.", + "ecpm_client" => "Custo efetivo por mil impressões.", + "clicks" => "Total de cliques entregues pelo Ad Exchange.", + "ctr" => "A porcentagem de impressões servidas pelo Ad Exchange que resultaram em cliques dos usuários.", + "unfilled_impressions" => "Número total de solicitações de anúncios para o servidor do Google Ad Manager, AdSense e Ad Exchange que não retornaram um anúncio.", + "active_view" => "Porcentagem de impressões visíveis em relação ao total de impressões mensuráveis.", + "pageview" => "O número de visitantes únicos, ou 'alcance', expostos à sua rede.", + "pmr" => "Taxa de correspondência de página.", + "ipv" => "Impressões por visitante.", + "average-roi" => "Retorno sobre investimento médio", + "total_result" => "Resultado Total", + "total_spend" => "Total Gasto", + "total_revenue" => "Receita de Campanhas" + ]; + + // Inicializar o novo objeto + $newObject = []; + + // Percorrer as chaves do objeto original + foreach ($original as $key => $value) { + + if ($key === 'requests_served') { + continue; + } + // Traduzir a chave para o português + $translatedKey = $translations[$key] ?? ucfirst(str_replace('_', ' ', $key)); // Usa a tradução ou mantém o nome em camel case + + // Formatar valores conforme necessário + if ($key === 'ctr' || $key === 'active_view') { + // Para 'ctr' e 'pmr', formatar como porcentagem + $valueFormatted = number_format($value * 100, 2) . '%'; + } elseif ($key === 'ecpm_client' || $key === 'revenue_client') { + // Para 'ecpm_client' e 'revenue_client', formatar como valor monetário + $valueFormatted = 'US$ ' . number_format($value, 2, ',', '.'); + } elseif ($key === 'pmr') { + $valueFormatted = number_format($value, 2) . '%'; + } else { + // Para os demais valores, manter como está + if (is_float($value)) { + + $valueFormatted = number_format($value, 2, ',', '.'); + } else { + $valueFormatted = number_format($value, 0, ',', '.'); + + } + } + + // Adicionar o item ao novo objeto com a chave traduzida + $newObject[$translatedKey] = [ + "value" => $valueFormatted, + "helper" => $helpers[$key] ?? "Informação não disponível." + ]; + } + + return $newObject; + } + + + + private function check_loader_status() + { + $options = get_option('joinads_loader_settings'); + return !empty($options['joinads_loader_ad_block']); + } + + private function get_loader_timeout() + { + $options = get_option('joinads_loader_settings'); + return $options['joinads_loader_timeout'] ?? 7; + } + + public function display_loader_page() + { + ?> +ads.txt atualizado com sucesso.
'; + } + + $ads_txt_content = ''; + if (file_exists($ads_txt_file)) { + $ads_txt_content = file_get_contents($ads_txt_file); + } + + ?> +Adicione abaixo seu ads.txt caso não esteja na lista.
+ ++ Digite após qual parágrafo o botão "Leia mais" deve aparecer (entre 1 e 20) +
+ token = isset($options['token_api']) ? sanitize_text_field($options['token_api']) : ''; + $this->domain = isset($options['id_domain']) ? sanitize_text_field($options['id_domain']) : ''; + } + + public function get_dashboard_data() { + // Validar token + if (empty($this->token)) { + return new WP_Error('missing_token', 'Token da API não configurado'); + } + // Validar domínio + if (empty($this->domain)) { + return new WP_Error('missing_domain', 'Domínio não configurado'); + } + // Pegar o período selecionado ou usar padrão (7 dias) + $period = isset($_GET['period']) ? absint($_GET['period']) : 7; + // Definir datas no formato correto + $end_date = date('Y-m-d\TH:i:s.v\Z'); + $start_date = date('Y-m-d\TH:i:s.v\Z', strtotime("-{$period} days")); + // Preparar payload + $payload = array( + 'start' => $start_date, + 'end' => $end_date, + 'domain' => array($this->domain) + ); + // Fazer requisição + $response = wp_remote_post($this->base_url . 'reports/main-filter', array( + 'headers' => array( + 'Authorization' => 'Bearer ' . $this->token, + 'Content-Type' => 'application/json', + 'Accept' => 'application/json' + ), + 'body' => json_encode($payload), + 'timeout' => 30, + 'sslverify' => true + )); + + + if (is_wp_error($response)) { + return new WP_Error('api_error', $response->get_error_message()); + } + + $response_code = wp_remote_retrieve_response_code($response); + $body = wp_remote_retrieve_body($response); + $data = json_decode($body, true); + + // Verificar erros específicos da API + if ($response_code !== 200) { + $error_message = 'Erro na API'; + if (isset($data['message'])) { + $error_message = $data['message']; + } + if (isset($data['details'])) { + $error_message .= ': ' . json_encode($data['details']); + } + return new WP_Error('api_error', $error_message); + } + + if (!$data) { + return new WP_Error('api_error', 'Erro ao processar dados da API'); + } + + return $data; + } + + public function get_error_message($wp_error) { + if (!is_wp_error($wp_error)) { + return ''; + } + + $error_messages = array( + 'missing_token' => 'Token da API não configurado. Por favor, configure nas configurações do plugin.', + 'missing_domain' => 'Domínio não configurado. Por favor, configure nas configurações do plugin.', + 'api_error' => 'Erro na comunicação com a API: ', + ); + + $code = $wp_error->get_error_code(); + $message = $error_messages[$code] ?? ''; + + if ($code === 'api_error') { + $message .= $wp_error->get_error_message(); + } + + return $message; + } +} diff --git a/includes/class-joinads-dashboard.php b/includes/class-joinads-dashboard.php new file mode 100644 index 0000000..df6ad00 --- /dev/null +++ b/includes/class-joinads-dashboard.php @@ -0,0 +1,224 @@ +get_dashboard_data(); + ?> + + +Revenue:
+$
+eCPM:
+$
+CTR:
+%
+JoinAds Loader iniciado
ads.txt atualizado com sucesso.
Adicione a baixo seu ads.txt caso não esteja na lista.
- -