├── .gitignore ├── composer.json ├── detail-view.png ├── dist ├── css │ └── field.css └── js │ └── field.js ├── index-view.png ├── mix-manifest.json ├── package.json ├── readme.md ├── resources ├── js │ ├── components │ │ ├── DetailField.vue │ │ └── IndexField.vue │ └── field.js └── sass │ └── field.scss ├── src ├── ExternalUrl.php └── FieldServiceProvider.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor 3 | /node_modules 4 | package-lock.json 5 | composer.phar 6 | composer.lock 7 | phpunit.xml 8 | .phpunit.result.cache 9 | .DS_Store 10 | Thumbs.db 11 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pdewit/nova-external-url", 3 | "description": "An external URL Laravel Nova field.", 4 | "keywords": [ 5 | "laravel", 6 | "nova" 7 | ], 8 | "license": "MIT", 9 | "require": { 10 | "php": ">=7.1.0" 11 | }, 12 | "autoload": { 13 | "psr-4": { 14 | "Pdewit\\ExternalUrl\\": "src/" 15 | } 16 | }, 17 | "extra": { 18 | "laravel": { 19 | "providers": [ 20 | "Pdewit\\ExternalUrl\\FieldServiceProvider" 21 | ] 22 | } 23 | }, 24 | "config": { 25 | "sort-packages": true 26 | }, 27 | "minimum-stability": "dev", 28 | "prefer-stable": true 29 | } 30 | -------------------------------------------------------------------------------- /detail-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdewit/nova-external-url/5451bb4048ee8c6876807f369358eb56ac961bc5/detail-view.png -------------------------------------------------------------------------------- /dist/css/field.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdewit/nova-external-url/5451bb4048ee8c6876807f369358eb56ac961bc5/dist/css/field.css -------------------------------------------------------------------------------- /dist/js/field.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t){e.exports=function(e,t,n,r,i,l){var s,o=e=e||{},c=typeof e.default;"object"!==c&&"function"!==c||(s=e,o=e.default);var a,u="function"==typeof o?o.options:o;if(t&&(u.render=t.render,u.staticRenderFns=t.staticRenderFns,u._compiled=!0),n&&(u.functional=!0),i&&(u._scopeId=i),l?(a=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),r&&r.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(l)},u._ssrRegister=a):r&&(a=r),a){var f=u.functional,d=f?u.render:u.beforeCreate;f?(u._injectStyles=a,u.render=function(e,t){return a.call(t),d(e,t)}):u.beforeCreate=d?[].concat(d,a):[a]}return{esModule:s,exports:o,options:u}}},function(e,t,n){n(2),e.exports=n(9)},function(e,t,n){Nova.booting(function(e,t){e.component("index-external-url",n(3)),e.component("detail-external-url",n(6))})},function(e,t,n){var r=n(0)(n(4),n(5),!1,null,null,null);e.exports=r.exports},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={props:["resourceName","field"],computed:{linkText:function(){return this.field.linkText?this.field.linkText:"External Link"}}}},function(e,t){e.exports={render:function(){var e=this.$createElement,t=this._self._c||e;return t("div",[this.field.value?t("div",[t("a",{staticClass:"no-underline text-90 block",attrs:{href:this.field.value,target:"_blank"}},[t("div",{staticClass:"flex items-center"},[t("svg",{staticClass:"fill-current w-4 h-4 mr-2 text-60",attrs:{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 576 512"}},[t("path",{attrs:{fill:"currentColor",d:"M576 14.4l-.174 163.2c0 7.953-6.447 14.4-14.4 14.4H528.12c-8.067 0-14.56-6.626-14.397-14.691l2.717-73.627-2.062-2.062-278.863 278.865c-4.686 4.686-12.284 4.686-16.971 0l-23.029-23.029c-4.686-4.686-4.686-12.284 0-16.971L474.379 61.621l-2.062-2.062-73.626 2.717C390.626 62.44 384 55.946 384 47.879V14.574c0-7.953 6.447-14.4 14.4-14.4L561.6 0c7.953 0 14.4 6.447 14.4 14.4zM427.515 233.74l-24 24a12.002 12.002 0 0 0-3.515 8.485V458a6 6 0 0 1-6 6H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h301.976c10.691 0 16.045-12.926 8.485-20.485l-24-24A12.002 12.002 0 0 0 331.976 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V242.225c0-10.691-12.926-16.045-20.485-8.485z"}})]),this._v(" "),t("span",[this._v(this._s(this.linkText))])])])]):t("p",[this._v("—")])])},staticRenderFns:[]}},function(e,t,n){var r=n(0)(n(7),n(8),!1,null,null,null);e.exports=r.exports},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={props:["resource","resourceName","resourceId","field"],computed:{linkText:function(){return this.field.linkText?this.field.linkText:"External Link"}}}},function(e,t){e.exports={render:function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("panel-item",{attrs:{field:e.field}},[n("template",{slot:"value"},[e.field.value?n("div",[n("a",{staticClass:"no-underline text-90 block",attrs:{href:e.field.value,target:"_blank"}},[n("div",{staticClass:"flex items-center"},[n("svg",{staticClass:"fill-current w-4 h-4 mr-2 text-60",attrs:{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 576 512"}},[n("path",{attrs:{fill:"currentColor",d:"M576 14.4l-.174 163.2c0 7.953-6.447 14.4-14.4 14.4H528.12c-8.067 0-14.56-6.626-14.397-14.691l2.717-73.627-2.062-2.062-278.863 278.865c-4.686 4.686-12.284 4.686-16.971 0l-23.029-23.029c-4.686-4.686-4.686-12.284 0-16.971L474.379 61.621l-2.062-2.062-73.626 2.717C390.626 62.44 384 55.946 384 47.879V14.574c0-7.953 6.447-14.4 14.4-14.4L561.6 0c7.953 0 14.4 6.447 14.4 14.4zM427.515 233.74l-24 24a12.002 12.002 0 0 0-3.515 8.485V458a6 6 0 0 1-6 6H54a6 6 0 0 1-6-6V118a6 6 0 0 1 6-6h301.976c10.691 0 16.045-12.926 8.485-20.485l-24-24A12.002 12.002 0 0 0 331.976 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V242.225c0-10.691-12.926-16.045-20.485-8.485z"}})]),e._v(" "),n("span",[e._v(e._s(e.linkText))])]),e._v(" "),n("span",{staticClass:"text-sm no-underline text-60"},[e._v(e._s(e.field.value))])])]):n("p",[e._v("—")])])],2)},staticRenderFns:[]}},function(e,t){}]); -------------------------------------------------------------------------------- /index-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdewit/nova-external-url/5451bb4048ee8c6876807f369358eb56ac961bc5/index-view.png -------------------------------------------------------------------------------- /mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/dist/js/field.js": "/dist/js/field.js", 3 | "/dist/css/field.css": "/dist/css/field.css" 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "cross-env": "^5.0.0", 14 | "laravel-mix": "^1.0", 15 | "laravel-nova": "^1.0" 16 | }, 17 | "dependencies": { 18 | "vue": "^2.5.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Nova External URL Field 2 | 3 | Adds the ability to show external URLs in the detail and index views of resources. It uses the resolving feature from Nova to generate links. 4 | 5 | It will show up in the detail view like this: 6 | 7 | 8 | 9 | And in the index view like this: 10 | 11 | 12 | 13 | ## Installation and usage 14 | 15 | You can require this package using composer: 16 | 17 | ``` 18 | composer require pdewit/nova-external-url 19 | ``` 20 | 21 | You can add the field with a resolver as follows: 22 | 23 | ```php 24 | use Pdewit\ExternalUrl\ExternalUrl; 25 | 26 | ExternalUrl::make('Google Link', function () { 27 | return 'https://www.google.com/search?q=' . $this->name; 28 | }), 29 | ``` 30 | 31 | ## Customising the displayed text 32 | 33 | You can customise the displayed text using the `linkText` function like so: 34 | 35 | ```php 36 | use Pdewit\ExternalUrl\ExternalUrl; 37 | 38 | ExternalUrl::make('Google Link', function () { 39 | return 'https://www.google.com/search?q=' . $this->name; 40 | })->linkText($this->name), 41 | ``` 42 | 43 | The label below the link normally shows the URL, but it can be overridden: 44 | 45 | ```php 46 | use Pdewit\ExternalUrl\ExternalUrl; 47 | 48 | ExternalUrl::make('Google Link', function () { 49 | return 'https://www.google.com/search?q=' . $this->name; 50 | })->labelText('View search results on Google'), 51 | ``` 52 | -------------------------------------------------------------------------------- /resources/js/components/DetailField.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 33 | -------------------------------------------------------------------------------- /resources/js/components/IndexField.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | -------------------------------------------------------------------------------- /resources/js/field.js: -------------------------------------------------------------------------------- 1 | Nova.booting((Vue, router) => { 2 | Vue.component('index-external-url', require('./components/IndexField')); 3 | Vue.component('detail-external-url', require('./components/DetailField')); 4 | }) 5 | -------------------------------------------------------------------------------- /resources/sass/field.scss: -------------------------------------------------------------------------------- 1 | // Nova Tool CSS 2 | -------------------------------------------------------------------------------- /src/ExternalUrl.php: -------------------------------------------------------------------------------- 1 | exceptOnForms(); 21 | } 22 | 23 | public function linkText($linkText) { 24 | return $this->withMeta(["linkText" => $linkText]); 25 | } 26 | 27 | public function labelText($labelText) { 28 | return $this->withMeta(["labelText" => $labelText]); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/FieldServiceProvider.php: -------------------------------------------------------------------------------- 1 |